Инжектиране на променливи по време на компилация в Go: използване на go build -ldflags -X

Предистория
В рамките на текущия проект в компанията търсих начин за инжектиране на променливи по време на компилация без използване на .env файл. Смятах, че ако това е възможно, ще е много удобно, тъй като ще е необходим само един файл, без .env или множество конфигурационни файлове.
Първоначално потърсих CLI инструмент за go:generate, който генерира файл с константи въз основа на .env, но такъв не намерих.
Но ако е така, би било по-просто да се редактират директно constants, без да се правят излишни стъпки за генериране. Тогава открих, че в 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, стойността 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: други типове не се поддържат