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