Compile-Time Variable Injection в Go
Предыстория
Работая над проектом компании на этот раз, я искал способ внедрения переменных во время компиляции (compile time) без использования .env.
Я полагал, что это будет крайне удобно, поскольку потребуется всего один файл вместо .env или множества файлов конфигурации.
Сначала я искал что-то вроде go:generate CLI, который генерирует файлы констант на основе .env, но такого инструмента не нашлось.
Однако, если бы такой инструмент существовал, было бы проще просто изменить constants напрямую, а не утруждаться генерацией (gen), поэтому я искал способ внедрения значений во время компиляции (compile time), подобно макросу include_bytes! в Rust.
Внедрение переменных во время компиляции (Compile Time Variable Injection)
Использование простое.
1package main
2
3import "fmt"
4
5var Foo string
6
7func main() {
8 fmt.Println(Foo)
9}
Если предположить, что имеется код, подобный приведенному выше, его можно внедрить во время сборки (build) следующим образом.
1go build -ldflags="-X 'main.Foo=bar'"
Если аргументы передаются через ldflag, значение bar внедряется в переменную Foo во время компиляции (compile time) в процессе сборки (build). Это просто.
Если в проекте есть пакеты (package) или переменные (variable) с одинаковым именем в нескольких местах, можно указать путь к пакету (package path).
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'"
Даже если в одном пакете (package) имеется несколько переменных (variable), можно просто передать дополнительные аргументы.
1go build -ldflags="-X 'main.Version=v1.0.0' -X 'main.BuildTime=2025-05-27' -X 'main.GitCommit=abc123'"
Особенности следующие:
- Переменные (
variable) не обязательно должны быть публичными (public): Переменные, начинающиеся со строчной буквы, также могут быть внедрены. - Поддерживается только тип
string: Другие типы не поддерживаются.