
L'un des grands atouts de Go est de produire un binaire unique, sans dépendance à installer chez l'utilisateur. Ce guide montre comment en tirer parti pour distribuer un outil : compiler avec go build, injecter la version et le commit dans le binaire via -ldflags -X, réduire sa taille, et le cross-compiler pour Linux, macOS et Windows depuis une seule machine. Public visé : intermédiaire en Go. Tous les exemples sont testés avec Go 1.26.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Compiler un binaire avec
go buildet l'installer avecgo install. - Injecter la version et le commit avec
-ldflags -X. - Réduire la taille du binaire avec
-s -w. - Cross-compiler pour plusieurs OS avec
GOOSetGOARCH.
go build et go install
Section intitulée « go build et go install »go build compile le paquet courant en un exécutable. Prenons un petit outil qui affiche sa version :
package main
import "fmt"
// Ces variables sont injectées au build via -ldflags -X.var ( version = "dev" commit = "none")
func main() { fmt.Printf("monoutil %s (commit %s)\n", version, commit)}go build -o monoutil ../monoutilmonoutil dev (commit none)Les valeurs par défaut (dev, none) s'affichent : on ne les a pas encore renseignées. go install fait la même compilation mais place le binaire dans $GOBIN (ou $GOPATH/bin), pratique pour un outil que vous utilisez localement.
Injecter la version avec -ldflags -X
Section intitulée « Injecter la version avec -ldflags -X »Coder la version en dur dans le fichier obligerait à modifier le code à chaque release. Go propose mieux : -ldflags -X écrit une valeur dans une variable de type chaîne au moment du link, sans toucher au source.
go build -ldflags "-X main.version=1.2.0 -X main.commit=a1b2c3d" -o monoutil ../monoutilmonoutil 1.2.0 (commit a1b2c3d)La syntaxe est -X chemin/du/paquet.Variable=valeur. Ici main.version cible la variable version du paquet main. En pratique, on alimente ces valeurs depuis Git :
go build -ldflags "-X main.version=$(git describe --tags --always) \ -X main.commit=$(git rev-parse --short HEAD)" -o monoutil .Réduire la taille du binaire
Section intitulée « Réduire la taille du binaire »Par défaut, le binaire embarque la table des symboles et les informations de debug (DWARF), utiles pour le débogage mais superflues en distribution. Les options -s (retire la table des symboles) et -w (retire le DWARF) allègent le binaire.
go build -o monoutil-big .go build -ldflags "-s -w" -o monoutil-small .ls -la monoutil-big monoutil-small2409844 monoutil-big1597602 monoutil-smallLe gain est net : environ 2,3 Mo tombent à 1,5 Mo, soit un tiers de moins, ici sans dépendance externe. En contrepartie, vous perdez le débogage symbolique sur ce binaire ; gardez une version non allégée si vous devez analyser un crash.
Cross-compiler pour plusieurs OS
Section intitulée « Cross-compiler pour plusieurs OS »C'est là que Go brille : depuis une seule machine, vous compilez pour n'importe quelle cible en fixant deux variables d'environnement, GOOS (système) et GOARCH (architecture). Aucun toolchain croisé à installer.
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o dist/monoutil-linux-amd64 .GOOS=linux GOARCH=arm64 go build -ldflags "-s -w" -o dist/monoutil-linux-arm64 .GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -o dist/monoutil-darwin-arm64 .GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o dist/monoutil-windows-amd64.exe .ls -la dist/1657858 monoutil-darwin-arm641597602 monoutil-linux-amd641573026 monoutil-linux-arm641680384 monoutil-windows-amd64.exeLes quatre cibles sont produites en quelques secondes. Les couples GOOS/GOARCH valides sont listés par go tool dist list. Notez le suffixe .exe ajouté à la main pour Windows.
Reproductibilité du build
Section intitulée « Reproductibilité du build »Deux compilations du même code devraient produire le même binaire. Par défaut, Go inscrit les chemins absolus de votre machine dans le binaire, ce qui casse cette propriété. L'option -trimpath remplace ces chemins par des références relatives au module :
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=1.2.0" -o monoutil .Combinée à des versions de dépendances figées par go.sum et à une version de Go fixée, -trimpath rapproche votre build de la reproductibilité : un audit peut recompiler et vérifier qu'il obtient le même binaire que celui distribué.
Bonnes pratiques
Section intitulée « Bonnes pratiques »- Injectez la version depuis Git (
git describe) plutôt que de la coder en dur. - Allégez avec
-s -wles binaires distribués, gardez une version complète pour le débogage. - Ajoutez
-trimpathsur les builds de release pour ne pas fuiter vos chemins locaux. - Utilisez
CGO_ENABLED=0pour un binaire statique destiné à un conteneur minimal. - Scriptez le build (Makefile ou tâche CI) : la commande complète est trop longue pour être retapée à la main.
À retenir
Section intitulée « À retenir »go buildproduit un binaire autonome, sans dépendance à installer.-ldflags -Xinjecte version et commit dans des variablesstringau link.-s -wréduit la taille d'environ un tiers en retirant symboles et debug.GOOS/GOARCHcross-compilent pour tout OS depuis une seule machine.-trimpathetCGO_ENABLED=0rapprochent le build de la reproductibilité et du statique.