GoSuda

Compile-Time Variable Injection в Go

By wHoIsDReAmer
views ...

Предыстория

Работая над проектом компании на этот раз, я искал способ внедрения переменных во время компиляции (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: Другие типы не поддерживаются.

Ссылки