CGO可以让golang和c互相调用,譬如x264或者aac编解码,用go再实现一遍比较麻烦,直接调用c的函数会更合适。
CGO可以直接用C的代码,或者C的静态库,或者动态库,当然C++也是可以的。
写了一个fdkaac的binding:https://github.com/winlinvip/go-fdkaac
参考这两篇文章,讲得很清楚:
https://golang.org/cmd/cgo/
https://blog.golang.org/c-go-cgo
有个例子,go调用x264的函数:https://github.com/winlinvip/codec
在import “C”之前加preamble(注释),包含头文件。这样在C这个命名空间中就可以用C的函数了。
这个C包,实际上是个伪包,导入后会解析前面的preamble,用到头文件定义的类型、变量和函数。
preamble中可以有include,代码,宏定义,编译条件;静态变量不可用,静态函数可用。
编译条件是用#cgo指定的,包括CFLAGS、CPPFLAGS、CXXFLAGS、LDFLAGS。
cgo指令还可以用一些变量,譬如${SRCDIR}用来链接静态库。
下面是个C++导出的库:
// winlin.h#ifdef __cplusplusextern "C"{#endif// get the version.extern int winlin_version();#ifdef __cplusplus}#endif
// winlin.cpp// g++ -c -o winlin.o winlin.cpp && ar -rs winlin.a winlin.o#include "winlin.h"int winlin_version() { return 0x01020304;}
// main.cpp// g++ -o cpp main.cpp winlin.a#include <stdio.h>#include "winlin.h"int main(int argc,char** argv) { printf("version is %#x\n",winlin_version()); return 0;}
下面是main.cpp在Centos6的执行结果:
[winlin@centos6 gos]$ ./cppversion is 0x1020304[winlin@centos6 gos]$ ldd cpp linux-vdso.so.1 => (0x00007fff9f674000) libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003cbda00000) libm.so.6 => /lib64/libm.so.6 (0x0000003cb0a00000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003cbca00000) libc.so.6 => /lib64/libc.so.6 (0x0000003cb0e00000) /lib64/ld-linux-x86-64.so.2 (0x0000003cb0600000)
cgo,可以在golang中用这个静态库:
// go run main.gopackage main// #include "winlin.h"// #cgo LDFLAGS: ${SRCDIR}/winlin.a -lstdc++import "C"import "fmt"func main() { fmt.Println("version is",C.winlin_version())}
注意,得在h头文件中,使用c的方式导出符号。
除此之外,使用c++的库,得在LDFLAGS中加入-lstdc++。
总之,cgo的编译和一般的c或c++差别不大,引入的库和头文件之类。
运行结果如下:
[winlin@centos6 gos]$ go build -o test main.go[winlin@centos6 gos]$ ldd test linux-vdso.so.1 => (0x00007fff8df9f000) libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003cbda00000) libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003cb1600000) libc.so.6 => /lib64/libc.so.6 (0x0000003cb0e00000) libm.so.6 => /lib64/libm.so.6 (0x0000003cb0a00000) /lib64/ld-linux-x86-64.so.2 (0x0000003cb0600000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003cbca00000)[winlin@centos6 gos]$ ./testversion is 16909060
注意:preabmle可以是//,或者是//,但是不能是//,不能多个,会解析失败。
在Centos6下面的golang程序,没有用cgo:
[winlin@centos6 srs-plus]$ ldd obJs/bocar linux-vdso.so.1 => (0x00007fffb1fff000) libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003cb1600000) libc.so.6 => /lib64/libc.so.6 (0x0000003cb0e00000) /lib64/ld-linux-x86-64.so.2 (0x0000003cb0600000)
下面是用了cgo的golang程序:
[winlin@centos6 gos]$ ldd test linux-vdso.so.1 => (0x00007ffff43ff000) libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003cb1600000) libc.so.6 => /lib64/libc.so.6 (0x0000003cb0e00000) /lib64/ld-linux-x86-64.so.2 (0x0000003cb0600000)
下面是C++程序:
[winlin@centos6 srs-plus]$ ldd obJs/srs linux-vdso.so.1 => (0x00007fff5d9ff000) libdl.so.2 => /lib64/libdl.so.2 (0x0000003cb1200000) libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003cbda00000) libm.so.6 => /lib64/libm.so.6 (0x0000003cb0a00000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003cbca00000) libc.so.6 => /lib64/libc.so.6 (0x0000003cb0e00000) /lib64/ld-linux-x86-64.so.2 (0x0000003cb0600000)
都只是引用了系统的so,譬如c和c++,pthread还有ldl之类的。
总结以上是内存溢出为你收集整理的CGO,GOLANG调用C库,调用代码、静态库或动态库全部内容,希望文章能够帮你解决CGO,GOLANG调用C库,调用代码、静态库或动态库所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)