下面我们自己在 Linux 下做一个动态库(.so 文件 - Shared Object),然在用 Go 来使用它。本文所用的操作系统为 Ubuntu18.04, 以 gcc 作为编译器。
1.实现头文件,声明文件中函数。这里创建一个add.h文件。
#ifndef __ADD_H__
#define __ADD_H__
char* Add(char* src, int n);
#endif
2.实现add主体函数add.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char* Add(char* src, int n)
{
char str[20];
sprintf(str, "%d", n);
char *result = malloc(strlen(src)+strlen(str)+1);
strcpy(result, src);
strcat(result, str);
return result;
}
3.用命令生成动态库,在linux下文件名称是libadd.so
gcc -fPIC -shared -o lib/libadd.so include/add.c
libadd.sonm -D libadd.so
4.编写一个库来测试一下
#include <stdio.h>
#include "add.h"
int main(int argc, char *argv[])
{
char* aa = "giter";
printf("%s\n", Add(aa, 8));
return 0;
}
链接动态库生成可执行文件
gcc include/test.c -L lib/ -ladd -o test
-L .-laddlibadd.so-o testtest
错误:运行出错的情况
# 运行 ./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=lib/ ./test
giter8
libadd.sotest
5.golang调用c动态库
demo1
├── include
│ └── add.c
│ └── add.h
│ └── test.c
├── lib
│ └── libadd.so
└── main.go
main.go 的代码如下:
package main
/*
// 头文件的位置,相对于源文件是当前目录,所以是 .,头文件在多个目录时写多个 #cgo CFLAGS: ...
#cgo CFLAGS: -I./include
// 从哪里加载动态库,位置与文件名,-ladd 加载 libadd.so 文件
#cgo LDFLAGS: -L./lib -ladd -Wl,-rpath,lib
#include "add.h"
*/
import "C"
import "fmt"
func main() {
val := C.Add(C.CString("go"), 2021)
fmt.Println("run c: ", C.GoString(val))
}
#cgo CFLAGS: -I.
./demo1
run c: go2021
import "C"/*...*/
/*
#cgo ...
*/
import "C"
出现下面的报错信息
# demo1
./main.go:15:10: could not determine kind of name for C.Add
import "C"import ("C"; "fmt")C.Add()
# demo1
./main.go:15:10: could not determine kind of name for C.Add
还有一个关键是能否加载到动态库 libadd.so, 参考了网上一些例子,如果把第五行改为
cgo LDFLAGS: -L./lib -ladd
编译不会报错,执行时会出错。
./demo1: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
但如果设置了环境变量 LD_LIBRARY_PATH=/home/vagrant/testgo/lib 也能让它跑起来
LD_LIBRARY_PATH=lib/ ./demo1
\