Go の Compile-Time Variable Injection
背景
今回、会社のプロジェクト作業中に、.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で引数を渡すと、ビルド時にコンパイルタイムにFoo変数にbar値が注入されます。簡単です。
もしプロジェクト内で同じ名前のパッケージや変数が複数箇所にある場合、パッケージパスを明示すれば良いです。
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'"
特徴は以下の通りです:
- 変数がpublicである必要はない: 小文字で始まる変数も注入可能です
- string型のみをサポート: 他の型はサポートしていません