动态库的麻烦之处

动态库的麻烦之处在于 - 如果你的程序使用了成百上千个动态库,你的程序在运行时如何找到这些动态库? 

一般有三个方法:

一、设置LD_LIBRARY_PATH

export LD_LIBRARY_PATH="/path/to/lib"

直接手工设是不可能完成的任务,因为你也知道有很多path (多不是问题,问题时你得知道这些path),所以一般需要在由编译系统来自动产生这些path,并放到一个runscript中:

#set path
export LD_LIBRARY_PATH=/path/to/lib1
export LD_LIBRARY_PATH=/path/to/lib2:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/path/to/lib3:$LD_LIBRARY_PATH
# ...
export LD_LIBRARY_PATH=/path/to/lib100:$LD_LIBRARY_PATH

# run app
/path/to/myapp

 

二、设置rpath

rpath设置可以在编译时:

g++ -Wl,-rpath,/path/to/lib ...
or
ld -rpath /path/to/lib ...

rpath应该可以是-L一致,所以可以在编译系统中做些工作自动产生rpath,premake目前(4.4beta)还不支持,但可以比较简单的做个扩展支持:(同时也展现了premake的灵活性)

origin_libdirs = libdirs
function libdirs(dirs) 
    origin_libdirs(dirs)
    if type(dirs) == 'string' then
        dirs = { dirs }
    end
    for _, dir in ipairs(dirs) do
        linkoptions('-Wl,-rpath,' .. dir)
    end
end

将libdirs都作为rpath编译到binary中去。

可以通过readelf查看

readelf -d binary

而cmake则提供了比较好内建支持,有选项可以选择是否加入rpath。

 

但是,你编译时的rpath并不代表就是你最终生产环境中的rpath,考虑一下continuous delivery中的一个情况:

该项目有一个shared library和一个binary,在CI的build agent上编译产生,所以指向shared library的rpath是一个指向build agent上local的path,这些artifacts会被上传到artifact repository,然后在发布时被部署到生产环境中,此时该rpath必定是错误 --- 运行失败。

此时需要postprocess来修改rpath,有个叫做patchelf的工具:

patchelf --set-rpath /path/to/production/lib

同样,怎么改rpath不是重点,重点是有哪些rpath,改成什么样 - 这些需要在build system在编译过程中收集。

还可以去掉不需要的rpath:

patchelf --shrink-rpath program

 

三、拷贝或者symbolic link

Windows下一般直接把所有dll打包放一起 - 与app同一目录,连PATH都不用设。

Linux下我们可以把所有的library都symblic link到同一目录下,PATH只要设一个即可 - 这个在网络环境下尤其有用,之前这篇文章也讲到过。

 

posted @ 2013-09-07 23:36 lzprgmr 阅读(...) 评论(...) 编辑 收藏

黄将军