• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Go中使用动态库C/C++库

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

转自:http://studygolang.com/articles/1441

最近需要做一些在go中使用动态C++库的工作,经常碰到找不到动态库路径这种情况,所以就花点时间,专门做一下实验来了解Go。

 

一、示例代码目录结构(假设代码根目录为/home/gdc/cgotest):

----|bin:
----|pkg
----|src
--------|main
------------|main.go
--------|oidb
------------|hello
----------------|hello.go:
----------------|api.h
------------|lib
----------------|libapi.so

二、代码
api.h文件内容:

#ifndef __API_H__
#define __API_H__
void hello();
#endif

hello.go文件内容:

package hello
/*
#cgo CFLAGS: -I./include
#cgo LDFLAGS: -L../lib -lapi
#include "api.h"
*/
import "C"

func Hello(){
C.hello();
}

main.go文件内容:

package main
import "oidb/hello"
func main(){
hello.Hello();
}


三、前提

A. 将该代码目录添加到GOPATH环境变量中。——export GOPATH=$GOPATH:/home/gdc/cgotest

B. 环境变量LD_LIBRARY_PATH值为空



四、关于cgo中使用动态C/C++库的一些小实验:

A. 按照如上的目录组织及文件内容,可以在任意地方执行go build oidb/hello或者 go install oidb/hello。

执行go build oidb/hello这个命令,可能会没啥反应,但是可以告诉你编译通过了。

执行go install oidb/hello这个命令,会在代码根目录下的pkg/linux_amd64目录(如果不存在会自动创建)创建oidb/hello.a。

OK,说明该包已经可以给别人使用了。但是别人能否正常使用呢?接下来做一些main.go相关实验。

 

B. 很遗憾,此时我在很多位置尝试执行go build main 或者 go install main,都会提示我找不到libapi.so动态库。

但有趣的是,当我在libhello目录下执行go build main 或者 go install main时,都会成功。其中执行go install main会在代码根目录的bin子目录下生成

一个main可执行文件,go build main会在当前目录下生成一个main可执行程序。然后当我尝试执行这个位于bin目录下的main可执行文件后,会提示找

不到libapi.so这个动态库。

然后我又尝试将lib目录复制到bin目录下和代码根目录下,然后在bin子目录下执行main可执行文件,还是提示找不到libapi.so动态库。

最后,我拿出终极大招,执行"export LD_LIBRARY_PATH=/home/gdc/cgotest/lib"(此时我将lib目录移动到代码根目录下了),然后就可以正常

运行main可执行程序了。

然后我又将该lib目录移动到bin目录和src目录下,然后分别用export命令将这个lib目录的新位置添加到LD_LIBRARY_PATH环境变量中,然后执行main,都可以正常执行。

 

小结:

main包的编译理解:

当编译或安装main包时,go会以此时所处的位置为当前目录。然后如果其引用的某个包中使用相对目录依赖某个动态库C/C++库。那么会从当前目录出发,根据那个相对位置去找动态库。所以上面在编译或安装main包时,唯独在lib或hello目录下成功通过编译了,这就是因为go以从当前目录出发,到其父目录的lib子目录下寻找libapi.so动态库,然后成功找到,从而通过编译。其实不一定非要在lib或者hello目录下编译main包。只要确保编译main包位置的父目录下有一个子目录lib,同时该lib目录下有libapi.so这个文件,即可通过编译。比如,我将lib目录在代码根目录下,然后我转到bin目录下,然后就可以成功编译或安装main包了。

当然了,如果你在使用动态库时使用"-L"选项设置的是绝对目录而不是相对目录,那么编译或安装main包,就没有这么多限制了。你可以在任意位置编译或安装。


main可执行程序执行的理解:
不管你在代码中使用"-L"选项指定的动态库位置是相对目录或绝对目录,要想执行这个main可执行程序,都要将所依赖的动态库所在的目录添加到环境变量LD_LIBRARY_PATH中(或者将动态库shell脚本,在这个脚本中先执行export语句,将动态库的路径加入到LD_LIBRARY_PATH中。然后再运行程序。
OK。这个方法通过。

D2. 第二种方法:在go中设置环境变量的值。

经过自己实验,然后问魏老大,感觉这是不可能的。因为当程序启动时,系统就会自动加载该程序所依赖的那些库,而此时你在程序中设置环境变量的

代码还没运行呢。当然还是找不到动态库。

一个解决办法:自己手动加载动态库。

参考了http://blog.csdn.net/joker0910/article/details/6103793这篇文章的手动加载库,可以正常使用。

 

F. 补充(2014.07.21)。
忘记做go test hello这个实验了。经实验,发现假如在该包中的-L使用相对目录来环境变量LD_LIBRARY_PATH中。这个与执行main很像。


修改后的hello.go文件内容如下:

package hello

/*
#cgo LDFLAGS: -ldl
#include 
#include 
#include "api.h"

void hello_c(char* lib_path){
        char* func_name="hello";
        void* libc;
        void (*hello_call)();
        if(libc = dlopen(lib_path,RTLD_LAZY))
        {
                hello_call = dlsym(libc, func_name);
                (*hello_call)();
                dlclose(libc);
        }
}
*/
import "C"
import "unsafe"

var EXTENSION_DIR string = "/home/guess/.davengu_workdir/go_learning/cgo/use_shared_library/src/oidb/lib/"
var OIDB_API string = "libapi.so"

//#cgo LDFLAGS: -L/home/guess/.davengu_workdir/go_learning/cgo/use_shared_library/src/oidb/lib -lapi
//#cgo LDFLAGS: -L../lib -lapi

func Hello() {
        libPathC := C.CString(EXTENSION_DIR+OIDB_API);
        defer C.free(unsafe.Pointer(libPathC));
        C.hello_c(libPathC);

}

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap