Go服务跨平台交叉编译打包与设置版本号


前言

最近在负责维护和开发守护进程、运营平台监控、连接池等相关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命令传递参数,来编译我们的程序:
golang makeFile运行示例
其中:

GOOS:目标平台的操作系统(darwin、freebsd、linux、windows)
GOARCH:目标平台的体系架构(386、amd64、arm)交叉编译不支持 CGO 所以要禁用它

当我们编译运行完成之后会发现在build目录下会生成我们所需要的不同平台下的可执行文件。最后我们需要注意,如果不想在生成完毕的文件名称中带上平台名称的后缀,那么需要在执行不同平台命令的后面去掉 "-$@" 相关配置信息。
后续还会继续在分享出来更多关于Go相关的文章内容,希望能与大家共同成长,一起进步。


文章作者: 小张哥
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小张哥 !
评论
 上一篇
io模型的演进 io模型的演进
学习三大要素 what、why、how,每天给自己强调一遍 1:什么是IO程序是由数据+指令构成的,运行程序的过程可以分成下面这几步:将代码加载到内存中,逐条运行内存中的代码在运行代码的过程中,可能需要对文件的读写,即将文件输入(Inp
下一篇 
java8新特性原理以及实战应用-lambda函数式编程与日期篇 java8新特性原理以及实战应用-lambda函数式编程与日期篇
1:简介目前截止2021年9月java最新的jdk版本为17,而我们目前大部分公司现在的java项目都还在运行的是java8的版本,对于我们目前的项目而言,java8已经能够满足我们大部分工作中的应用场景。而且截止目前为止oracle公司还
  目录