GoSuda

Go 编译时变量注入:go build -ldflags -X 用法详解

By wHoIsDReAmer views ...

背景

这次在公司项目工作中,我查找了是否有不使用 .env 而在编译时注入变量的方法。我想,这样只需要一个文件,而无需 .env 或多个配置文件,应该会非常方便。

最初我查找的是能够基于 .env 生成常量文件的 go:generate CLI 之类的工具,但没有找到。

不过,既然这样,直接修改 constants 就行了,没必要麻烦地再执行 gen,于是我找到了类似 Rust 中 include_bytes! 宏那样、可以在编译时注入值的方法。

编译时变量注入

用法很简单。

1package main
2
3import "fmt"
4
5var Foo string
6
7func main() {
8    fmt.Println(Foo)
9}

假设有如上的代码,在构建时可以按如下方式注入。

1go build -ldflags="-X 'main.Foo=bar'"

通过 ldflag 传递参数后,在构建时的编译阶段,bar 值会被注入到 Foo 变量中。很简单。

如果项目中多个地方存在同名的包或变量,则明确指定包路径即可。

1// github.com/myproject/config/config.go
2package config
3
4var Version string
5
6// github.com/myproject/internal/config/config.go
7package config
8
9var BuildTime string

在这种情况下,可以按如下方式加以区分后注入:

1go build -ldflags="-X 'github.com/myproject/config.Version=v1.0.0' -X 'github.com/myproject/internal/config.BuildTime=2025-05-27'"

同一个包中存在多个变量时,只需追加相应的参数即可。

1go build -ldflags="-X 'main.Version=v1.0.0' -X 'main.BuildTime=2025-05-27' -X 'main.GitCommit=abc123'"

其特点如下:

  • 变量无需为公开的:以小写字母开头的变量也可以注入
  • 仅支持 string 类型:不支持其他类型

参考