GoSuda

Goにおけるコンパイル時変数インジェクション

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で引数を渡すと、ビルド時にコンパイルタイムに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型のみサポート: 他の型はサポートしていません。

参照