源码先锋

源码先锋

Go 编程:交叉编译 vs 条件编译

admin 122 191

说起条件编译,大部分开发人员都会联想到交叉编译。但是条件编译和交叉编译完全是两回事,解决的问题也是不一样的。总结区分一下:

交叉编译,解决的是目标程序问题,是目的。

条件编译,解决的是代码适配问题,是过程。

交叉编译

交叉编译解决目标程序问题,即在一台具体的系统环境下编译出不同系统或不同语言环境的目标程序。举个简单的例子,在一台任意操作系统的机器上,编译出不同系统的目标程序:

以平台darwin作为目标编译平台$:GOOS=darwingobuildlinux$:GOOS=linuxgolist-f'{{.GoFiles}}'os/exec[__]windows$:GOOS=windowsgolist-f'{{.GoFiles}}'os/exec[__]

可以看出,这个命令能够快速回答我们按当前的目标平台编译时,编译所需要的代码文件。有了这个利器,就可以很方便的开始条件编译的话题了。

条件编译

条件编译解决的是一份代码在不同的编译平台以及不同的语言版本的兼容性问题,即一份代码处处都可以编译。Go语言中的条件编译的方式,可直接官方提供的文档:BuildConstraints.总结下来就是两种方式:

文件名后缀方式

gobuild在不读取源文件的情况下可以通过文件名后缀以决定哪些文件参与编译,哪些不需要。文件名后缀的形式,主要有:

_$

_$

_$GOOS_$

最后一种组合后缀,顺序不能颠倒。

编译标签标注方式

更加灵活的条件编译方式,是通过在文件头增加条件编译标签。条件标签在使用上需要和常规注释进行区分。

条件编译标签的格式://+build前缀开始,条件编译标签必须和普通的注释以及代码通过空行分隔开来。否则,编译器就无法认出。

条件编译具体条件组合的规则,总结出来就是:

空格''=OR逗号','=AND感叹号'!'=NOT换行=OR

官网例子:

//+buildlinux,386darwin,!cgo

条件编译组合结果是:(linuxAND386)OR(darwinAND(NOTcgo))

//+buildlinuxdarwin//+build386

条件编译组合结果是:(linuxORdarwin)AND386

具体条件则可以有:

操作系统,值可以通过获取

CPU架构,值可以通过获取

编译器,如gc,gccgo

是否开启Cgo,cgo

语言版本,Go版本如,,

自定义标签,任意标签,可以是发布版本号,开发版本等等

现实问题

不论是交叉编译还是条件编译,终归是为了解决问题。交叉编译解决发布问题,条件编译解决代码问题。两种都很重要,此节仅就代码问题进行说明,即如何保证一份代码在不同编译条件下能够通用。

其实这是一个编程领域的经典问题,即多态。既然是多态问题,就可以通过常说的OOP中的多态来实现,即对多态进行抽象,再进行具体实现。

看一个例子pkg/profile:

在代码实现中有两个trace实现文件,分别是:与其中用到了runtime/trace包,而该包是在版本中新引入的。所以作者定义了一个统一的抽象函数,具体实现则通过条件编译,在不同的版本中提供具体的实现。对以下的版本则采用空实现的方式。

贴一下代码看看,针对版本以及后续版本的实现:

//+"runtime/trace"varstartTrace==

再看看的实现:

//+build!"io"//()error{returnnil}funcstopTrace(){}

问题怎么解决的,应该不用解释了。

原文: