Home  >  Article  >  Backend Development  >  Information embedding in Go 1.18 binaries

Information embedding in Go 1.18 binaries

Go语言进阶学习
Go语言进阶学习forward
2023-07-24 16:05:52981browse
The long-awaited Go 1.18 has finally been released. This version update has a lot of content, including generics, fuzz testing, multi-module workspaces, and new net/netip package, new string.Cut function, etc.

#Perhaps everyone has heard of the above characteristics. After reading the release note, I noticed a new feature that may not have been noticed by everyone: binary file information embedding.

The reason why we pay attention to this point is that we just worked on a different Go project version number management solution last weekI have discussed this issue in the article, and I feel that I have received a perfect combo with the official.

Build information embedding

In Go 1.18, through the go build build command, we can embed build information into the binary file.

Next, let’s intuitively feel it through examples.

First, make sure the Go 1.18 version is installed through the go version command.

$ go version
go version go1.18 darwin/amd64

Next, initialize the project environment

$ mkdir versionDemo
$ cd versionDemo
$ go mod init example/version
$ touch main.go

In main.go, write a simple printing logic

package main

import (
 "fmt"
)

func main() {
 fmt.Println("HELLO GOPHER")
}

At this point, we compile and obtain the binary file

$ go build -o main1.18 example/version

After obtaining the binary file, we can obtain some meta-information when compiling the file through the following command

$ go version -m main1.18
main1.18: go1.18
 path example/version
 mod example/version (devel)
 build -compiler=gc
 build CGO_ENABLED=1
 build CGO_CFLAGS=
 build CGO_CPPFLAGS=
 build CGO_CXXFLAGS=
 build CGO_LDFLAGS=
 build GOARCH=amd64
 build GOOS=darwin
 build GOAMD64=v1

可以看到,通过 <span style="font-size: 15px;">go version -m binaries</span> ,我们可以获取到二进制文件的各项构建信息。

当然,如果在构建过程中,为二进制文件指定了 -tags 等,我们同样能够以上的方式获取。

$ go build -tags version1.1 --ldflags="-X &#39;main.s=sss&#39;" -o main1.18more example/version
$ go version -m main1.18more
main1.18more: go1.18
 path example/version
 mod example/version (devel)
 build -compiler=gc
 build -ldflags="-X &#39;main.s=sss&#39;"
 build -tags=version1.1
 build CGO_ENABLED=1
 build CGO_CFLAGS=
 build CGO_CPPFLAGS=
 build CGO_CXXFLAGS=
 build CGO_LDFLAGS=
 build GOARCH=amd64
 build GOOS=darwin
 build GOAMD64=v1

VCS 信息嵌入

正如在一个不一样的 Go 项目版本号管理方案一文中探讨过的一样,版本信息不应该仅包含 Go 本身的信息,还应该包含 VCS 信息,例如 Git、Mercurial、Fossil 和 Bazaar。

在 Go 1.18,通过 go help build 命令,可以看到多了 -buildvcs 参数,它默认是打开的。

$ go help build
...
 -buildvcs
  Whether to stamp binaries with version control information. By default,
  version control information is stamped into a binary if the main package
  and the main module containing it are in the repository containing the
  current directory (if there is a repository). Use -buildvcs=false to
  omit version control information.
...

在上述项目中,我们添加 Git 版本控制。

$ git init
$ go build -o mainwithgit example/version
$ go version -m mainwithgit
mainwithgit: go1.18
 path example/version
 mod example/version (devel)
 build -compiler=gc
 build CGO_ENABLED=1
 build CGO_CFLAGS=
 build CGO_CPPFLAGS=
 build CGO_CXXFLAGS=
 build CGO_LDFLAGS=
 build GOARCH=amd64
 build GOOS=darwin
 build GOAMD64=v1
 build vcs=git
 build vcs.modified=true

此时,输出信息中多出了两列关于 vcs 的信息。接下来,我们将仓库内文件保存并提交。

$ git add go.mod main.go
$ git commit -m &#39;feat: this is a commit message&#39;
$ go build -o mainwithgit example/version
$ go version -m mainwithgit
 $ go version -m mainwithgit
mainwithgit: go1.18
 path example/version
 mod example/version (devel)
 build -compiler=gc
 build CGO_ENABLED=1
 build CGO_CFLAGS=
 build CGO_CPPFLAGS=
 build CGO_CXXFLAGS=
 build CGO_LDFLAGS=
 build GOARCH=amd64
 build GOOS=darwin
 build GOAMD64=v1
 build vcs=git
 build vcs.revision=f28c77dfcfcfb5289fae9318d3ab3e487b8a3b37
 build vcs.time=2022-03-20T14:26:24Z
 build vcs.modified=true

二进制文件中记录了更详细 vcs 信息,包括 git 版本号,提交时间等。

出于某些原因,有时我们并不想二进制中包含这些 vcs 信息,这时,在构建时指定 <span style="font-size: 15px;">-buildvcs=false</span> 即可。

没有 Go 环境,如何查看嵌入信息

在上面的场景中,我们都是通过执行 <span style="font-size: 15px;">go version -m binaries</span>  命令查看二进制文件的嵌入信息的。但是,在能拿到二进制文件的场景下,并不总是存在 Go 环境,例如没有 Go 环境的远程服务器。这样的场景中,如何查看它的嵌入信息呢?

这时,可以通过 <span style="font-size: 15px;">runtime/debug.ReadBuildInfo</span> 获取。例如,我们将上述例子中的 main.go  的内容更改如下

package main

import (
 "fmt"
 "runtime/debug"
)

func main() {
 info, _ := debug.ReadBuildInfo()
 fmt.Println("=========== build info ===========")
 fmt.Println(info)
}

同样可得到构建信息如下

=========== build info ===========
go      go1.18
path    workspace/example/versionDemo
mod     workspace/example/versionDemo   (devel) 
build   -compiler=gc
build   CGO_ENABLED=1
build   CGO_CFLAGS=
build   CGO_CPPFLAGS=
build   CGO_CXXFLAGS=
build   CGO_LDFLAGS=
build   GOARCH=amd64
build   GOOS=darwin
build   GOAMD64=v1
build   vcs=git
build   vcs.revision=b3f9cd7b83d4e624be942365728d676dfdca6a3e
build   vcs.time=2022-03-20T14:10:44Z
build   vcs.modified=true

因此,为了解决没有 Go 环境的远程服务器不能查看嵌入信息的情况。我们不妨利用 <span style="font-size: 15px;">runtime/debug.ReadBuildInfo</span> 函数,将其封装为一个接口,访问该接口即可获取当前二进制文件的嵌入信息。

总结

其实在 1.18 之前的版本中,Go 二进制文件就包括了少许的嵌入信息。例如同样是上文中的项目,我们通过 1.16 构建二进制文件,读取它的嵌入信息,其仅包括了 path 与 mod 信息。

$ go1.16.4 build -o main1.16 example/version
$ go1.16.4 version -m main1.16
main1.16: go1.16.4
 path example/version
 mod example/version (devel)

在 1.18 中,通过丰富二进制文件的嵌入信息,能够让我们更好地了解到当前程序。例如利用 vcs 信息可以判断从三方获取的 Go 二进制文件是否是预期程序,代码提交的发版部署是否有误等。

The above is the detailed content of Information embedding in Go 1.18 binaries. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:Go语言进阶学习. If there is any infringement, please contact admin@php.cn delete