Go语言调用C语言代码
Go 语言除了语法精炼、并发支持好外,还有一个优点就是可以调用 C 代码。可以直接在 Go 源代码里写 C 代码,也可以引 C 语言的外部库。这样在性能遇到瓶颈的地方可以重写,或者某些功能 Go 和第三方还缺失,但 C 语言有现成的库就可以直接用了。官方 Cgo 这块目前有一篇博客 https://blog.golang.org/c-go-cgo 和 命令行文档 https://golang.org/cmd/cgo/ 对 Cgo 进行了说明,其中某些地方还不够明确或者没有提到的地方。
Section1:Go语言内联C语言代码
下面例子是直接将 C 代码内嵌在 Go 源代码里,引入了一个不存在的包 “C”, 然后将 C 代码写在了引入上面,注意只能写在 “C” 包上面。这里定义了一个sum函数, 然后通过 C.sum 在 Go 代码里使用。
|
|
运行一下这个简单的程序,会得到如下执行结果:
|
|
Section2:Go语言调用独立的C语言源代码
小巧的 C 语言代码可以方便的通过内联使用,但是代码比较庞大的话可以将 C 语言代码独立编码为包。下面将上面内嵌的C语言代码定义为相应的源文件,当前目录如下:
|
|
C语言simple_sum.h头文件
simple_sum.h文件,具体代码如下:
|
|
C语言simple_sum.c源文件
simple_sum.c文件,具体代码如下:
|
|
Go语言main.go源文件
main.go文件,具体代码如下:
|
|
当前示例将 Section1:Go语言内联C语言代码
部分中内嵌C语言代码,拆分为独立的C语言文件 simple_sum.h
和 simple_sum.c
。Go语言源文件代码只需要将 simple_sum.h
头文件引入,即可调用C语言定义的 sum
函数。需要注意的是,main包引用多个文件后就不能再直接使用go run命令直接运行了,需要使用go build命令先对其编译,然后通过执行编译后的可执行文件来运行。go build会检测cgo引用的文件,以 .h
和 .c
为扩展名的C语言源文件也会一起被编译。
|
|
Section3:Go语言调用C语言外部库
将 Section2:Go语言调用独立的C语言源代码
部分的C语言源代码重新组织为C语言功能库,具体目录结构如下:
|
|
其中simple目录就一个整合后的C语言外部库,C语言simple/sum.h、simple/sum.c源文件分别对应 Section2:Go语言调用独立的C语言源代码
部分中的 simple_sum.h
、simple_sum.c
源文件,代码和之前一样,只是整合到了simple目录,目的是强制让Go语言不编译它。
假定simple目录就是Go程序需要用到的C语言外部库,先编译静态库,在simple目录下生成libsimplesum.a
静态链接库文件。
编译C语言外部库simple
。
|
|
生成C语言动态链接库。
|
|
生成静态链接库后的目录结构如下:
|
|
具体的main.go文件,如下所示:
|
|
执行go build编译这个example程序:
|
|
调用外部库需要用到 #cgo
伪指令,他可以指定编译和链接参数,如 CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS。CFLAGSS可以配置C语言编译器参数,其中 -I
可以指定头文件目录,例如 -I/path/to/include
。LDFLAGS 可以配置引用库的参数,其中 -L
指定引用库的目录,-l
指定库名称。如果引用的头文件或者库在系统默认的目录下(例如 /usr/include, /usr/local/include 和 /usr/lib, /usr/local/lib)则可以不用指定目录。
#cgo
指令中可以添加限制平台的参数,例如只针对 linux 或者 darwin 平台,详情参考 https://golang.org/pkg/go/build/#hdr-Build_Constraints 。同时可以使用${SRCDIR}
代替源代码目录。
|
|