如何正确使用构建标签?

huangapple go评论81阅读模式
英文:

How to properly use build tags?

问题

我需要能够构建不同版本的go应用程序;一个是“debug”版本,一个是普通版本。

这很容易做到;我只需要一个控制应用程序行为的常量DEBUG,但是每次需要切换构建类型时都需要编辑配置文件,这很麻烦。

我在阅读关于go build(http://golang.org/pkg/go/build/)和标签的内容,我想也许我可以这样做:

config.go:

// +build !debug
package build
const DEBUG = false

config.debug.go:

// +build debug
package build
const DEBUG = true

然后我应该能够使用go buildgo build -tags debug进行构建,标签应该排除config.go并包含config.debug.go

...但是这不起作用。我得到了以下错误:

> src/build/config.go:3: DEBUG在此块中重新声明(<0>),之前的声明在src/build/config.debug.go:3中

我做错了什么?

还有其他更合适的#ifdef风格的方法可以使用吗?

英文:

I need to be able to build different versions of a go application; a 'debug' version and a normal version.

This is easy to do; I simply have a const DEBUG, that controls the behaviour of the application, but it's annoying to have to edit the config file every time I need to swap between build types.

I was reading about go build (http://golang.org/pkg/go/build/) and tags, I thought perhaps I could do this:

config.go:

// +build !debug
package build
const DEBUG = false

config.debug.go:

// +build debug
package build
const DEBUG = true

Then I should be able to build using go build or go build -tags debug, and the tags should exclude config.go and include config.debug.go.

...but this doesn't work. I get:

> src/build/config.go:3: DEBUG redeclared in this block (<0>) previous
> declaration at src/build/config.debug.go:3

What am I doing wrong?

Is there another and more appropriate #ifdef style way of doing this I should be using?

答案1

得分: 32

请参见我对另一个问题的回答。在// +build行之后需要一个空行。

另外,你可能想要在config.go中使用!,而不是在config.debug.go中;并且你可能想要其中一个为"DEBUG = false"。

英文:

See my answer to another question. You need a blank line after the // +build line.

Also, you probably want the ! in config.go, not in config.debug.go; and presumably you want one to be "DEBUG = false".

答案2

得分: 22

你可以使用编译时常量来实现:如果你使用以下命令编译你的程序:

go build -ldflags '-X main.DEBUG=YES' test.go

包 main 中的变量 DEBUG 将被设置为字符串 "YES"。否则,它将保持其声明的内容。

package main

import (
	"fmt"
)

var DEBUG = "NO"

func main() {
	fmt.Printf("DEBUG is %q\n", DEBUG)
}
英文:

You could use compile time constants for that: If you compile your program with

go build -ldflags &#39;-X main.DEBUG=YES&#39; test.go

the variable DEBUG from package main will be set to the string "YES". Otherwise it keeps its declared contents.

package main

import (
	&quot;fmt&quot;
)

var DEBUG = &quot;NO&quot;

func main() {
	fmt.Printf(&quot;DEBUG is %q\n&quot;, DEBUG)
}

Edit: since Go 1.6(?) the switch is -X main.DEBUG=YES, before that it was -X main.DEBUG YES (without the =). Thanks to a comment from @poorva.

答案3

得分: 4

从Go 1.17开始,可以使用新的//go:build语法来指定构建标签。

至于//go:build指令的放置位置,新的设计规定:

> 约束条件可以出现在任何类型的源文件中(不仅限于Go),但它们必须出现在文件的顶部附近,仅在空行和其他///* */注释之前。这些规则意味着在Go文件中,构建约束条件必须出现在包声明之前。

因此,在//go:build指令和包声明之间仍然需要留出一个空行,否则它可能被解析为包文档,但现在:

  • 编译器将拒绝错误放置的指令
  • 运行go fmt将自动修复错误放置的指令

例如,在没有空行的情况下运行go fmt

//go:build foo
package main

import "fmt"

func main() {
    fmt.Println("Hello world")
}

将会得到(有空行):

//go:build foo

package main

import "fmt"

func main() {
    fmt.Println("Hello world")
}

<hr>

有关新语法的更多详细信息,请参见此答案

英文:

As of Go 1.17, build tags can be specified with the new //go:build syntax.

As for the placement of the //go:build directive, the new design states:

> Constraints may appear in any kind of source file (not just Go), but they must appear near the top of the file, preceded only by blank lines and other // and /* */ comments. These rules mean that in Go files a build constraint must appear before the package clause.

So you still need to leave a blank line between the //go:build directive and the package statement, otherwise it could be parsed as package documentation, however now:

  • the compiler will reject misplaced directives
  • running go fmt will automatically fix misplaced directives

For example running go fmt on (no blank line):

//go:build foo
package main

import &quot;fmt&quot;

func main() {
    fmt.Println(&quot;Hello world&quot;)
}

gives (with blank line):

//go:build foo
package main

import &quot;fmt&quot;

func main() {
    fmt.Println(&quot;Hello world&quot;)
}

<hr>

See also this answer for further details about what changes with the new syntax.

huangapple
  • 本文由 发表于 2013年3月5日 09:51:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/15214459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定