Interesting applications of Golang compilation options (ldflags)

This article describes how to use the ldflags option to inject variables into Golang applications during construction, which is used to add information such as version identification or GIT submission summary to Go executable files.

Application version information

Let's first look at the commit information contained in Docker Cli:

docker version

return result:

Server: Docker Engine - Community
 Engine:
  Version:          23.0.1
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.5
  Git commit:       bc3805a
  Built:            Thu Feb  9 19:46:56 2023
  OS/Arch:          linux/amd64
  Experimental:     false

You can see that it contains Git commit: bc3805ainformation , which is the last version information submitted by git.

So why add version information? This information makes it easy to identify which version the user is using and how long it has been used.

Git commit log

Before getting into the topic, let's think about what information is meaningful to inject at build time? It can be anything like the name of the host serving the web or more commonly the last commit id of GIT. The following briefly demonstrates how to obtain the ID of the last commit log of GIT.

$ git init && echo "let's work with git" > readme && git add . && git commit -m "initial "

Initialized empty Git repository in C:/Users/86137/Desktop/test/.git/
warning: LF will be replaced by CRLF in readme.
The file will have its original line endings in your working directory
[master (root-commit) b446263] initial
1 file changed, 1 insertion(+)
create mode 100644 readme

$ ls

readme

$ cat readme

let’s work with git

$ echo "let's keep working" >> readme && git add . && git commit -m "first update"

warning: LF will be replaced by CRLF in readme.
The file will have its original line endings in your working directory
[master b7a900c] first update
1 file changed, 1 insertion(+)

$ cat readme

let’s work with git
let’s keep working

Now we look at the GIT commit log twice:

$ git log

commit b7a900cdbb23493c4d48d009173daf9eb4b4e9d0 (HEAD -> master)
Author: test [email protected]
Date: Sat Mar 11 15:30:16 2023 +0800

first update

commit b446263cf7af8f62906587cbe97029df575ae592
Author: test [email protected]
Date: Sat Mar 11 15:29:34 2023 +0800

initial

Get the last commit ID with the following command:

$ git rev-list --all -1

b7a900cdbb23493c4d48d009173daf9eb4b4e9d0

$ export GIT_COMMIT=$(git rev-list --all -1) && echo $GIT_COMMIT

b7a900cdbb23493c4d48d009173daf9eb4b4e9d0

Sample Go application

Let's use a simple Hello World:

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello world")
}

In order to pass in the build-time variables, a variable needs to be dismantled in the main package, named here GitCommit:

package main

import (
    "fmt"
)

var GitCommit string

func main() {
    fmt.Printf("Hello world, version: %s\n", GitCommit)
}

Compile and run:

$ go build main.go && ./main.exe

Hello world, version:

The version information is empty, and the following starts to inject the version into the GitCommit variable.

use -ldflags

Now we add options to the go build command, and pass in the last submission ID of git as the version information. Let's take a look at the submission first:

$ git log
commit 1111c009f3caf4730bd31a4226d5a36e4b5a0083 (HEAD -> master)
Author: test <[email protected]>
Date:   Sat Mar 11 15:53:57 2023 +0800

    增加GIT_COMMIT变量

commit b7a900cdbb23493c4d48d009173daf9eb4b4e9d0
Author: test <[email protected]>
Date:   Sat Mar 11 15:30:16 2023 +0800

    first update

commit b446263cf7af8f62906587cbe97029df575ae592
Author: test <[email protected]>
Date:   Sat Mar 11 15:29:34 2023 +0800

    initial

The syntax of ldflags :

go build -ldflags="-X 'package_path.variable_name=new_value'", you can specify multiple variables at once.

Now use the previous knowledge to increment the last commit ID:

go build -ldflags "-X 'main.GitCommit=$(git rev-list --all -1)'" main.go

Executing the program can see the version information

$ ./main.exe

Hello world, version: 1111c009f3caf4730bd31a4226d5a36e4b5a0083

Of course we can also add multiple variables:

package main

import (
	"fmt"
)

var GitCommit string
var BuildTime string
var BuildUser string

func main() {
	fmt.Printf("Hello world, version: %s\n", GitCommit)
	fmt.Println("build.Time:\t", BuildTime)
	fmt.Println("build.User:\t", BuildUser)
}

go build -ldflags "-X main.GitCommit=$(git rev-list --all -1) -X 'main.BuildUser=$(id -u -n)' -X 'main.BuildTime=$(date +%F_%T)'" main.go

Run the program:

Hello world, version: 1111c009f3caf4730bd31a4226d5a36e4b5a0083
build.Time: 2023-03-11_16:36:50
build.User: 86137

compressed executable

We can also compress the executable with the -ldflags "-s -w" options:

go build -ldflags “-X main.GitCommit= ( g i t r e v − l i s t − − a l l − 1 ) − X ′ m a i n . B u i l d U s e r = (git rev-list --all -1) -X 'main.BuildUser= ( g i t re vlistall1)Xmain.BuildUser=(id -u -n)’ -X ‘main.BuildTime=$(date +%F_%T)’ -s -w” main.go

Compare the file size before and after compilation:

# 压缩前大约1.9M
-rwxr-xr-x 1 86137 197609 1965056  3月 11 16:37 main.exe*

# 压缩后为大约1.3M
-rwxr-xr-x 1 86137 197609 1338880  3月 11 16:58 main.exe*

Summarize

This article introduces the git commit log and how to add information to the Go program during construction, such as GIT commit log, compilation time and other information. The option to compress executable files is also mentioned in passing.

Guess you like

Origin blog.csdn.net/neweastsun/article/details/129465923
Recommended