开发环境:
CentoOs(Linux )
起因:
最近在项目开发过程中需要生成.so文件来给其他的程序调用,而我的这部分程序又需要调用其他的.so,这对于一个刚刚入职的程序猿来说着实有些令人着急,大致的项目需要如图,其中libStd.so是项目的标准库,和我的.so在同一父目录下,libmkl_xxx.so是mkl库,在系统目录下。
当时由于是第一次生成.so(年少无知),照着网上的代码直接就编译了,然后其他同事在使用时出现undefined symbol <something>.
错误代码:
g++ -c -g -fPIC Dir1/*.cpp Dir2/*.cpp -I/opt/intel/mkl/include g++ -shared -o libMyLib.so *.o
概念:
函数库可以分成动态库(dynamic)和静态库(static),静态库相当于把你的所有文件都打了包,以后要跟其他程序集成的话就得把整个包给集成进去,这往往导致最终程序会变得很大,而且也不易升级、维护,动态库相当于一个开放的包,大家都可以用,只要你链接到它,你也可以用,我链接到之后我也可以用,是公共、独立的。两者更进一步的区别参考链接【1】在不同系统上这两者命名稍微有些不同:
(后缀) | Windows | Linux |
静态库 | .lib | .a |
动态库 | .dll | .so |
.so文件是shared object文件,即共享对象,也就是说其在加载后是可以被多个进程所共享,至于如何实现可以参考链接【2】。
-fPIC: Position Independent Code,参见链接【2】
-shared:表示产生的是共享对象
由于在链接产生共享对象的时候需要检查语法和语义,所以在链接阶段需要指定链接的库名-l和库所在位置-L【1】(这也是我出现上面的错误的原因)
解决方案:
g++ -c -g -fPIC Dir1/*.cpp Dir2/*.cpp -I/opt/intel/mkl/include g++ -shared -o libMyLib.so *.o -lStd -L../PATH_A/TO/Bin -lmkl_xxx -L/PATH_B/TO_MKL_XXX
后续:
为了查看自己生成的库链接对不对,可以使用
ldd MyLib
这条指令用于查看依赖项,即你的库有没有链接成功
可以看到上面的libBarbeque.so没有找到,这是为什么的?我明明在链接阶段指定了对应的.so才对?先别急,这是因为你虽然刚刚指定库,但是系统在查找时默认只会在当前路径或者系统指定的LD_LIBRARY_PATH目录下查找,所以你只需要把依赖的.so放到当前目录下,或者用配置环境变量的方式使系统知道你需要在哪里找,可以参考链接【3】(记得是修改LD_LIBRARY_PATH不是默认的PATH!)
最后注意,在实际运行的时候也需要指定对应的库和路径,在LD_LIBRARY_PATH中添加.so所在文件夹,这样可以确保程序顺利调用
【1】http://blog.csdn.net/nieyinyin/article/details/6890557:linux中的.so和.a文件
【2】http://www.cnblogs.com/cswuyg/p/3830703.html:linux共享对象之编译参数fPIC
简要提纲(仅供自己观看,有理解不对的请谅解!)
1.如果不采用PIC,相当于给每个进程开专线,这样物理内存利用率不高;PIC在我认为就是建立了一个中转站,大家先来中转站,再转到对应的模块;
【3】http://www.cnblogs.com/hust-chenming/p/4943268.html:linux查看和修改PATH环境变量的方法