1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 04:22:22 +00:00

ch2-03: 初步完稿, 细节以后再完善

This commit is contained in:
chai2010 2018-01-03 22:02:21 +08:00
parent 25e5062c19
commit a899d2846f
2 changed files with 64 additions and 9 deletions

View File

@ -12,7 +12,7 @@
* [第二章 CGO编程](ch2-cgo/readme.md)
* [2.1. 你好, CGO!](ch2-cgo/ch2-01-hello-cgo.md)
* [2.2. 基础类型转换](ch2-cgo/ch2-02-cgo-types.md)
* [2.3. CGO编程基础(TODO)](ch2-cgo/ch2-03-basic.md)
* [2.3. CGO编程基础](ch2-cgo/ch2-03-basic.md)
* [2.4. CGO内存模型(TODO)](ch2-cgo/ch2-04-memory.md)
* [2.5. C++类包装(TODO)](ch2-cgo/ch2-05-class.md)
* [2.6. 命令行工具和构建参数(TODO)](ch2-cgo/ch2-06-build.md)

View File

@ -1,4 +1,4 @@
# 2.3. CGO编程基础(TODO)
# 2.3. CGO编程基础
Go是一门以实用为主要目的的编程语言我们可以通过cgo来直接调用C语言代码也可以在C语言代码中直接调用Go函数。要使用CGO特性需要安装CC++构建工具链在macOS和Linux下是要安装和GCC在windows下是需要安装MinGW工具。同时需要保证环境变量`CGO_ENABLED`被设置为1这表示CGO是被启用的状态。在本地构建时`CGO_ENABLED`默认是启用的当交叉构建时CGO默认是禁止的。比如要交叉构建ARM环境运行的Go程序需要手工设置好C/C++交叉构建的工具链,同时开启`CGO_ENABLED`环境变量。
@ -101,16 +101,71 @@ import "C"
对于在cgo环境混合使用C和C++的用户来说可能有三种不同的编译选项其中CFLAGS对应C语言特有的编译选项、CXXFLAGS对应是C++特有的编译选项、CPPFLAGS则对应C和C++共有的便于选项。但是在链接阶段C和C++的链接选项是通用因此这个时候已经不在有C和C++语言的区别,它们都是相同的类型的目标文件。
如果是针对特定平台的参数可以通过Go语言的build tag来指定
`#cgo`指令还支持条件选择当满足某个操作系统或某个CPU架构类型时后面的编译或链接选项生效。比如下面是分别针对windows和非windows下平台的编译和链接选项
```
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo windows CFLAGS: -DX86=1
// #cgo !windows LDFLAGS: -lm
```
TODO
其中在windows平台下编译前会预定义X86宏为1再非widnows平台下再链接阶段会要求链math数学库。这种用法对应在不太平台下只有少数编译选项差异的场景比较适用。
<!--
文件后缀名和 cgo 指令的对应关系
如果是在不同的系统下cgo对应者不同的c代码我们可以通过在`#cgo`指令定义不同的宏然后通过C语言的宏来区分不同的代码
自定义的 build 类型不是cgo特有的
-->
```go
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)
static char* os = "windows";
#elif defined(CGO_OS_DARWIN)
static char* os = "darwin";
#elif defined(CGO_OS_LINUX)
static char* os = "linux";
#else
# error(unknown os)
#endif
*/
import "C"
func main() {
print(C.GoString(C.os))
}
```
这样我们就可以用C语言中常用的技术来处理不同平台之间的差异代码。
## build tag 条件编译
build tag 是在Go或cgo环境下的C/C++文件开头的一种特殊的注释。条件编译类似签名的`#cgo`指令针对不同平台定义的宏,只有在对应平台的宏被定义之后才会构建对应的代码。但是通过`#cgo`指令定义宏有个限制它只能是基于Go语言支持的windows、darwin和linux等已经支持的操作系统。如果我们希望定义一个DEBUG标志的宏`#cgo`指令就无能为力了。而Go语言提供的build tag 条件编译特性则可以简单做到。
比如下面的源文件只有在设置debug构建标志时才会被构建
```go
// +build debug
package main
var buildMode = "debug"
```
可以用以下命令构建:
```
go build -tags="debug"
go build -tags="windows,debug"
```
我们可以通过`-tags`命令行参数同时指定多个build标志它们之间用逗号分割。
当有多个build tag时我们将多个标志通过与或的规则来组合使用。比如以下的构建标志表示只有在linux/386或非cgo环境的darwin平台下才进行构建。
```go
// +build linux,386 darwin,!cgo
```
其中`linux,386`中linux和386用逗号链接表示AND的意思`linux,386``darwin,!cgo`之间通过空白分割表示OR的意思。