Golang中的C风格条件编译

32

golang支持吗?

#define DEBUG 

#ifdef DEBUG 
  fmt.Println("Debug message..."); 
#endif 

那么我可以构建一个没有任何运行时开销的调试版本吗?


1
严格来说不是的。没有预处理器,因此也没有预处理器魔法。 - lofcek
就像Java一样,GoLang中没有内嵌的预处理器,但是也像Java一样,可以使用第三方类似的工具。例如,我使用Java Comment Preprocessor + mvn-golang,能够得到良好的结果。 - Igor Maznitsa
2个回答

48

Go语言没有预处理器或宏系统。您可以通过-tags标志将标记传递给go build,并使用构建约束。为此,您需要同一源的两个版本,只有一个版本会根据是否存在标记而进行构建。

请查看https://golang.org/pkg/go/build/中的构建约束。

main_debug.go

// +build debug

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Debug build")
}

主要发布.go

// +build !debug

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Release build")
}

在这里,go build会使用main_release.go进行编译,而go build -tags debug会使用main_debug.go进行编译。


21
如果不是显然的话,你可以在这些文件中声明一个常量,将其设为true或false,因为它们是互斥的。然后你可以在if语句中使用该常量。Go会识别出if语句在构建标记下始终为真或假,并从非调试版本中删除代码,或者反之亦然。 - John Leidegren
我想在发布版本时隐藏调试字符串。有没有更简单的解决方案? - undefined

6
如果你使用的是Linux或者Mac系统,你可以尝试使用“m4”命令。这个命令是一个适用于此问题的宏处理器。
在运行“go build”之前,编写一个Makefile来运行m4命令可以实现与使用“go build -tags…”相同的效果,并支持更多的自定义,当然还可以节省你的工作量。
例如:
在你的go文件中(例如main.go)写入以下内容:
define(DEBUG)
ifdef(`DEBUG',
    fmt.Println("Debug message..."); 
)

在你的Makefile文件中写入以下内容:

all:*.go
    mv main.go main.go.bak
    m4 main.go.bak > main.go
    go build
    mv main.go.bak main.go

然后运行"make"命令。

缺点:

  1. 你不能写一个名为"define"或"ifndef"等的go函数,因为它们将被m4翻译成宏。
  2. 如果你有很多文件,你可能需要改进你的Makefile。
  3. 你可能需要学习一些有点困难和复杂的m4知识。

3
这是我一直想做的事情,但主要的缺点是linter不理解m4,会非常困惑,因此这个想法变得不切实际。没有任何linter实时反馈的编写代码当然是可能的,但相当不愉快。 - Roflcopter4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接