注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天地不仁,以万物为Googol!

天行有常,不以物喜,不以己悲……

 
 
 

日志

 
 

Golang里调用C  

2010-04-18 13:21:28|  分类: 积累 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Golang调用C分两个步骤:1 写一个C的wrapper,这个很简单;2 对wrapper做编译,这个步骤有点复杂,而且涉及众多中间文件。应该是有办法用自动化的工具简化这个过程的。

先来展示一下C程序。为了将描述集中在如何调用上,C的程序很简单:
prints.h
#ifndef PRINTS_HEAD
void prints(char* str);
#endif

prints.c
#include "prints.h"
#include <stdio.h>

void prints(char* str)
{
  printf("%s\n", str);
}

之后是Golang对C的一个wrapper:
prints.go
package prints

//#include "prints.h"
// // some comment
import "C"

func Prints(s string) {
  p := C.CString(s);
  C.prints(p);
}

需要注意的是红色高亮的几行。在编译过程中,go会根据import "C"之前的几行注释生成一个c程序,并将这个c程序里的符号导入到模块C里,最后由import "C"再导入到go程序里。如果需要在其他go程序里调用api,需要参照prints.go里的Prints函数(要导出的go模块需要首字母大写)写一个wrapper func。其中对c程序里符号的引用都需要通过C来引用,包括一些c的类型定义,比如传给c api的int需要通过C.int来定义,而字符串则是C.CString。

有了这几个文件,就可以编译一个可以在go里加载的库了。以下都是在x86 linux下操作过程,如果是其他环境,请替换相应的编译命令。

cgo prints.go
编译wrapper,生成文件:
_cgo_defun.c:根据prints.go里标红的注释,生成用于在go里调用的c符号和函数
_cgo_gotypes.go:_cgo_defun.c里的符号在go里对应的定义
_cgo_.o
prints.cgo1.go:根据prints.go生成的go wrapper func
prints.cgo2.c:根据prints.go生成的c wrapper func

8g -o _go_.8 prints.cgo1.go _cgo_gotypes.go
编译go wrapper相关的文件,生成_go_.8

8c -FVw -I"/home/lizh/go/src/pkg/runtime/" _cgo_defun.c
编译c wrapper的通用部分,生成_cgo_defun.8

gopack grc prints.a _go_.8 _cgo_defun.8
对上面两个编译好的wrapper打包,生成prints.a

cp prints.a $GOROOT/pkg/linux_386/
将生成的prints.a放到go的包目录下

之后是对c部分的编译:
gcc -m32 -fPIC -O2 -o prints.cgo2.o -c prints.cgo2.c 
gcc -m32 -fPIC -O2 -o prints.o -c prints.c
gcc -m32 -o prints.so prints.o prints.cgo2.o -shared
根据prints.c和prints.cgo2.c生成prints.so,是一个可供go程序引入的动态库。通过objdump查看prints.so的符号,可以发现:
prints:需要引入的c api符号
_cgo_prints:由go生成的对c api的wrapper,具体可以查看prints.cgo2.c

cp prints.so /home/lizh/go/pkg/linux_386/
将编译好的动态库放入go的包目录下

之后就可以在go里调用prints这个c函数了:
package main

import "prints"

func main() {
  s := "Hello world!";
  prints.Prints(s);
}

查看生成的调用程序,可以看到对$GOROOT/pkg/linux_386/libcgo.so和$GOROOT/pkg/linux_386/prints.so两个动态库的引用。发布时需要将这两个库放到发布环境里。
  评论这张
 
阅读(11455)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017