转自: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动态库。

但有趣的是,当我在lib或hello目录下执行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中(或者将动态库拷贝到系统默认的库搜索路径下,但是老大不允许啊,郁闷)。

C. 下面,再做一些关于直接编译main.go文件的实验吧。
这个的编译与编译main包一样的——"-L"使用相对路径,那么必须确保编译的位置在加上相对路径能最终找到动态库;"-L"使用绝对路径,则可以在任意位置编译。

D. 最后,再做一些关于go中设置环境变量的实验。因为main程序的执行需要依赖LD_LIBRARY_PATH这个环境变量的值。
D1. 第一种方法:魏老大说的,就是写一个shell脚本,在这个脚本中先执行export语句,将动态库的路径加入到LD_LIBRARY_PATH中。然后再运行程序。
OK。这个方法通过。

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

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

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

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

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

F. 补充(2014.07.21)。
忘记做go test hello这个实验了。经实验,发现假如在该包中的-L使用相对目录来定位动态库,那么要想成功执行这个命令,需要以下两点:
第一,要确保执行该命令的位置再加上相对目录所得到的目录需要包含所依赖的动态库。这个与编译或安装main包很像。
第二,需要将所依赖的动态库所在的目录添加到环境变量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); }

Go中使用动态库C/C++库的更多相关文章

  1. ios 开发中 动态库 与静态库的区别

    使用静态库的好处 1,模块化,分工合作 2,避免少量改动经常导致大量的重复编译连接 3,也可以重用,注意不是共享使用 动态库使用有如下好处: 1使用动态库,可以将最终可执行文件体积缩小 2使用动态库, ...

  2. Linux中的动态库和静态库(.a/.la/.so/.o)

    Linux中的动态库和静态库(.a/.la/.so/.o) Linux中的动态库和静态库(.a/.la/.so/.o) C/C++程序编译的过程 .o文件(目标文件) 创建atoi.o 使用atoi. ...

  3. Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf 动态库的后缀为*.so 静态库的后缀为 libxxx.a ldconfig 目录名

    Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf  动态库的后缀为*.so  静态库的后缀为 libxxx.a   ldconfig   目录名 转载自:http://b ...

  4. Linux系统中“动态库”和“静态库”那点事儿【转】

    转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻. ...

  5. gcc中动态库和静态库的链接顺序

    so文件:动态库a文件: 静态库exe文件:可执行程序(linux下以文件属性来标示是否是可执行文件,与后缀名无关) 经过自己写的一些测试程序,大致了解了下gcc中链接顺序问题,总结出以下几点:1,动 ...

  6. Linux系统中“动态库”和“静态库”那点事儿

    摘自http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在 ...

  7. QT中添加 动态库(.so) 和 静态库 (.a) 的方法

    在QT 的Makefile文件中: 1 添加动态库,如lipcap.so 则,在LIBS一行中添加“-L/usr/local/lib -lpcap”,依据自己的情况修改libpcap.so的路径 2 ...

  8. 如何在vue中修改动态标签中的样式和修改组件库样式

    vue中修改动态标签中的样式和修改组件库样式 因为vue中的标签在渲染的时候,都会给标签加上id 所以你想在<style lang="scss" scoped>直接修改 ...

  9. 动态库与静态库的学习 博主写的很好 静态库 编译的时候 需要加上 static 动态库编译ok运行不成功就按照文章中的方法修改

    来源连接   http://www.cnblogs.com/skynet/p/3372855.html C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库 ...

随机推荐

  1. python网络爬虫之scrapy 调试以及爬取网页

    Shell调试: 进入项目所在目录,scrapy shell “网址” 如下例中的: scrapy shell http://www.w3school.com.cn/xml/xml_syntax.as ...

  2. linux 中解压与压缩 常用操作详细讲解

    平时有时候 会在服务器进行一些文件的操作,比如安装一些服务与软件等等,都有解压操作,一般在 导出一些简单的服务器文件,也是先压缩后再导出,因此,在这里根据平时用到解压与压缩命令的频率来记录下: 1.最 ...

  3. Linux通过Shell对文件自动进行远程拷贝备份

    在执行计划任务拷贝文件的时候,用scp命令需要输入密码,这里用公共密钥的方式实现密码的自动输入. 具体操作: 要求:把192.168.0.2机上的test.tar拷贝到192.168.0.3机器的上 ...

  4. Hadoop2.x + eclipse 插件配置

    http://blog.csdn.net/u012874209/article/details/52105304 搭建集群那些就不用说了,主要有几个关键的地方需要注意(自己的Hadoop版本是2.5. ...

  5. 每天一个Linux命令(19)find命令_初识

    Linux下find命令在目录结构中搜索文件,并执行指定的操作.     (1)用法: 用法: find pathname    -option      [-print | -exec | -ok] ...

  6. 声明:关于该博客部分Java等方向知识参考来源的说明

    [声明] 该博客部分代码是通过学习黑马程序员(传智播客)视频后,参考毕向东.张孝祥.杨中科等老师的公开课视频中讲解的代码,再结合自己的理解,自己手敲上去的,一方面加深自己的理解和方便以后自己用到的时候 ...

  7. C#Winform之等待窗体

    窗体主要代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...

  8. rail模型

    rail是一种以用户为中心的性能模型,又google提出,其主要目标是让用户满意,主要分为response animation idle load四个部分 response 输入延迟时间小于100毫秒 ...

  9. crond

    Crond介绍 Crond是linux系统用来定期执行命令或程序的工具. 服务 /etc/init.d/crond 命令 crontab [root@rhel6 script]# crontab -h ...

  10. dedecms 织梦点击图片进入下一页代码

    织梦DedeCMS5.6网站文章页点击图片进入下一页最后一页进入下一篇文章的方法: 我们首先按照下面的方法修改: 修改 include/arc.archives.class.php 1.查找“//解析 ...