前言
最近在负责维护和开发守护进程、运营平台监控、连接池等相关Go服务,首先守护进程服务是部署在客户的windows平台下运行,其它大部分服务都是部署在linux环境下,首先现在面临的一个问题就是如果在一台机器上进行跨平台交叉编译后可以在主流的Mac OS, Linux, Windows上运行。如何让每次发布的时候,自动带上版本号软件包呢?这下就轮到Makefile上场了……
这里主要介绍一下如何用Makefile以及Go本身所支持的编译特性,实现编译时自动生成版本号的功能。
在开始之前,假设我们程序发布的流程是这样:
1、编码完成,提交测试工程师测试
2、测试工程师测试出的bug都已解决,并重新测试和验证通过
3、工程师把修复好bug的代码合并到release分支,并建立git tag:2020-03011-release,准备用于最终程序的构建,发布和部署
在编译生成最终要发布的程序时,我们希望程序可以通过 -v 参数,提供如下的版本信息:
BTIME: 显示程序编译和构建时的日期
GITHEAD: 显示程序当前代码的git tag,用以在程序出现问题时,查找和定位对应版本的源代码
首先,我们需要实现一个demo程序,用于接收 -v 参数,在运行的时候,显示当前程序的编译构建时间,以及代码编译时所使用的git tag名称:
package main
import (
"flag"
"fmt"
)
var (
GITHEAD = "2020-03-11-release"
BTIME = "2020-03-11 16:01:00:080"
)
func main() {
version := flag.String("v", "2020-03-12-release", "version")
flag.Parse()
if version != nil {
fmt.Println("GITHEAD: " + GITHEAD)
fmt.Println("BTIME: " + BTIME)
fmt.Println("version: ", *version)
}
}
在程序中,我们为GITHEAD和BTIME定义了默认值。运行起来,是这样的:
我们已经有了一个程序,接收 -v 参数,并且能输出程序对应的GITHEAD和构建时间。不过不足的地方在于,每一次发布程序的时候,我们需要手动修改这两个值,再进行编译,非常不人性化,而且在发布程序的时候,总会忘掉这一步。于是,得用上Go的build -ldflags所提供的一个功能:-X 参数,使用-X参数,允许我们在编译构建Go程序的时候,传入自定义的值,覆盖对应的import path下的指定变量。于是,我们可以在编译程序的时候这么干:
go build -ldflags “-X main.GITHEAD=2020.03.13.release -X main.BTIME=2020-03-13 16:01:00:080” main.go
编译成功后,运行 ./main -v 程序输出:
到目前为止,我们已经成功的实现了”Compile time variables”,这意味着在编译时,动态传入参数和值,让程序在编译的时候,动态生成我们所指定的版本号。不过,这个GITHEAD和BITIME是在我们编译的时候指定的,而且编译的命令很长,作为一个懒惰的程序员,每次编译的时候敲这么长的命令是很磨人的。得用一种更灵活的方法来实现编译时传入参数,可选的方式大概有两种:
1、写一个shell脚本来实现编译的自动化
2、写一个Makefile文件,用make命令来编译
shell脚本是一种比较常用的方式,这次我们来体验一下用Makefile实现Go程序的编译。于是,我又折腾出来了一个Makefile文件:
NAME=project_nameBINDIR=GITV=BVERSION=BUILDTIME=GOBUILD= PLATFORM_LIST = WINDOWS_ARCH_LIST = all: darwin-amd64:
GOARCH=amd64 GOOS=darwin $ -o $/$-$@
linux-386:
GOARCH=386 GOOS=linux $ -o $/$-$@
linux-amd64:
GOARCH=amd64 GOOS=linux $ -o $/$linux-armv5:
GOARCH=arm GOOS=linux GOARM=5 $ -o $/$-$@
linux-armv6:
GOARCH=arm GOOS=linux GOARM=6 $ -o $/$-$@
linux-armv7:
GOARCH=arm GOOS=linux GOARM=7 $ -o $/$-$@
linux-armv8:
GOARCH=arm64 GOOS=linux $ -o $/$-$@
linux-mips-softfloat:
GOARCH=mips GOMIPS=softfloat GOOS=linux $ -o $/$-$@
linux-mips-hardfloat:
GOARCH=mips GOMIPS=hardfloat GOOS=linux $ -o $/$-$@
linux-mipsle-softfloat:
GOARCH=mipsle GOMIPS=softfloat GOOS=linux $ -o $/$-$@
linux-mipsle-hardfloat:
GOARCH=mipsle GOMIPS=hardfloat GOOS=linux $ -o $/$-$@
linux-mips64:
GOARCH=mips64 GOOS=linux $ -o $/$-$@
linux-mips64le:
GOARCH=mips64le GOOS=linux $ -o $/$-$@
freebsd-386:
GOARCH=386 GOOS=freebsd $ -o $/$-$@
freebsd-amd64:
GOARCH=amd64 GOOS=freebsd $ -o $/$-$@
windows-386:
GOARCH=386 GOOS=windows $ -o $/$-$@.exe
windows-amd64:
GOARCH=amd64 GOOS=windows $ -o $/$-$@.exe
gz_releases=zip_releases=$(gz_releases): %.gz : +x $/$-$ $@ -f -S -$.gz $/$-$ $@$(zip_releases): %.zip : -m -j $/$-$ $@-$.zip $/$-$ $@.exe
all-arch: releases: clean:
$/*
最后,我们直接用make命令传递参数,来编译我们的程序:
其中:
GOOS:目标平台的操作系统(darwin、freebsd、linux、windows)
GOARCH:目标平台的体系架构(386、amd64、arm)交叉编译不支持 CGO 所以要禁用它
当我们编译运行完成之后会发现在build目录下会生成我们所需要的不同平台下的可执行文件。最后我们需要注意,如果不想在生成完毕的文件名称中带上平台名称的后缀,那么需要在执行不同平台命令的后面去掉 "-$@"
相关配置信息。
后续还会继续在分享出来更多关于Go相关的文章内容,希望能与大家共同成长,一起进步。