動態庫的麻煩之處在於 - 如果你的程式使用了成百上千個動態庫,你的程式在執行時如何找到這些動態庫?
一般有三個方法:
一、設定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只要設一個即可 - 這個在網路環境下尤其有用,之前這篇文章也講到過。