Como injetar valores em variáveis com ldflags

Uma feature pouco conhecida para quem está iniciando na linguagem Go, é a capacidade de injetarmos valores em variáveis durante o processo de build. Embora possa parecer um tanto quanto estranho fazer isso, essa técnica nos possibilita adicionar informações como versão, data e commit do build, sem a necessidade de commitar essas informações. Embora possamos criar essas variáveis no mesmo arquivo onde estará a função main da aplicação, eu prefiro fazer algo que possa ser reutilizado.

Definindo as variáveis de build

Por isso, pensando em um repositório onde haverão várias aplicações, ou até mesmo em uma estrutura de monorepo, vamos criar um package dentro da pasta pkg chamado build. Dentro do package, vamos criar um arquivo chamado version.go com o seguinte conteúdo.

package build

var (
	Commit   string = "-"
	Datetime string = "0000-00-00T00:00:00"
	Version  string = "dev"
)

Essas variáveis terão seus valores padrões substituídos no processo de build. Agora, dentro da pasta cmd, vamos adicionar o seguinte conteúdo em um arquivo de nome main.go.

package main

import (
	"fmt"

	"github.com/aprendagolang/version/pkg/build"
)

func main() {
	fmt.Println("version:", build.Version)
	fmt.Println("commit:", build.Commit)
	fmt.Println("time:", build.Datetime)
}

Feito isso, ao executar o comando go run cmd/main.go, o seguinte output é esperado.

version: dev
commit: -
time: 0000-00-00T00:00:00

Maravilha! Isso quer dizer que nosso arquivo está conseguindo ler as variáveis do package build. Tudo que precisamos fazer agora, é modificar essas variáveis durante o processo de build. Para isso, vamos utilizar a flag -ldflags.

ldflags

Para facilitar a utilização da flag, dentro da pasta scripts, vamos criar um arquivo com o nome de build.sh com o seguinte conteúdo.

#!/usr/bin/env bash

PACKAGE="github.com/aprendagolang/version/pkg"

VERSION="$(git describe --tags --always --abbrev=0 --match='v[0-9]*.[0-9]*.[0-9]*' 2> /dev/null | sed 's/^.//')"
COMMIT_HASH="$(git rev-parse --short HEAD)"
BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')

LDFLAGS=(
  "-X '${PACKAGE}/build.Version=${VERSION}'"
  "-X '${PACKAGE}/build.Commit=${COMMIT_HASH}'"
  "-X '${PACKAGE}/build.Datetime=${BUILD_TIMESTAMP}'"
)

go build -ldflags="${LDFLAGS[*]}" -o server ./cmd/

Começamos nosso script declarando uma variável PACKAGE, onde sua única função é não tornar repetitivo a escrita do endereço de onde está o package build. VERSION, COMMIT_HASH e BUILD_TIMESTAMP são as três variáveis onde armazenaremos os valores para serem injetados no binário. A variável LDFLAGS, é responsável por guardar as flags que vamos passar para o comando go build. Repare que após cada -X, temos que declarar o caminho completo do nosso package build + nome da variável que definimos no arquivo version.go. Por fim, executamos o comando go build com a flag -ldflags e a variável que criamos. Também definimos o nome server para a saída do nosso binário, e apontamos a pasta onde está o arquivo com a função main. Se você está utilizando Linux ou Mac, não esqueça de dar um chmod +x ./scripts/build.sh antes de executar o arquivo de build. Agora, executamos o script com um ./scripts/build.sh. Se tudo deu certo, um binário com o nome server deve ter sido criado no root do diretório. Como meu diretório já tinha alguns commits e tags, ao fazer um ./server para executar o binário, obtive uma saída diferente de quando fizemos o go run.

version: 1.0.0
commit: 9d71ada
time: 2023-07-18T05:54:06

Conclusão

Como eu disse no início do post, de forma muito simples, essa técnica é muito utilizada para que as informações de build não sejam injetadas manualmente como é obrigatório em algumas linguagens. Espero que você tenha gostado! Não deixe de se inscrever na nossa newsletter e assinar o canal do YouTube. Até a próxima!


Se inscreva na nossa newsletter

* indicates required

Deixe uma resposta