Tutorial

Usando ldflags para definir informações de versão em aplivativos Go

Published on February 13, 2020
Português
Usando ldflags para definir informações de versão em aplivativos Go

Introdução

Ao implantar aplicativos em um ambiente de produção, a compilação de binários com informações de versão e outros metadados irá melhorar seu processo de monitoramento, registro e depuração através da adição de informações de identificação para ajudar a rastrear suas compilações ao longo do tempo. Essas informações de versão com frequência podem incluir dados altamente dinâmicos, como o tempo de compilação, a máquina ou o usuário que compila o binário, o ID de confirmação do Sistema de Controle de Versão (VCS) em relação ao qual foi compilado, entre outras coisas. Como esses valores estão em constante mudança, codificar esses dados diretamente no código fonte e modificá-los antes de cada nova compilação é um processo tedioso e propenso a erros: os arquivos fonte podem mover-se e as variáveis/constantes podem trocar arquivos ao longo do desenvolvimento, interrompendo o processo de compilação.

Uma maneira de resolver isso em Go é usando -ldflags com o comando go build para inserir informações dinâmicas no binário no momento da compilação, sem a necessidade de modificar códigos fonte. Neste identificador, o ld significa linker [vinculador], o programa que vincula os diferentes pedaços do código fonte compilado em um binário final. ldflags, então, significa *linker flags *[identificadores de vinculador]. Ele recebe esse nome porque passa um identificador para o conjunto subjacente do vinculador da cadeia de ferramentas em Go, cmd/link, que permite que você altere os valores de pacotes importados no momento da compilação a partir da linha de comando.

Neste tutorial, você usará -ldflags para alterar o valor das variáveis no momento da compilação e introduzir suas próprias informações dinâmicas em um binário, usando um aplicativo exemplo que imprime informações de versão para a tela.

Pré-requisitos

Para seguir o exemplo neste artigo, será necessário:

Compilando seu aplicativo exemplo

Antes de poder usar ldflags para introduzir dados dinâmicos, será necessário primeiro um aplicativo no qual inserir as informações. Neste passo, você criará esse aplicativo, o qual, por enquanto,imprimirá apenas informações sobre o controle de versão estática. Vamos criar esse aplicativo agora.

No seu diretório src, crie um diretório com o nome do seu aplicativo. Este tutorial usará o nome de aplicativo app:

  1. mkdir app

Mude seu diretório de trabalho para essa pasta:

  1. cd app

Em seguida, usando o editor de texto de sua escolha, crie o ponto de entrada do seu programa, main.go:

  1. nano main.go

Agora, faça seu aplicativo imprimir informações de versão, adicionando o seguinte conteúdo:

app/main.go
package main

import (
	"fmt"
)

var Version = "development"

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

Dentro da função main(), você declarou a variável Version, em seguida imprimiu a string Version:, seguida de um caractere de guia (tab), \t e, na sequência declarou a variável.

Neste ponto, a variável Version foi definida como development, a qual será a versão padrão desse app. Mais tarde, você trocará esse valor por um número oficial de versão, organizado segundo o formato semântico para controle de versão.

Salve e saia do arquivo. Assim que terminar, compile e execute o aplicativo para confirmar que ele imprime a versão correta:

  1. go build
  2. ./app

Você verá o seguinte resultado:

  1. Output
    Version: development

Agora, você tem um aplicativo que imprime informações da versão padrão, mas ainda não tem como enviar as informações da versão atual no momento da compilação. No próximo passo, você usará -ldflags e go build para resolver esse problema.

Usando ldflags com o go build

Assim como mencionado anteriormente, ldflags significa identificadores de vinculador e é usado para enviar identificadores para o vinculador subjacente na cadeia de ferramentas Go. Isso funciona de acordo com a seguinte sintaxe:

  1. go build -ldflags="-flag"

Nesse exemplo, transmitimos o flag para o comando go tool link subjacente que executa como parte do go build. Esse comando usa aspas duplas ao redor do conteúdo transmitido para os ldflags para evitar quebrar caracteres nele, ou caracteres que a linha de comando possa interpretar como algo diferente do que queremos. A partir daqui, você poderia enviar muitos e diferentes identificadores de link. Para os fins deste tutorial, usaremos o identificador -X para gravar informações na variável no momento de vincular, seguido do caminho do pacote até a variável e seu novo valor:

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

Dentro das aspas, há agora a opção -X e um par chave-valor que representa a variável a ser alterada e seu novo valor. O caractere . separa o caminho do pacote e o nome da variável e aspas únicas são usadas para evitar a quebra de caracteres no par chave-valor.

Para substituir a variável Version no seu aplicativo exemplo, use a sintaxe no último bloco de comando para enviar um novo valor e compilar o novo binário:

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

Neste comando, main é o caminho de pacote da variável Version, uma vez que essa variável está no arquivo main.go. Version é a variável para a qual está gravando, e o v1.0.0 é o novo valor.

Para usar o ldflags, o valor que você quiser alterar deve existir e ser uma variável do nível de pacote do tipo string. Essa variável pode ser exportada ou não exportada. O valor não pode ser const ou ter seu valor definido pelo resultado de uma chamada de função. Felizmente, Version se encaixa em todos esses requisitos: ela já foi declarada como variável no arquivo main.go, assim como o valor atual (development) e o valor desejado (v1.0.0) são ambos strings.

Assim que seu novo binário app for compilado, execute o aplicativo:

  1. ./app

Você receberá o seguinte resultado:

  1. Output
    Version: v1.0.0

Usando -ldflags, você mudou com sucesso a variável Version de development para v1.0.0.

Agora, você modificou uma variável string dentro de um aplicativo simples na hora da compilação. Usando ldflags, você pode inserir detalhes de versão, informações de licenciamento e outras coisas em um binário pronto para a distribuição, usando apenas a linha de comando.

Neste exemplo, a variável que você mudou estava no programa main, o que reduz a dificuldade em determinar o nome do caminho. No entanto, as vezes, o caminho para essas variáveis é mais complicado de se encontrar. No próximo passo, você irá gravar valores para as variáveis nos subpacotes para demonstrar a melhor maneira de se determinar caminhos de pacotes mais complexos.

Concentrando-se em variáveis para subpacotes

Na última seção, você manipulou a variável Version, a qual estava no pacote de nível superior do aplicativo. Mas esse não é sempre o caso. Com frequência, é mais prático colocar essas variáveis em outro pacote, já que o main não é um pacote importável. Para simular isso em seu aplicativo exemplo, você criará um novo subpacote, app/build que armazenará informações sobre a hora em que o binário foi compilado e o nome do usuário que emitiu o comando de compilação.

Para adicionar um novo subpacote, adicione primeiro um novo diretório ao seu projeto chamado build:

  1. mkdir -p build

Depois, crie um novo arquivo chamado build.go para reter as novas variáveis:

  1. nano build/build.go

No seu editor de texto, adicione novas variáveis para Time e User:

app/build/build.go
package build

var Time string

var User string

A variável Time reterá uma representação de string da hora em que o binário foi compilado. A variável User reterá o nome do usuário que compilou o binário. Como essas duas variáveis sempre terão valores, você não precisa inicializar essas variáveis com valores padrão como você fez para Version.

Salve e saia do arquivo.

Em seguida, abra o main.go para adicionar essas variáveis ao seu aplicativo:

  1. nano main.go

Dentro de main.go, adicione as seguintes linhas destacadas:

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)
}

Nessas linhas, você importou primeiro o pacote app/build e, então, imprimiu build.Time e build.User da mesma forma que imprimiu Version.

Salve o arquivo e depois saia do seu editor de texto.

Em seguida, para atingir essas variáveis com o ldflags, você poderia usar o caminho de importação app/build seguido de . User ou . Time, uma vez que você já sabe o caminho de importação. No entanto, para simular uma situação mais complexa na qual o caminho para a variável não é evidente, em vez disso, vamos usar o comando nm na cadeia de ferramentas Go.

O comando go tool nm dará como resultado os símbolos envolvidos em um dado executável, arquivo de objeto ou arquivo. Neste caso, um símbolo se refere a um objeto no código, como uma variável ou função definida ou importada. Ao gerar uma tabela de símbolos com nm e usar o grep para procurar por uma variável, você pode rapidamente encontrar informações sobre seu caminho.

Nota: o comando nm não ajudará você a encontrar o caminho da sua variável se o nome do pacote tiver qualquer caractere não ASCII ou um caractere " ou %, já que essa é uma limitação da ferramenta em si.

Para usar esse comando, compile primeiro o binário para app:

  1. go build

Agora que o app foi compilado, aponte a ferramenta nm para ele e examine o resultado:

  1. go tool nm ./app | grep app

Quando executada, a ferramenta nm gerará muitos dados como resultado. Por isso, o comando anterior usou o símbolo | para canalizar o resultado até o comando grep, o qual, na sequência, pesquisou termos que tivessem app de nível elevado no título.

Você irá receber um resultado parecido com este:

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

Neste caso, as duas primeiras linhas do conjunto de resultados contêm os caminhos para as duas variáveis que você está procurando: app/build.Time e app/build.User.

Agora que você conhece os caminhos, compile o aplicativo novamente, desta vez alterando Version, User e Time no momento de compilar. Para tanto, passe vários identificadores -X para os -ldflags:

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

Aqui, você enviou o comando Bash id -u -n para listar o usuário atual e o comando date para listar a data atual.

Assim que o executável estiver compilado, execute o programa:

  1. ./app

Esse comando, quando executado em um sistema Unix, gerará um resultado similar ao seguinte:

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

Agora, você tem um binário que contém informações do controle de versão e compilação que podem fornecer assistência vital na produção ao resolver problemas.

Conclusão

Este tutorial mostrou como, quando aplicado corretamento, o ldflags pode ser uma ferramenta poderosa para injetar informações valiosas em binários no momento da compilação. Dessa forma, você pode controlar identificadores de recursos, informações de ambiente, informações de controle de versão e outras coisas, sem introduzir alterações no seu código fonte. Ao adicionar ldflags ao seu fluxo de trabalho de compilação atual, você pode maximizar os benefícios do formato de distribuição binária independente do Go.

Se quiser aprender mais sobre a linguagem de programação Go, confira toda a nossa série sobre Como codificar em Go. Se estiver procurando mais soluções para controle de versão, teste nosso guia de referência Como usar o Git.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.