go语言如何在编译阶段给变量赋值
如何使用”go build -ldflags -X”命令行参数给package变量赋值。
给出一个应用场景:
我们有时候需要在应用程序启动的时候打印出当前binary的版本信息或者编译时间,从而确定具体的binary版本号。
方法1:
首先想到一个办法就是由编译脚本在编译时生产一个go源文件,包含一个变量值,例如:
$ echo "package main; var Version string = \"build-$(date +%Y%m%d)\"" > version.go
$ cat version.go
package main; var Version string = "build-20180531"
$ cat main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("version=" + Version)
}
$ go build
$ ./main
version=build-20180531
这个办法存在一个问题,就是version.go文件每次都会新生产,在有源代码版本管理环境下,污染我们的视线:每一次build这个文件就会发生更新。
方法2:
另一个办法,我们可以使用”go build -ldflags -X”参数来保持version.go文件内容不会发生变化。
- 步骤1:生产一个版本文件
这个go文件只定义了变量Version,而没有赋值。
$ cat version.go
package main
var Version string
- 步骤2:在main里面引用变量
main.go和前面的一样。
$ cat main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("version=" + Version)
}
- 步骤3:编译的时候指定变量值
$ go build -ldflags "-X main.Version=1.0.5"
- 步骤4:运行
$ ./main
version=1.0.5
- 步骤5:其他格式定义变量
- 通过命令行输出。
$ go build -ldflags "-X main.Version=ver-$(date +%Y%m%d)"
$ ./main
version=ver-20180531
- 通过环境变量
$ VERSION="testv";go build -ldflags "-X main.Version=ver-${VERSION}"
$ ./main
version=ver-testv
- 步骤6:另外可以把version变量放在一个包(package)里面
其实和main包里面是一样的,只是指定的package名是具体的package名,而不是main
$ cat main.go
package main
import (
"fmt"
"version"
)
func main() {
fmt.Println("version=" + version.Version)
}
$ cat version/version.go
package version
var Version string
$ go build -ldflags "-X version.Version=v$(date +%Y%m%d)" -o main
$ ./main
version=v20180531
参考go build link command文档:https://golang.org/cmd/link/
其中对-X的定义如下,
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
Note that before Go 1.5 this option took two separate arguments.
Now it takes one argument split on the first = sign.