Wstrzykiwanie zmiennych w czasie kompilacji w Go: zastosowanie go build -ldflags -X

Tło
Pracując nad projektem firmowym, sprawdziłem, czy istnieje sposób na wstrzykiwanie zmiennych w czasie kompilacji bez użycia pliku .env. Pomyślałem, że byłoby to bardzo wygodne, ponieważ wystarczyłby jeden plik, bez .env i wielu plików konfiguracyjnych.
Na początku szukałem narzędzia CLI dla go:generate, które generowałoby plik ze stałymi na podstawie .env, ale takiego nie znalazłem.
Skoro jednak i tak miałbym to zrobić, to lepiej po prostu zmodyfikować constants, bez zawracania sobie głowy generowaniem. Znalazłem wtedy sposób, który przypomina makro include_bytes! z Rusta, pozwalający wstrzyknąć wartość w czasie kompilacji.
Wstrzykiwanie zmiennych w czasie kompilacji
Sposób użycia jest prosty.
1package main
2
3import "fmt"
4
5var Foo string
6
7func main() {
8 fmt.Println(Foo)
9}
Mając powyższy kod, podczas budowania można wstrzyknąć wartość w następujący sposób.
1go build -ldflags="-X 'main.Foo=bar'"
Przekazując argument przez ldflag, wartość bar zostaje wstrzyknięta do zmiennej Foo w czasie kompilacji. To proste.
Jeśli w projekcie istnieją pakiety lub zmienne o tej samej nazwie w wielu miejscach, wystarczy podać ścieżkę pakietu.
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
W takim przypadku można rozróżnić je w następujący sposób:
1go build -ldflags="-X 'github.com/myproject/config.Version=v1.0.0' -X 'github.com/myproject/internal/config.BuildTime=2025-05-27'"
Również gdy w jednym pakiecie znajduje się wiele zmiennych, wystarczy przekazać dodatkowe argumenty.
1go build -ldflags="-X 'main.Version=v1.0.0' -X 'main.BuildTime=2025-05-27' -X 'main.GitCommit=abc123'"
Charakterystyka tego rozwiązania jest następująca:
- Zmienna nie musi być publiczna: można wstrzyknąć również zmienną zaczynającą się od małej litery
- Obsługiwany jest wyłącznie typ string: inne typy nie są obsługiwane