为了对运行程序进行版本追踪,避免各个版本的服务程序混淆,通常的做法为在go build编译的时候程序注入
版本标志、编译时间、当前分支、当前 Tag、当前的提交号等信息,让go程序在运行的时候就可以打印编译时候的参数情况。
golang项目常用三个参数,含义如下:
-X definition #注入变量定义
add string value definition of the form importpath.name=value
-s disable symbol table # 禁用符号表
-w disable DWARF generation # 禁用调试信息
-s -w俩个参数可以减小构建二进制包大小。
CGO_ENABLED=0 go build \
-ldflags " \
-X 'main.BuildVersion=${build_version}' \
-X 'main.BuildGoVersion=${go_version}' \
-X 'main.BuildTime=${build_time}' \
-X 'main.BuildCommit=${build_commit}' \
-o ${APP_NAME}
" main.go
CGO_ENABLED=0 禁用cgo。
-X ‘main.BuildVersion=${build_version}’ 编译时候会想main中注册变量BuildVersion,如下代码中main.go代码即可接受。
package main
import (
"flag"
"fmt"
)
// 构建版本信息
var (
BuildVersion = ""
BuildGoVersion = ""
BuildCommit = ""
BuildTime = ""
)
func main() {
// 构建信息,golang版本 commit id 时间
var version bool
flag.BoolVar(&version, "v", false, "version")
flag.Parse()
if version {
fmt.Printf("go version: %s\n,Build version: %s\n, Build commit: %s\n, Build time: %s\n",
BuildGoVersion, BuildVersion, BuildCommit, BuildTime)
return
}
// 业务逻辑
}
编译后结果运行如下
$ ./demo_app -v
go version: go version go1.19.2 darwin/amd64,
Build version: dev_8899bca,
Build commit: 8899bca,
Build time: 2022-11-21T15:12:57Z
Makefile简单理解为它定义了一个项目文件的编译规则。早期适用于 C/C++ 工程的编译,一旦写编写好 Makefile 文件,
只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。
后面随着逐渐发展其它项目也开始使用Makefile进行服务的编译,极大简化项目编译过程。
所以我们将上文的go build命令集合进Makefile文件中,简化编译过程。
Makefile结构说明
Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。
获取仓库taggit describe --tags --abbrev=0
获取仓库最近提交commit id
git rev-parse --short HEAD
获取仓库当前所处分支git rev-parse --abbrev-ref HEAD
在go项目仓库根目录下 创建Makefile文件
git_rev = $(shell git rev-parse --short HEAD)
git_tag = $(shell git describe --tags --abbrev=0)
git_branch = $(shell git rev-parse --abbrev-ref HEAD)
app_name = "demo_app"
BuildVersion := $(git_branch)_$(git_rev)
BuildTime := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ')
BuildCommit := $(shell git rev-parse --short HEAD)
BuildGoVersion := $(shell go version)
# in detached HEAD state
ifeq ($(git_branch), HEAD)
git_branch = $(shell git show-ref | grep $(shell git show HEAD | sed -n 1p | cut -d " " -f 2) | sed 's|.*/\(.*\)|\1|' | grep -v HEAD | sort | uniq | head -n 1)
# when git checkout <>, branch may still be empty
ifeq ($(git_branch), )
git_branch := $(git_tag)
endif
BuildVersion := $(git_branch)_$(git_rev)
endif
ifeq ($(git_branch), develop)
BuildVersion := develop_$(git_rev)
endif
ifeq ($(git_branch), master)
BuildVersion := release_$(git_tag)_$(git_rev)
endif
# -ldflag 参数
GOLDFLAGS = -s -w -X 'main.BuildVersion=$(BuildVersion)'
GOLDFLAGS += -X 'main.BuildTime=$(BuildTime)'
GOLDFLAGS += -X 'main.BuildCommit=$(BuildCommit)'
GOLDFLAGS += -X 'main.BuildGoVersion=$(BuildGoVersion)'
# go mod
mod:
go mod tidy
all: linux
# linux 构建二进制
linux:
@GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o "$(app_name)" -ldflags "$(GOLDFLAGS)"
# arm 构建二进制
arm:
@GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o "$(app_name)" -ldflags "$(GOLDFLAGS)"
# mac 构建二进制
mac:
@GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o "$(app_name)" -ldflags "$(GOLDFLAGS)"
make linux
即可生成demo_app二进制服务
编译后结果运行如下,与go build之后结果一样
$ ./demo_app -v
go version: go version go1.19.2 darwin/amd64,
Build version: dev_8899bca,
Build commit: 8899bca,
Build time: 2022-11-21T15:12:57Z
通过makefile与-ldflags结合注入服务版本信息,是一种常见方式,可以帮助我们快速定位一些基础问题,避免踩坑。