dduo518 / hexo-blog

hexo静态blog点击 https://github.com/chong0808/hexo-blog/issues
3 stars 0 forks source link

golang 条件编译 #56

Open dduo518 opened 3 years ago

dduo518 commented 3 years ago

golang 条件编译

场景

压力测试环境需要增加Golang pprof 性能监测工具,但是pprof一般在生产环境是禁用的,这个时候需要根据环境来打包不同环境下的镜像,测试环境中需要pprof功能生产的镜像需要去掉pprof功能。

解决方案

由于在不同环境使用的镜像是不一样的,比如在测试环境使用的vX.Y.Z-beta.a,在正式环境使用的是vX.Y.Z版本的镜像,此时可以使用条件编译,分别在不同的环境编译不同的代码。 当我们编译go项目的时候可以根据go build -tags="${TAG}"命令,根据传入的tag 值决定使用哪个文件进行编译,只要在编译的时候不传入beta 作为tag参数。 example: main.go

func main(){
    // ...  
    go pprof.create(ctx)
    // ...
}

pprof_beta.go,测试环境使用xx_beta.go 文件的代码

// +build beta

package main

import (
    "context"
    "fmt"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "go.uber.org/zap"
    "net/http"
    _ "net/http/pprof"
)

func create(ctx context.Context) { 
    port := "6060"
    zap.L().Debug("create pprof server", zap.String("port", port))
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(fmt.Sprintf("0.0.0.0:%s", port), nil)
}

pprof_prd.go,生产环境使用xx_prd.go文件代码

// +build !beta

package main

import (
    "context"
    "go.uber.org/zap"
)

func create(ctx context.Context) {
    zap.L().Debug("prd env not create pprof server")
}

构建实现

由于是在git lab上进行构建,需要在gitlab-ci.yml文件中,通过环境变量拿到git tag获取到版本信息,然后在git lab 中将版本信息注入到build.sh脚本,然后在shell脚本中执行go build 构建。

build:app:
  before_script: 
    - VERSION=$(echo ${CI_COMMIT_TAG} | sed -e "s/^v//") # 获取版本信息
  script:
    - chmod +x ./build.sh && ./build.sh build ${VERSION}

build.sh中,拿到版本信息判断版本信息是否有beta,字符串,如果是包含beta,则在tags中加入 beta 字符

result=$(echo $2 | grep "beta") 
tag="release"
if [[ $result != "" ]] ; then 
  tag="release beta"
fi
go build -tags="$tag" -o=bin/cmd ./cmd
exit $? 

条件编译

golang支持两种条件编译方式

编译标签(build tag)

在源代码里添加标注,通常称之为编译标签( build tag),编译标签是在尽量靠近源代码文件顶部的地方用注释的方式添加

go build在构建一个包的时候会读取这个包里的每个源文件并且分析编译便签,这些标签决定了这个源文件是否参与本次编译 编译标签添加的规则: 1). 编译标签由空格分隔的编译选项(options)以"或"的逻辑关系组成

2). 每个编译选项由逗号分隔的条件项以逻辑"与"的关系组成

3). 每个条件项的名字用字母+数字表示,在前面加!表示否定的意思

例子(编译标签要放在源文件顶部)

// +build darwin freebsd netbsd openbsd 

这个将会让这个源文件只能在支持kqueue的BSD系统里编译

一个源文件里可以有多个编译标签,多个编译标签之间是逻辑"与"的关系

// +build linux darwin
// +build 386

这个将限制此源文件只能在 linux/386或者darwin/386平台下编译. 除了添加系统相关的tag,还可以自由添加自定义tag达到其它目的。 编译方法: 只需要在go build指令后用-tags指定编译条件即可

go build -tags mytag1 mytag2 

代码文件

// +build !mytag1 

package mypkg // 注意这里需要与编译条件空行

文件后缀

这个方法通过改变文件名的后缀来提供条件编译,这种方案比编译标签要简单,go/build可以在不读取源文件的情况下就可以决定哪些文件不需要参与编译。文件命名约定可以在go/build 包里找到详细的说明,简单来说如果你的源文件包含后缀:_GOOS.go,那么这个源文件只会在这个平台下编译,_GOARCH.go也是如此。这两个后缀可以结合在一起使用,但是要注意顺序:_GOOS_GOARCH.go, 不能反过来用:_GOARCH_GOOS.go.

例子如下:

mypkg_freebsd_arm.go // only builds on freebsd/arm systems
mypkg_plan9.go       // only builds on plan9

编译标签和文件后缀的选择

编译标签和文件后缀的功能上有重叠,例如一个文件名:mypkg_linux.go包含了// +build linux将会出现冗余

通常情况下,如果源文件与平台或者cpu架构完全匹配,那么用文件后缀,例如:

mypkg_linux.go         // only builds on linux systems
mypkg_windows_amd64.go // only builds on windows 64bit platforms

相反,如果满足以下任何条件,那么使用编译标签: