mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-24 12:32:21 +00:00
ch2-06: 完善部分内容
This commit is contained in:
parent
8c37cef838
commit
ee5715778e
@ -15,7 +15,7 @@
|
|||||||
* [2.3. CGO编程基础](ch2-cgo/ch2-03-basic.md)
|
* [2.3. CGO编程基础](ch2-cgo/ch2-03-basic.md)
|
||||||
* [2.4. CGO内存模型](ch2-cgo/ch2-04-memory.md)
|
* [2.4. CGO内存模型](ch2-cgo/ch2-04-memory.md)
|
||||||
* [2.5. C++类包装](ch2-cgo/ch2-05-class.md)
|
* [2.5. C++类包装](ch2-cgo/ch2-05-class.md)
|
||||||
* [2.6. CGO包的可移植性(TODO)](ch2-cgo/ch2-06-go-get-friendly.md)
|
* [2.6. CGO包的组织(Doing)](ch2-cgo/ch2-06-go-get-friendly.md)
|
||||||
* [2.7. Go实现Python模块(TODO)](ch2-cgo/ch2-07-py-module.md)
|
* [2.7. Go实现Python模块(TODO)](ch2-cgo/ch2-07-py-module.md)
|
||||||
* [2.8. SWIG(TODO)](ch2-cgo/ch2-08-swig.md)
|
* [2.8. SWIG(TODO)](ch2-cgo/ch2-08-swig.md)
|
||||||
* [2.9. 补充说明(TODO)](ch2-cgo/ch2-09-faq.md)
|
* [2.9. 补充说明(TODO)](ch2-cgo/ch2-09-faq.md)
|
||||||
|
@ -1,4 +1,66 @@
|
|||||||
# 2.6. CGO包的可移植性(TODO)
|
# 2.6. CGO包的组织(Doing)
|
||||||
|
|
||||||
|
凡事都有两面性,CGO虽然是继承了C/C++庞大的生态资源,同时也带来了C/C++语言的诸多问题。第一个遇到的重要问题是如何打包CGO中对用到的C/C++库或代码的依赖。很多用户对Go语言的第一映像是构建和运行都非常快速,甚至可以当中一个脚本语言来使用。但是这种映像的前提是程序要能够正常构建,如何正确构建一个使用了CGO特性的Go语言包对很多用户是一个挑战。
|
||||||
|
|
||||||
|
## 常见的C和C++编译问题
|
||||||
|
|
||||||
|
在真实世界中C/C++一般是混合存在的。编译这类C/C++混合代码遇到的问题也是CGO经常需要解决的问题。混合C/C++代码的构建和组织的有两个原则:一是C/C++头文件最小化;二是C/C++编译参数和头文件分离。
|
||||||
|
|
||||||
|
原本的C语言世界是简单的,头文件也是简单的。当C++引入了函数重载(一个函数名有多个实现)后头文件也变得复杂起来。主要的原因是C++为了支持多个有着不同参数类型的同名函数,在生成目标文件时要对应不同的链接符号。简言之,C++中在编译阶段默认采用和C语言不同的名字修饰规则,同时支持C语言采用的名字修饰规则。
|
||||||
|
|
||||||
|
因为cgo只支持C语言语法,因此cgo也只能包含C语言的头文件。如果这个C语言头文件没有针对C++做过特殊的处理,那么在被其它的C++代码包含时需要放到`extern "C" { ... }`括号中(这是C++针对兼容C语言而增加的语法)。
|
||||||
|
|
||||||
|
编译C/C++源文件时,`.c`后缀名的对应是C语言代码,其它的一般是C++代码。C和C++代码编译时有着不同的编译选项,在`#cgo`指令中,CFLAGS对应C语言的编译选项,CPPFLAGS对应C和C++共有的编译选项,CXXFLAGS则对于C++特有的编译参数。C/C++源文件编译后成为一个个目标文件,C/C++的目标文件没有区别,共同使用LDFALAGS表示链接选项。
|
||||||
|
|
||||||
|
需要说明的是,如果C++代码中使用了C++11或更新的特性,需要在C++编译选项中指明,否则会导致编译错误。
|
||||||
|
|
||||||
|
<!-- 组织一个例子 -->
|
||||||
|
|
||||||
|
## 依赖二进制库
|
||||||
|
|
||||||
|
最简单的CGO程序是没有任何的依赖,仅仅只是通过`import "C"`语句表示启用CGO特性:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// hello.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("hello cgo")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这种程序最为简单,而且又是单个文件,我们可以通过`go run hello.go`命令来直接运行。但是这个程序虽然简单,但是依然会出发cgo命令行工具,依然会触发C语言代码的编译链接的过程。最终我们的得到的可执行程序会依赖一个底层的运行时库。
|
||||||
|
|
||||||
|
在不同的操作系统下看可执行程序有哪些依赖有着不同的工具。Linux系统是ldd命令,macOS系统是otool命令,Windows下则有带节目的Depends依赖检查工具。下面是这个例子在macOS系统下默认生成的可执行程序的依赖:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go build -o a.out
|
||||||
|
$ otool -L a.out
|
||||||
|
a.out:
|
||||||
|
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
|
||||||
|
```
|
||||||
|
|
||||||
|
对于macOS系统,`libSystem.B.dylib`一般会包含C语言运行时库的实现。对于Linux和Windows环境应该有类似的C语言运行时库。当然普通用户很少需要关心这些细节。
|
||||||
|
|
||||||
|
但是随着Docker等容器技术的流行,如何打包一个最小化Go写的程序容器成了某些用户的追求。Go语言之所以会随着容器技术会大势流行,这是一个非常重要的因素:我们甚至在没有C语言运行时库的环境正常运行Go语言写的程序。下面是在Linux环境打包静态库版本的C语言运行时库:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go build --ldflags '-w -s -extldflags "-static"' hello.go
|
||||||
|
```
|
||||||
|
|
||||||
|
如果现在再用Linux的ldd命令查看将不会有任何的依赖,这是一个绝对绿色的程序。
|
||||||
|
|
||||||
|
更实用的CGO包一般会依赖第三方的C/C++库。如果本地操作系统中已经安装了依赖的第三方库,那么这种情况就和依赖标准的C/C++库差不多了。但是在发布时,需要确保运行程序的目标系统也包含一致的第三方C/C++共享库。
|
||||||
|
|
||||||
|
需要注意的是,释放采用静态库版本的C/C++运行时库是最终构建用户的选择,每个cgo包本书不应该过多设置最终的构建选项(因为这可能导致不同cgo包之间的链接参数的冲突)。
|
||||||
|
|
||||||
|
<!-- pkg-config 自定义的命令 -->
|
||||||
|
|
||||||
|
## 同时打包C源码
|
||||||
|
|
||||||
|
## 打包巨量C源码的问题
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
|
@ -5,5 +5,7 @@ TODO
|
|||||||
<!--
|
<!--
|
||||||
静态库和动态库
|
静态库和动态库
|
||||||
|
|
||||||
|
导出C接口分布在不同的钩包
|
||||||
|
|
||||||
实战: py 模块
|
实战: py 模块
|
||||||
-->
|
-->
|
||||||
|
7
examples/ch2-06/hello-01/hello.go
Normal file
7
examples/ch2-06/hello-01/hello.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("hello cgo")
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user