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

ch2-06: 完善部分内容

This commit is contained in:
chai2010 2018-01-11 02:49:12 +08:00
parent c5c995c72b
commit 8786e6fe07

View File

@ -75,9 +75,67 @@ func main() {
## 使用C动态库
好处是跨编译器
坏处是多了一个依赖
动态库出现的初衷是对于相同的库多个进程可以共享一个动态库可以节省内存和磁盘资源。但是在磁盘和内存已经白菜价的今天动态库能节省的空间已经微不足道了那么动态库还有哪些存在的价值呢从库开发角度来说动态库可以隔离不同动态库之间的关系减少链接时出现符号冲突的风险。而且对于windows等平台动态库是跨越VC和GCC不太编译器平台的唯一的可行方式。
对于CGO来说使用动态库和静态库是一样的因为动态库也必须要有一个小的静态导出库用于链接动态库Linux下可以直接链接so文件但是在Windows下必须为dll创建一个`.a`文件用于链接。我们还是以前面的number库为例来说明如何以动态库方式使用。
对于在macOS和Linux系统下的gcc环境我们可以用以下命令创建number库的的动态库
```
$ cd number
$ gcc -shared -o libnumber.so number.c
```
因为动态库和静态库的基础名称都是libnumber只是后缀名不同而已。因此Go语言部分的代码和静态库版本完全一样
```go
package main
//#cgo CFLAGS: -I./number
//#cgo LDFLAGS: -L${SRCDIR}/number -lnumber
//
//#include "number.h"
import "C"
import "fmt"
func main() {
fmt.Println(C.number_add_mod(10, 5, 12))
}
```
编译时GCC会自动找到libnumber.a或libnumber.so进行链接。
对于windows平台我们还可以用VC工具来生成动态库windows下有一些复杂的C++库只能用VC构建。我们需要先为number.dll创建一个def文件用于控制要导出到动态库的符号。
number.def文件的内容如下
```
LIBRARY number.dll
EXPORTS
number_add_mod
```
其中第一行的LIBRARY指明动态库的文件名然后的EXPORTS语句之后是要导出的符号名列表。
现在我们可以用以下命令来创建动态库需要进入VC对于的x64命令行环境
```
$ cl /c number.c
$ link /DLL /OUT:number.dll number.obj number.def
```
这时候会为dll同时生成一个number.lib的导出库。但是在CGO中我们无法使用lib格式的链接库。
要生成`.a`格式的导出库需要通过mingw工具箱中的dlltool命令完成
```
$ dlltool -dllname number.dll --def number.def --output-lib libnumber.a
```
生成了libnumber.a文件之后就可以通过`-lnumber`链接参数进行链接了。
需要注意的是在运行时需要将动态库放到系统能够找到的位置。对于windows来说可以将动态库和可执行程序放到同一个目录或者将动态库所在的目录绝对路径添加到PATH环境变量中。对于macOS来说需要设置DYLD_LIBRARY_PATH环境变量。而对于Linux系统来说需要设置LD_LIBRARY_PATH环境变量。
## 导出C静态库