簡體   English   中英

為什么動態庫可以鏈接到其他庫,而靜態庫不能?

[英]Why can dynamic libraries link to other libraries, but static ones can't?

考慮以下代碼結構:

main.cpp -> depends on libone.a -> depends on libtwo.a

假設在main.cpp只使用來自libone.a函數。 所以實際上編寫main.cpp的程序員真的只關心libone.a 此時他們甚至不知道libone.a依賴於libtwo.a

他們嘗試如下編譯他們的代碼並得到鏈接器錯誤:

g++ -o main main.cpp -lone

在此處輸入圖片說明 - 錯誤! 未定義的符號!

這成為一個問題,因為因為libone.a依賴於libtwo.a ,任何使用libone.a人都必須知道這個依賴......正如你想象的那樣,這個問題可能發生在比單個庫更多的依賴中,並且可以很快成為一個連接噩夢。


嘗試 1 解決此問題:

解決這個問題的第一個想法是“這很簡單,當我編譯libone.a時,我只需將libone.alibtwo.a鏈接!

事實證明它並不像我希望的那么簡單......在編譯libone.a ,無法鏈接libtwo.a 靜態庫在編譯時不會鏈接到任何內容,而是在將庫編譯為可執行文件時必須鏈接所有依賴項。

例如,要編譯依賴於另一個靜態庫的靜態庫的main.cpp ,您必須鏈接這兩個庫。 總是。

g++ -o main main.cpp -lone -ltwo


嘗試 2 解決此問題:

另一個想法是嘗試將libone編譯為鏈接到libtwo.a的動態庫。

奇怪的是,這剛剛奏效! 編譯鏈接libone.so ,主程序只需要關心libone.so ,不再需要關心libtwo.a

g++ -o main main.cpp -lone

成功!


完成此練習后,仍然缺少一件。 我似乎無法弄清楚為什么靜態庫不能鏈接到其他庫,而動態庫可以。 事實上,在我鏈接libtwo.a之前,動態庫libone.so根本不會編譯。 不過這很好,因為作為libone.so的作者,我會知道它對libtwo.a依賴 - main.cpp的作者,但是不知道。 實際上,他們不應該知道。

所以回到真正的問題......為什么動態庫可以鏈接到其他這樣的庫而靜態庫不能? 這似乎是動態庫相對於靜態庫的明顯優勢,但我從未在任何地方看到過它!

靜態庫只是目標文件的存檔,沒有依賴的概念,因為它從未鏈接過。

共享庫是鏈接的、解決符號的,因此它們可以具有依賴關系。

由於您的問題涉及 gcc 和 .so/.a 文件,我假設您使用的是某種將 ELF 文件用於目標代碼的 Unix。

完成此練習后,仍然缺少一件。 我似乎無法弄清楚為什么靜態庫不能鏈接到其他庫,而動態庫可以。

正如另一個答案中提到的那樣,靜態庫沒有鏈接。 它們只是已編譯目標文件的存檔。 共享庫實際上是鏈接的,這意味着鏈接器實際上解析了任何導出符號可訪問的所有符號。 將導出的符號視為庫的 API。 一個完全鏈接的共享庫要么包含每個符號的定義,要么包含告訴操作系統(特別是動態加載器)需要哪些其他共享庫來訪問符號所需的依賴信息。 鏈接器將所有這些組合成一種稱為ELF 共享對象(動態庫)的特殊文件格式。

事實上,在我鏈接 libtwo.a 之前,動態庫 libone.so 根本不會編譯。 不過這很好,因為作為 libone.so 的作者,我會知道它對 libtwo.a 的依賴——但是 main.cpp 的作者不知道。 實際上,他們不應該知道。

libone.so可能編譯得很好,但由於未解析的符號,沒有libtwo將無法鏈接。 因為鏈接器在鏈接共享庫時必須解析所有可訪問的符號,所以如果找不到任何符號,它將失敗。 由於libone.so在使用符號libtwo ,鏈接器需要了解libtwo.a找到他們。 當您將靜態庫鏈接到共享庫時,通過將定義直接復制到輸出共享對象文件中來解析符號,因此此時, libone.so用戶可能對libone.so的使用libtwo因為它的符號只是在libone.so

另一種選擇是將共享庫鏈接到其他共享庫。 如果您將libtwo.so鏈接到libone.so (注意 .so 后綴),則鏈接器通過向輸出共享對象文件添加一個特殊部分來解析libone所需的符號,該部分表明它在運行時需要libtwo.so 稍后,當操作系統加載libone.so ,它知道它還需要加載libtwo.so 而且,如果您的應用程序僅直接使用libone ,那么您只需要在構建時告訴鏈接器即可,因為它將在libone鏈接,看到它需要libtwo ,並遞歸解析直到一切正常。

現在,操作系統必須在運行時加載的所有內容都會導致性能成本,並且如果您不小心,多個共享對象中存在全局靜態變量的一些問題。 靜態鏈接還有一些其他潛在的性能優勢,我不會在這里介紹,但可以說使用動態庫的平均性能並不那么好,但對於大多數現實世界情況,這種差異也可以忽略不計。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM