总有那么一些老的,或高效的库是用 C/C++ 实现的,于是在其他语言中如果使用动态共享库就成了个问题。Java 要调用动态库需要用 JNI, 更快捷的话可使用第三方包装好的 JNI 调用库。在 Java 中要映射 C/C++ 的类型麻烦些,因为 Java 没有指针类型,所以从这方面来讲 Go 调用动态库幸许会更简单些。

下面我们自己在 Linux 下做一个动态库(.so 文件  - Shared Object),然在用 Go 来使用它。本文所用的操作系统为 Ubuntu20.04, 以 gcc  作为编译器。动态库的生成过程参考自 Linux动态库生成与使用指南

add.h
add.c
libadd.so

$ gcc -fPIC -shared -o libadd.so add.c

libadd.sonm -D libadd.so
test.c

链接动态库生成可执行文件

$ gcc test.c -L . -ladd -o test

-L .-laddlibadd.so-o testtest
test
libadd.sotest

$ ./test
./test: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory

libadd.soldconfigLD_LIBRARY_PATH

$ LD_LIBRARY_PATH=. ./test
giter8

libadd.sotest

以下是成功的例子,测试完之后发现很简单,可是过程中碰到许多的问题。后面会列出所遇到见的问题

假设项目目录为 /home/vagrant/testgo (用的 Vagrant 启动的 Ubuntu 20.04 进行本文中的测试),目录结构如下

testgo
├── lib
│     └── libadd.so
└── src
        ├── add.h
        └── main.go

main.go 的代码如下:

#cgo CFLAGS: -I.

CFLAGS: -I 和 LDFLAGS: -L 都是相对于源文件 main.go 的位置

/home/vagrant/testgo

~/testgo$ go run src/main.go
Hello c value: go2021

成功调用 C 实现的 add 函数

下面列出一些问题

import "C"/*...*/

/*
#cgo ...
*/

import "C"

会出现错误

# command-line-arguments
src/main.go:15:10: could not determine kind of name for C.add

import "C"import ("C"; "fmt")
C.Add()

# command-line-arguments
src/main.go:13:10: could not determine kind of name for C.Add

还有一个关键是能否加载到动态库 libadd.so, 参考了网上一些例子,如果把第五行改为

#cgo LDFLAGS: -L../lib -ladd

执行时会出错

/tmp/go-build3845117109/b001/exe/main: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
exit status 127

但如果设置了环境变量 LD_LIBRARY_PATH=/home/vagrant/testgo/lib 也能让它跑起来

LD_LIBRARY_PATH=/home/vagrant/testgo/lib go run src/main.go
Hello c value: go2021

链接: