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.
Para seguir o exemplo neste artigo, será necessário:
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
:
- mkdir app
Mude seu diretório de trabalho para essa pasta:
- cd app
Em seguida, usando o editor de texto de sua escolha, crie o ponto de entrada do seu programa, main.go
:
- nano main.go
Agora, faça seu aplicativo imprimir informações de versão, adicionando o seguinte conteúdo:
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:
- go build
- ./app
Você verá o seguinte resultado:
- OutputVersion: 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.
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:
- 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:
- 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:
- 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:
- ./app
Você receberá o seguinte resultado:
- OutputVersion: 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.
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
:
- mkdir -p build
Depois, crie um novo arquivo chamado build.go
para reter as novas variáveis:
- nano build/build.go
No seu editor de texto, adicione novas variáveis para Time
e User
:
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:
- nano main.go
Dentro de main.go
, adicione as seguintes linhas destacadas:
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
:
- go build
Agora que o app
foi compilado, aponte a ferramenta nm
para ele e examine o resultado:
- 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
:
- 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:
- ./app
Esse comando, quando executado em um sistema Unix, gerará um resultado similar ao seguinte:
OutputVersion: 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.
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.
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!