傳統方式下,庫函數的連結是在編譯器完成的,所有相關對象在編譯的時候被整合成一個可執行檔。與此相比,我們也可以把對庫函數的連結載入延遲到程式啟動並執行時期,也就是我們所稱作的動態連結。
動態連結的優點
除了靜態連結庫所有的模組化和代碼複用外,動態連結程式庫還有如下優點。
- 可以實現進程之間的程式庫共用:
當多個進程共用一個庫時(如stl庫和一些系統庫是基本上大多數程式都用的),動態連結方式可以只在記憶體中保留一份副本,節約記憶體。
- 升級變得簡單:
使用者只需要升級動態連結程式庫,而無需重新編譯連結其他原有的代碼就可以完成整個程式的升級(很多Windows的補丁就是這種方式發布的)。
- 可以動態載入:
當軟體比較大的時候,可以根據需要動態載入/卸載相應的連結庫,而無需像靜態連結的方式那樣必須一次性全部載入
建立動態連結程式庫
建立動態連結程式庫的方式比較簡單,以前文靜態連結庫的例子為例,我們只需要通過gcc -shared指令即可建立一個libstack.so的動態庫(靜態庫一般以.a作為副檔名,動態庫一般以.so作為副檔名)。
gcc -shared -o libstack.so stack.o
在連結階段使用動態庫的方式基本上和靜態庫一致。
gcc -o run main.c -L. –lstack
編譯玩這個程式後,我們執行後卻發現,它報動態連結程式庫找不到的錯誤提示。
tianfang > ./run
./run: error while loading shared libraries: libstack.so: cannot open shared object file: No such file or directory
我們也可以通過ldd命令查看某程式當前對動態連結程式庫的依賴情況:
tianfan > ldd run
linux-gate.so.1 (0xb7707000)
libstack.so => not found
libc.so.6 => /lib/libc.so.6 (0xb7546000)
/lib/ld-linux.so.2 (0xb7708000)
ldd的結果表明了我們產生的libstack.so找不到。因為動態連結程式庫是一個可以共用的檔案,因此往往存放在一個公用的位置,在Linux系統中程式尋找動態連結程式庫的規則如下:
- 首先在環境變數LD_LIBRARY_PATH所記錄的路徑中尋找。
- 然後從快取檔案/etc/ld.so.cache中尋找。
- 如果上述步驟都找不到,則到預設的系統路徑中尋找,先是/lib然後是/usr/lib。
很明顯,這幾個路徑都不包含當前路徑。要解決上述問題,一個簡單的方式就是把當前路徑加到環境變數中:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
然後再次用ldd名稱測試,發現現在就能找到我們的連結庫了。
tianfan > ldd run
linux-gate.so.1 (0xb77ce000)
libstack.so => ./libstack.so (0xb77ca000)
libc.so.6 => /lib/libc.so.6 (0xb760a000)
/lib/ld-linux.so.2 (0xb77cf000)
不過,很多大牛並不建議通過修改LD_LIBRARY_PATH這種方式
- LD_LIBRARY_PATH is not the answer http://prefetch.net/articles/linkers.badldlibrary.html
- Why LD_LIBRARY_PATH is bad http://xahlee.org/UnixResource_dir/_/ldpath.html
- LD_LIBRARY_PATH - just say no http://blogs.sun.com/rie/date/20040710
小結
本文主要介紹了一下如何通過gcc命令建立動態連結程式庫,如何通過ldd命令查看對動態連結程式庫的依賴情況和解決動態連結程式庫找不到的問題。並沒有對動態連結程式庫的原理進行詳細的介紹,感興趣的朋友可以在網上尋找相關文章。