import "C"
接着上一期的内容,要使用 CGO 则需要编写导入伪包 "C"
的 Go 语言代码,在 Go 语言中出现 import "C"
语句即表明使用了 CGO ,在这个导入语句之前的注释就是一种特殊的代码块,里面就是 C 语言的代码,这个注释我们一般称为 前导 。所以, import "C"
语句实际上就是导入 C 伪包,并且 C 伪包的代码就是该语句上方注释里的 C 代码。
通过使用 import "C"
语句,我们就能在 Go 语言代码中引用像 C.size_t
的类型、或者 C.stdout
之类的变量、或者 C.putchar
之类的函数。
例如前面几期经常提到的这个例子:
通过前面几期的介绍,相信你也一定知道前导可以包含任何的 C 代码,包括函数以及变量的声明和定义,你可以在 Go 代码中引用它们。但是注意一点,前导中的静态变量可能不被 Go 代码引用。
#cgo
在前导中可以通过使用 #cgo
语句设置编译阶段和链接阶段的相关参数。例如以下的几个指令:CFLAGS
、 CPPFLAGS
、 CXXFLAGS
、 FFLAGS
、 LDFLAGS
。
这些指令可以包含一个构建的约束列表,限制其对满足其中一个约束的系统的影响,编译阶段的参数主要用于定义相关宏和指定头文件检索路径。链接阶段的参数主要是指定库文件检索路径和要链接的库文件。例如:
或者, CPPFLAGS
和 LDFLAGS
可以通过 pkg-config
工具使用 #cgo pkg-config:
指令后跟包名称来获得。例如:
可以通过设置 PKG_CONFIG
环境变量来更改默认的 pkg-config
工具。
出于安全原因,只允许使用一组有限的标志,特别是 -D
、 -U
、 -I
和 -l
。要允许附加标志,要将 CGO_CFLAGS_ALLOW
设置为匹配新标志的正则表达式。要禁止原本允许的标志,要将 CGO_CFLAGS_DISALLOW
设置为匹配必须禁止的参数的正则表达式。
同样出于安全原因,只允许使用有限的字符集,尤其是一些符号,例如 .
,它们可能会以其他方式解释。使用禁止字符会报 malformed #cgo argument
错误。
解析 CGO 指令时,如果出现字符串 ${SRCDIR}
,它们都将替换为包含源文件目录的绝对路径。这允许将预编译的静态库包含在包目录中并正确的链接。例如,如果包 foo
在目录 /go/src/foo
中:
将扩展为:
参考文献:
[1] 柴树杉;曹春晖, Go 语言高级编程, 北京: 人民邮电出版社, 2019.
[2] https://pkg.go.dev/cmd/cgo