GO条件编译
go build 参数
附加参数 | 备注 |
---|---|
-v | 编译时显示包名 |
-p n | 开启并发编译,默认情况下为CPU核数 |
-a | 强制重新构建所有的文件 |
-n | 打印编译时会用的所有命令,但不真正执行 |
-x | 打印编译时会用到的所有命令 |
-race | 开启竞态检测,支持linux/amd64,freebsd/amd64,darwin/amd64,windows/amd64 |
-work | 打印临时工作目录的名称 |
-o | 指定输出文件 |
-tags | 构建出带tag的版本 |
-gccgoflags | gccgo 编译/链接器参数(少用) |
条件编译方式一:编译标签
在源码添加标注,通常称之为编译标签(build tag),编译标签是在尽量靠近源代码文件顶部的地方用注释的方式添加,如下所示:
// +build darwin freebsd netbsd openbsd
这个将会让这个源文件只能在支持kqueue的BSD系统中编译
-
一个源文件可以有多个编译标签,多个编译标签之间是逻辑"与"的关系
// +build linux darwin // +build 386
这个将限制此源文件只能在Linux/386或者darwin/386平台下编译
-
关于注释的说明:
编译标签和包的声明一定要用空行隔开,如下为***错误示范***
// +build !linux package main // <- it's wrong
下面这个才是正确示范:
// +build !linux package main // <- it's right
可以用
go vet
命令来检测这个缺少空行的错误
条件编译方式二:文件后缀
这个方法通过改变文件名的后缀来提供条件编译,这种方案比编译标签要简单, go/build可以在不读取源文件的情况下就可以决定哪些文件不需要参与编译
-
文件命名约定:
- 编译平台约束:源文件后缀包括:
_$GOOS.go
- 编译CPU架构约束:源文件后缀包括:
_$GOARCH.go
这两个后缀可以结合在一起使用,但要注意顺序:
_$GOOS_$GOARCH.go
- 编译平台约束:源文件后缀包括:
编译标签和文件后缀的选择
- 通常情况来讲,如果源文件与平台或者CPU架构完全匹配,那么用文件后缀
- 相反,如果这个源文件可以在超过一个平台/CPU架构下使用,或者去除指定平台,那么使用编译标签
CGO条件编译
CGO也可以使用上述GO的条件编译方式来进行条件编译。这里只针对与对于跨平台情况下需要链接不同的库的注释写法:
条件链接依赖库
先来看一段正常的cgo代码:
// #cgo CFLAGS: -DPNG_DEBUG=1 -I./include
// #cgo LDFLAGS: -L/usr/local/lib -lpng
// #include <png.h>
import "C"
#cgo
语句
在import "C"语句前的注释中可以通过#cgo
语句设置编译阶段和链接阶段的相关参数。编译阶段的参数主要用于定义相关宏和指定头文件检索路径。链接阶段的参数主要是指定库文件检索路径和要链接的库文件
#cgo
语句主要影响CFLAGS
、CPPFLAGS
、CXXFLAGS
、FFLAGS
和LDFLAGS
几个编译器环境变量。LDFLAGS
用于设置链接时的参数,除此之外的几个变量用于改变编译阶段的构建参数(CFLAGS
用于针对C语言代码设置编译参数)
条件选择
#cgo
指令还支持条件选择,当满足某个操作系统或某个CPU架构类型时后面的编译或链接选项生效。比如下面是分别针对windows和非windows下平台的编译和链接选项
// #cgo windows CFLAGS: -DX86=1
// #cgo !windows LDFLAGS: -lm
// #cgo amd64 CFLAGS: -lpthread
// #cgo arm64 CFLAGS: -lpng
如上就是在不同操作系统预定义宏,链接不同库的操作。
如果在不同的系统下cgo对应着不同的c代码,我们可以先使用#cgo
指令定义不同的C语言的宏,然后通过宏来区分不同的代码:
package main
/*
#cgo windows CFLAGS: -DCGO_OS_WINDOWS=1
#cgo darwin CFLAGS: -DCGO_OS_DARWIN=1
#cgo linux CFLAGS: -DCGO_OS_LINUX=1
#if defined(CGO_OS_WINDOWS)
const char* os = "windows";
#elif defined(CGO_OS_DARWIN)
const char* os = "darwin";
#elif defined(CGO_OS_LINUX)
const char* os = "linux";
#else
# error(unknown os)
#endif
*/
import "C"
func main() {
print(C.GoString(C.os))
}