总有那么一些老的,或高效的库是用 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
链接: