动态库的麻烦之处在于 - 如果你的程序使用了成百上千个动态库,你的程序在运行时如何找到这些动态库?
一般有三个方法:
一、设置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只要设一个即可 - 这个在网络环境下尤其有用,之前这篇文章也讲到过。