動態庫的麻煩之處

lzprgmr發表於2013-09-07

動態庫的麻煩之處在於 - 如果你的程式使用了成百上千個動態庫,你的程式在執行時如何找到這些動態庫? 

一般有三個方法:

一、設定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只要設一個即可 - 這個在網路環境下尤其有用,之前這篇文章也講到過。

 

相關文章