CGO,GOLANG调用C库,调用代码、静态库或动态库

winlinvip · · 8601 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

CGO

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 __cplusplus
extern "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]$ ./cpp
version 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.go
package 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]$ ./test
version 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之类的。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:winlinvip

查看原文:CGO,GOLANG调用C库,调用代码、静态库或动态库

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

8601 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传