交叉编译条件编译
GolangGolang条件编译交叉编译
这两者虽然都是为了解决跨平台问题而产生的工具,但他们针对的问题却并不冲突,我们可以在项目中仅使用其中一种或是一起使用都是可以的。
2. 两者分别解决了什么问题?
- 交叉编译,帮助我们在一台任意操作系统的机器上,编译出不同系统的目标程序,主要解决了跨平台编译的问题。
- 条件编译,申明指定代码文件只能在对应平台上编译,解决了代码兼容性 的问题。
接下来我们就来讲讲这两个编译工具是怎么使用的。
3. 交叉编译的用法
交叉编译解决目标程序问题,即在一台具体的系统环境下编译出不同系统或不同语言环境的目标程序;由于交叉编译日常工作中大家也许都用过,理解起来也比较简单,我这儿直接提供了一些常用平台的编译命令,后面我们还是主要介绍下条件编译:
Mac 下编译 Linux 和 Windows 64位可执行程序
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
Linux 下编译 Mac 和 Windows 64位可执行程序
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
Windows 下编译 Mac 和 Linux 64位可执行程序
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build main.go
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build main.go
不带前面参数的 go build 只是编译出开发环境适用的执行文件。
当然交叉编译不仅仅是可以根据目的操作系统进行编译,还可以区分系统的CPU架构类型,以及不同的语言版本,甚至可以指定用户自定义的编译标签,按自定义的方式编译目标程序。
更复杂的交叉编译参数如下:
$: GOOS=${GOOS} GOARCH=${GOARCH} go build -tags ...
4. 条件编译的用法
go listgo list
如下例子,可以得到所有将被编译的源码文件名。
C:\go> go list -f '{{.GoFiles}}' os/exec
[exec.go exec_windows.go lp_windows.go]
但如果在mac或linux下执行上面那个命令,结果如下:
~ go list -f '{{.GoFiles}}' os/exec
[exec.go exec_unix.go lp_unix.go]
exec.golp_unix.gounixexec.LookPath
/usr/local/go/src/os/exec/exec_unix.go
// +build !plan9,!windows
package exec
...
从上面的例子中我们发现了两处特殊的地方
xxx_unix.goxxx_windows.go// +build !plan9,!windows
这其实就是条件编译的的两种方式构建标签与文件名后缀
构建标签(Build tags)
第一种实现条件编译的方法是在源码中插入注释,被称之为构建标签。
构建标签的注释应该尽可能的接近源码文件的顶部位置。
当Go编译一个包时,它会分析包内的每个源码文件并查找构建标签。标签决定了这个源码文件是否被编译。
构建标签遵循以下三个原则:
!
// +build darwin freebsd netbsd openbsd
kqueue
linux/386darwin/386
// +build linux darwin
// +build 386
package main
文件名后缀(File suffixes)
第二种条件编译的方法是通过源码文件的文件名实现的。这种方案比构造标签方案更简单。
go/build_$GOOS.go_$GOARCH.go_$GOOS_$GOARCH.go_$GOARCH_$GOOS.go
以下是文件名后缀的一些例子:
mypkg_freebsd_arm.go // 只在 freebsd/arm 系统编译
mypkg_plan9.go // 只在 plan9 编译
源码文件光有后缀是不够的,比如如下文件名:
_linux.go
_freebsd_386.go
go/build._
使用构建标签还是文件名后缀
mypkg_linux.go// +build linux
通常来说,当只有一个特定平台或体系需要指定时,我们选择文件名后缀的方式。比如:
mypkg_linux.go // 只在 linux 系统编译
mypkg_windows_amd64.go // 只在 windows amd 64位 平台编译
相反,如果你的文件需要指定给多个平台或体系使用,或者你需要排除某个特定平台时,我们选择构建标签的方式。比如:
// 在所有类unix平台编译
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go
// +build darwin dragonfly freebsd linux netbsd openbsd
// 在非Windows平台编译
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go
// +build !windows
总结
.go.c.sGoruntimesyscallosnet
测试文件也支持构建标签和文件名后缀,它们的表现和Go源码文件表现一致。从而允许我们为特定平台指定特定测试用例。
参考文章
- https://dave.cheney.net/2013/10/12/how-to-use-conditional-compilation-with-the-go-build-tool
- https://juejin.im/post/5d21ff42e51d457778117407
长按关注,订阅更多优质内容哦~