编译 Go 语言程序时注入版本信息
在定位线上应用程序的问题的时候,确定应用程序使用的版本号等细节通常是非常有必要做的且非常有帮助的。 于是我们通常会在最终生成的二进制文件中嵌入相关信息,比如:编译时间、谁编译的、当前分支、当前 Tag、当前的提交号等。 这篇文章讲解在 Go 语言程序中注入版本信息的方式。
链接器参数
Go 语言的链接器文档中提到了一个 -X
参数,用来修改一个包的字符串变量的值。
官方说明如下:
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
This is only effective if the variable is declared in the source code either uninitialized
or initialized to a constant string expression. -X will not work if the initializer makes
a function call or refers to other variables.
Note that before Go 1.5 this option took two separate arguments.
有几个重点:
- 变量的类型需要是字符串类型;
- 变量未被初始化,或被初始化成一个字符串常量表达式;
- 如果被初始化成一个函数调用的返回值,或是引用其它变量,则不会生效;
- 变量不需要是导出变量(文档未提及);
- 可以多次使用该参数以修改多个变量的值;
- 不存在的变量会直接忽略。
然而,我们通常直接使用 go build
一个命令来完成编译与链接工作,不会直接调用链接器。
所以,应该让 go build
帮我们把这些参数传递给链接器。这时候需要用到 go build
的 -ldflags
参数:
-ldflags '[pattern=]arg list'
arguments to pass on each go tool link invocation.
特别需要注意 shell 语法中引号、空格的使用,不然很容易出错。
修改 main 包的变量
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
编译及运行:
1 2 3 |
|
这个结果不是很好看,可以格式化一下 date 的输出:
1 2 3 |
|
修改导入包的变量
导入包需要写完整的导入路径。
比如我的 main 导入了一个外部包:
1 2 3 4 5 6 7 8 9 10 11 |
|
可以用下面的命令修改 version
包的 BuiltAt
变量的值:
1
|
|
因为我要在 main
包使用这个变量,所以将其大写后导出了。
同时修改多个变量
用空格把它们分开就好了,注意引号把全部引起来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
编译命令及运行结果:
1 2 3 4 |
|
在脚本中执行
手写太长的命令通常不是一个好注意,放在脚本中是个不错的选择。
以下代码片段节选中我博客的相关代码。
-
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
package main import ( "fmt" "os" ) var ( builtOn string builtAt string goVersion string gitAuthor string gitCommit string ) func main() { fmt.Fprintf(os.Stderr, ""+ "Built On : %s\n"+ "Built At : %s\n"+ "Go Version: %s\n"+ "Git Author: %s\n"+ "Git Commit: %s\n", builtOn, builtAt, goVersion, gitAuthor, gitCommit, ) }
-
build.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/bin/bash set -euo pipefail builtOn="$USER@$(hostname)" builtAt="$(date +'%F %T %z')" goVersion=$(go version | sed 's/go version //') gitAuthor=$(git show -s --format='format:%aN <%ae>' HEAD) gitCommit=$(git rev-parse HEAD) ldflags="\ -X 'main.builtOn=$builtOn' \ -X 'main.builtAt=$builtAt' \ -X 'main.goVersion=$goVersion' \ -X 'main.gitAuthor=$gitAuthor' \ -X 'main.gitCommit=$gitCommit' \ " go build -ldflags "$ldflags"
编译及运行结果:
1 2 3 4 5 6 7 |
|