Utilisation de ldflags pour définir les informations de version des applications Go

introduction

Lors du déploiement d'applications dans un environnement de production, la création de fichiers binaires avec des informations de version et d'autres métadonnées améliorera vos processus de surveillance, de journalisation et de débogage en ajoutant des informations d'identification permettant de suivre vos générations au fil du temps. Ces informations de version peuvent souvent inclure des données hautement dynamiques, telles que le temps de construction, la machine ou l'utilisateur qui construit le binaire, l'ID de validationVersion Control System (VCS) avec lequel il a été construit, etc. Comme ces valeurs changent constamment, coder ces données directement dans le code source et les modifier avant chaque nouvelle construction est fastidieux et sujet aux erreurs: les fichiers sources peuvent se déplacer etvariables/constants peut changer de fichier tout au long du développement, interrompant le processus de construction. .

Une façon de résoudre ce problème dans Go est d'utiliser-ldflags avec la commandego build pour insérer des informations dynamiques dans le binaire au moment de la construction, sans avoir besoin de modifier le code source. Dans cet indicateur,ld représentelinker, le programme qui relie les différentes parties du code source compilé dans le binaire final. ldflags, alors, signifielinker flags. Il s'appelle ainsi car il transmet un indicateur à l'éditeur de liens de la chaîne d'outils Go sous-jacent,cmd/link, qui vous permet de modifier les valeurs des packages importés au moment de la construction à partir de la ligne de commande.

Dans ce didacticiel, vous utiliserez-ldflags pour modifier la valeur des variables au moment de la construction et introduire vos propres informations dynamiques dans un fichier binaire, à l'aide d'un exemple d'application qui imprime les informations de version à l'écran.

Conditions préalables

Pour suivre l'exemple de cet article, vous aurez besoin de:

Construire votre exemple d'application

Avant de pouvoir utiliserldflags pour introduire des données dynamiques, vous avez d'abord besoin d'une application dans laquelle insérer les informations. Dans cette étape, vous allez créer cette application qui, à ce stade, n’imprimera que les informations de versioning statiques. Créons cette application maintenant.

Dans votre répertoiresrc, créez un répertoire nommé d'après votre application. Ce tutoriel utilisera le nom de l'applicationapp:

mkdir app

Changez votre répertoire de travail dans ce dossier:

cd app

Ensuite, à l'aide de l'éditeur de texte de votre choix, créez le point d'entrée de votre programme,main.go:

nano main.go

Maintenant, faites en sorte que votre application imprime les informations de version en ajoutant le contenu suivant:

app/main.go

package main

import (
    "fmt"
)

var Version = "development"

func main() {
    fmt.Println("Version:\t", Version)
}

À l'intérieur de la fonctionmain(), vous avez déclaré la variableVersion, puis imprimé lesstringVersion:, suivi d'un caractère de tabulation, , puis le variable.

À ce stade, la variableVersion est définie commedevelopment, qui sera la version par défaut de cette application. Plus tard, vous changerez cette valeur en un numéro de version officiel, organisé selonsemantic versioning format.

Enregistrez et quittez le fichier. Une fois que cela est fait, générez et exécutez l'application pour vous assurer qu'elle affiche la version correcte:

go build
./app

Vous verrez la sortie suivante:

OutputVersion:     development

Vous disposez maintenant d'une application qui imprime les informations de version par défaut, mais vous ne disposez pas encore d'un moyen de transmettre les informations de version actuelles au moment de la construction. Dans l'étape suivante, vous utiliserez-ldflags etgo build pour résoudre ce problème.

Utilisation deldflags avecgo build

Comme mentionné précédemment,ldflags signifielinker flags et est utilisé pour transmettre des indicateurs à l'éditeur de liens sous-jacent dans la chaîne d'outils Go. Cela fonctionne selon la syntaxe suivante:

go build -ldflags="-flag"

Dans cet exemple, nous avons transmisflag à la commande sous-jacentego tool link qui s'exécute en tant que partie dego build. Cette commande utilise des guillemets doubles autour du contenu passé àldflags pour éviter de casser des caractères qu'il contient, ou des caractères que la ligne de commande pourrait interpréter comme autre chose que ce que nous voulons. De là, vous pouvez passer enmany different link flags. Pour les besoins de ce tutoriel, nous utiliserons l'indicateur-X pour écrire des informations dans la variable au moment du lien, suivi du cheminpackage vers la variable et sa nouvelle valeur:

go build -ldflags="-X 'package_path.variable_name=new_value'"

À l'intérieur des guillemets, il y a maintenant l'option-X et unkey-value pair qui représente la variable à modifier et sa nouvelle valeur. Le caractère. sépare le chemin du package et le nom de la variable, et des guillemets simples sont utilisés pour éviter de casser les caractères dans la paire clé-valeur.

Pour remplacer la variableVersion dans votre exemple d'application, utilisez la syntaxe du dernier bloc de commande pour passer une nouvelle valeur et construire le nouveau binaire:

go build -ldflags="-X 'main.Version=v1.0.0'"

Dans cette commande,main est le chemin du package de la variableVersion, puisque cette variable se trouve dans le fichiermain.go. Version est la variable dans laquelle vous écrivez etv1.0.0 est la nouvelle valeur.

Pour utiliserldflags, la valeur que vous souhaitez modifier doit exister et être une variable de niveau package de typestring. Cette variable peut être exportée ou non exportée. La valeur ne peut pas être unconst ou avoir sa valeur définie par le résultat d'un appel de fonction. Heureusement,Version répond à toutes ces exigences: il a déjà été déclaré comme variable dans le fichiermain.go, et la valeur actuelle (development) et la valeur souhaitée (v1.0.0 ) sont les deux chaînes.

Une fois que votre nouveau binaireapp est construit, exécutez l'application:

./app

Vous recevrez le résultat suivant:

OutputVersion:     v1.0.0

En utilisant-ldflags, vous avez réussi à changer la variableVersion dedevelopment àv1.0.0.

Vous avez maintenant modifié une variablestring à l'intérieur d'une application simple au moment de la construction. À l'aide deldflags, vous pouvez incorporer les détails de la version, les informations de licence et plus encore dans un fichier binaire prêt à être distribué, en utilisant uniquement la ligne de commande.

Dans cet exemple, la variable que vous avez modifiée se trouvait dans le programmemain, ce qui réduit la difficulté de déterminer le nom du chemin. Mais parfois, le chemin de ces variables est plus compliqué à trouver. Dans l'étape suivante, vous allez écrire des valeurs dans des variables de sous-packages pour montrer la meilleure façon de déterminer des chemins de package plus complexes.

Ciblage des variables de sous-package

Dans la dernière section, vous avez manipulé la variableVersion, qui se trouvait dans le package de niveau supérieur de l'application. Mais ce n'est pas toujours le cas. Il est souvent plus pratique de placer ces variables dans un autre package, carmain n'est pas un package importable. Pour simuler cela dans votre exemple d'application, vous allez créer un nouveau sous-package,app/build, qui stockera des informations sur l'heure à laquelle le binaire a été construit et le nom de l'utilisateur qui a émis la commande de construction.

Pour ajouter un nouveau sous-package, ajoutez d'abord un nouveau répertoire à votre projet nommébuild:

mkdir -p build

Puis créez un nouveau fichier nommébuild.go pour contenir les nouvelles variables:

nano build/build.go

Dans votre éditeur de texte, ajoutez de nouvelles variables pourTime etUser:

app/build/build.go

package build

var Time string

var User string

La variableTime contiendra une représentation sous forme de chaîne de l'heure à laquelle le binaire a été construit. La variableUser contiendra le nom de l'utilisateur qui a construit le binaire. Étant donné que ces deux variables auront toujours des valeurs, vous n’avez pas besoin d’initialiser ces variables avec des valeurs par défaut comme vous l’avez fait pourVersion.

Enregistrez et quittez le fichier.

Ensuite, ouvrezmain.go pour ajouter ces variables à votre application:

nano main.go

À l'intérieur demain.go, ajoutez les lignes en surbrillance suivantes:

main.go

package main

import (
    "app/build"
    "fmt"
)

var Version = "development"

func main() {
    fmt.Println("Version:\t", Version)
    fmt.Println("build.Time:\t", build.Time)
    fmt.Println("build.User:\t", build.User)
}

Dans ces lignes, vous avez d'abord importé le packageapp/build, puis imprimébuild.Time etbuild.User de la même manière que vous avez impriméVersion.

Enregistrez le fichier, puis quittez votre éditeur de texte.

Ensuite, pour cibler ces variables avecldflags, vous pouvez utiliser le chemin d'importationapp/build suivi de.User ou.Time, puisque vous connaissez déjà le chemin d'importation. Cependant, pour simuler une situation plus complexe dans laquelle le chemin vers la variable n’est pas évident, utilisons à la place la commandenm dans la chaîne d’outils Aller.

La commandego tool nm affichera lessymbols impliqués dans un exécutable, un fichier objet ou une archive donné. Dans ce cas, un symbole fait référence à un objet du code, tel qu'une variable ou une fonction définie ou importée. En générant une table de symboles avecnm et en utilisantgrep pour rechercher une variable, vous pouvez trouver rapidement des informations sur son chemin.

[.note] #Note: La commandenm ne vous aidera pas à trouver le chemin de votre variable si le nom du package ne contient pas de https: //en.wikipedia.org/wiki/ASCII [ASCII ] caractères, ou un caractère" ou%, car il s'agit d'une limitation de l'outil lui-même.
#

Pour utiliser cette commande, construisez d'abord le binaire pourapp:

go build

Maintenant queapp est construit, pointez l'outilnm dessus et recherchez dans la sortie:

go tool nm ./app | grep app

Lorsqu'il est exécuté, l'outilnm sortira beaucoup de données. Pour cette raison, la commande précédente utilisait| pour diriger la sortie vers la commandegrep, qui recherchait ensuite les termes ayant le niveau supérieurapp dans le titre.

Vous recevrez une sortie similaire à celle-ci:

Output  55d2c0 D app/build.Time
  55d2d0 D app/build.User
  4069a0 T runtime.appendIntStr
  462580 T strconv.appendEscapedRune
. . .

Dans ce cas, les deux premières lignes du jeu de résultats contiennent les chemins vers les deux variables que vous recherchez:app/build.Time etapp/build.User.

Maintenant que vous connaissez les chemins, créez à nouveau l'application, en changeant cette foisVersion,User etTime au moment de la construction. Pour ce faire, transmettez plusieurs indicateurs-X à-ldflags:

go build -v -ldflags="-X 'main.Version=v1.0.0' -X 'app/build.User=$(id -u -n)' -X 'app/build.Time=$(date)'"

Ici, vous avez passé la commandeid -u -n Bash pour lister l'utilisateur actuel, et la commandedate pour lister la date actuelle.

Une fois l'exécutable construit, lancez le programme:

./app

Cette commande, lorsqu'elle est exécutée sur un système Unix, générera une sortie similaire à celle-ci:

OutputVersion:     v1.0.0
build.Time:  Fri Oct  4 19:49:19 UTC 2019
build.User:  sammy

Vous disposez maintenant d'un fichier binaire contenant des informations de version et de génération permettant de fournir une assistance essentielle en production lors de la résolution de problèmes.

Conclusion

Ce tutoriel a montré comment, lorsqu'il est appliqué correctement,ldflags peut être un outil puissant pour injecter des informations précieuses dans les binaires au moment de la construction. De cette façon, vous pouvez contrôler les indicateurs de fonctionnalité, les informations sur l’environnement, les informations sur la gestion des versions, etc. sans introduire de modifications dans votre code source. En ajoutantldflags à votre flux de travail de construction actuel, vous pouvez maximiser les avantages du format de distribution binaire autonome de Go.

Si vous souhaitez en savoir plus sur le langage de programmation Go, consultez nosHow To Code in Go series complets. Si vous recherchez plus de solutions pour le contrôle de version, essayez notre guide de référenceHow To Use Git.