调用C库函数

    虽然发展迅猛,局限性也有——类库不是特别丰富。有些开源项目,例如 x264 ,只有 C 语言版本, Go 重写一遍也不太现实。

    好在, Go 提供了一种调用 C 函数的机制—— cgo 。本节以具体的例子演示,如何使用 cgo 调用 C 函数:

    为了演示需要,虚设一个名为 的函数库。函数库只提供一个名为 sayHello 的函数,接口如头文件:

    /_src/practices/cgo/callee.h

    sayHello 函数只是简单输出 Hello, world! ,实现如下:

    /_src/practices/cgo/callee.c

    1. /**
    2. * FileName: callee.c
    3. * Author: Fasion Chan
    4. * @contact: fasionchan@gmail.com
    5. * @version: $Id$
    6. *
    7. * Description:
    8. *
    9. *
    10. **/
    11.  
    12. #include <stdio.h>
    13. #include "callee.h"
    14.  
    15. void SayHello() {
    16. printf("Hello, world!\n");
    17. }

    接下来,将上述代码编译成动态库:

    这个命令将 callee.c 源码编译成 callee.o 目标文件。接下来,将目标文件转成成 libcallee.so 动态库文件:

    1. $ gcc -shared -o libcallee.so callee.o
    2. $ ls
    3. Makefile callee.c callee.h callee.o caller.go libcallee.so

    /_src/practices/cgo/caller.go

    16 行通过 选项指定头文件搜索路径,编译器据此发现头文件 callee.h 。这里 . 表示当前目录,可以根据项目情况设置为其他目录。

    17 行通过 -L 选项指定动态库搜索路径,编译器据此发现 libcallee.so 。接着,通过 -l 参数链接到该动态库。

    18 行则是引入头文件,据此编译器知晓 C 函数接口。

    第 通过 import 关键字引入一个特殊的模块 C ,之后便可访问到所用链接的 C 库函数。第 27 行,调用 sayHello 函数。

    警告

    第19行与20行之间不能留空行,不然构建失败!

    接下来,编译整个程序:

    1. $ ls
    2. Makefile callee.c callee.h callee.o caller caller.go libcallee.so
    3. $ ./caller
    4. Hello, world!
    5. Success!

    以上例子包含多个编译步骤,需要执行多个命令。

    在程序开发中,经常也是如此。如果每次修改代码后,都需要手工执行这么多命令,那么效率和质量将深受拖累。

    我们可以用更自动化的手段进行构建,以 Makefile 为例:

    /_src/practices/cgo/Makefile

    在源码目录准备以上 ,之后运行:

    1. $ make
    2. gcc -fPIC -c callee.c
    3. gcc -shared -o libcallee.so callee.o
    4. go build caller.go
    5. ./caller
    6. Hello, world!
    7. Success!

    可以看到, make 命令根据 Makefile 定义自动执行编译命令并执行目标程序。

    Makefile 更深入的使用方法不在本节的讨论范畴,有兴趣的童鞋自行 。

    订阅更新,获取更多学习资料,请关注我们的 微信公众号