GoSuda

Инъекция переменных на этапе компиляции в Go

By wHoIsDReAmer
views ...

배경

В процессе работы над проектом компании возникла необходимость изучения методов внедрения переменных во время компиляции без использования .env файлов. Предполагалось, что такой подход обеспечит значительное удобство, поскольку для работы потребуется только один файл, исключая зависимость от .env или множества конфигурационных файлов.

Изначально был предпринят поиск CLI-инструментов, таких как go:generate, способных генерировать файлы констант на основе .env, однако таковых не было обнаружено.

Тем не менее, если бы такой инструмент существовал, это было бы излишним усложнением, поскольку можно было бы просто изменять сами константы; таким образом, был найден метод для внедрения значений во время компиляции, аналогичный макросу include_bytes! в Rust.

Компиляция переменных во время выполнения

Использование является простым.

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'"

Характеристики следующие:

  • Переменная не обязательно должна быть public: Возможно внедрение переменных, начинающихся со строчной буквы.
  • Поддерживается только тип string: Другие типы не поддерживаются.

참조