linux 下 奇怪的 動態庫 依賴問題


 轉:http://fanwei51880.blog.163.com/blog/static/3240674020111145285375/

 

總結如下:
1)當你在編譯生成靜態庫的時候, 只需要相應的依賴庫庫的頭文件即可. 只有在你想生成so,或可執行文件 時, 才需要lib庫.
   對於你沒有用到的lib, 但是不包含又編譯失敗, 那么只包含其頭文件即可.
2)如果你同時使用了多個庫,而庫之間又相互依賴,那么在鏈接是,把最底層的依賴庫放在最右側.否則可能會鏈接失敗
3)如果我已經把最底層的庫放在最后邊了,還是鏈接失敗怎么辦?
請檢查是否依賴了同名的其他的庫. 自己查看鏈接庫的路徑


對1)的說明
如果你不用該so, 那么你就不要將他的lib放在你的makefile里面! 否則運行時會依賴該so的.
案例:

      我的cgi, cp到正式環境, 居然開始依賴 mysql的so, 奇怪, 我的項目中並無用到mysql. 然后,makefile中去掉mysql相關的 頭文件, 以及lib, 卻發現 沒有mysql的頭文件還編譯不過去, 因為我用的另一個庫tlib用到了mysql, fuck, 怎么辦?

答案: 只把mysql的頭文件 路徑等加到 makefile里面, 這樣gcc有了頭文件至少可以編譯過去. 然后, 在連接的時候, 由於你的代碼並沒有真正用到mysql, 所以不會去連接mysql相關的東東. 所以, 直接鏈接通過.

分析: 雖然tlib用到了mysql, 但是由於tlib是一個非常龐大的靜態庫, 其里面依賴的內容非常多, 而我只用到了tlib里面的一小部分功能(且不含mysql), 所以, 我只需把mysql頭文件加上即可. 鏈接時時不會真正用到mysql的沒有lib. 除非我用到tlib里面的相關mysql接口.


如果你想生成靜態庫:
linux下, 如果你的項目(是個靜態庫)的依賴某個庫(不管動態庫還是靜態庫), 當你在編譯生成靜態庫的時候, 只需要相應的依賴庫庫的頭文件即可.
(因為, linux的.a本身就是一堆.o的集合, .o也就是一堆cpp文件的編譯結果, 並沒有開始執行鏈接)
舉例:
  libcomm.a 就是這樣, 雖然依賴的很多的庫, 比如html_template, mysql, MARKUPSTL, 但只需他們的頭文件即可.
USED = \
       MARKUPSTL \
       NETCLIENTEX \
       HTML_TEMPLATE \
       TLIB \


INC  = \
    $(foreach i, $(USED), $(INC_$(i)))

#看到沒, LIB 為空!!!
LIB  = 



如果你想生成so,或可執行文件 
1)那么你必須包含上你需要的lib, 而且, 如果你 通過 -lxxx, 那么gcc默認后首先嘗試鏈接 xxx的動態庫libxxx.so.1(libxxx.so.1是libxxx.so的符號鏈接文件, 並不是真正的libxxx.so, 但是會指向libxxx.so), 如果找不到libxxx.so.1,然后尋找xxx的靜態庫libxxx.a.
2)同時, 如果你沒有用到某個lib的話, 一定不要包含其lib, 如果編譯不通過, 最多只需包含其頭文件即可.
就像我上面的案例一樣, 沒有用到mysql, 卻包含而來mysql的lib, 導致在運行機上找不到 mysql.so 而運行失敗, 去掉mysql的lib, 只保留mysql的 頭文件, 可以鏈接過去, 並且可以正常運行.

2)如果你同時使用了多個庫,而庫之間又相互依賴,那么在鏈接是,把最底層的依賴庫放在最右側.否則可能會鏈接失敗
  g++ -o $(target) liba libb libc
  如果liba 依賴libb, libb依賴libc, 那么請把libc放在最后面.
  如果 g++ -o $(target) liba libc libb會導致libb的鏈接失敗. 
  有一種情況離開,liba也依賴libc,並且依賴關系和libb對libc的依賴的接口一樣, 那么把libc放在中間不會報錯,但最好不要這么做.
 
3)如果我已經把最底層的庫放在最后邊了,還是鏈接失敗怎么辦?
   檢查是否連接到了相同名字的其他的庫.  我又一次就是如此,系統系統中存在多個network的庫, 雖然我把正確的network庫放在了最后面,但是由於其他庫包含路徑下也有老的同名的network庫,導致我鏈接失敗.

庫依賴的查看

使用ldd命令來查看執行文件依賴於哪些庫。

該命令用於判斷某個可執行的 binary 檔案含有什么動態函式庫。
[root@test root]# ldd [-vdr] [filename]
參數說明:
--version  打印ldd的版本號
-v --verbose  打印所有信息,例如包括符號的版本信息
-d --data-relocs  執行符號重部署,並報告缺少的目標對象(只對ELF格式適用)
-r --function-relocs  對目標對象和函數執行重新部署,並報告缺少的目標對象和函數(只對ELF格式適用)
--help 用法信息。

如果命令行中給定的庫名字包含'/',這個程序的libc5版本將使用它作為庫名字;否則它將在標准位置搜索庫。運行一個當前目錄下的共享庫,加前綴"./"。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM