[英]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
人都必須知道這個依賴......正如你想象的那樣,這個問題可能發生在比單個庫更多的依賴中,並且可以很快成為一個連接噩夢。
解決這個問題的第一個想法是“這很簡單,當我編譯libone.a
時,我只需將libone.a
與libtwo.a
鏈接!
事實證明它並不像我希望的那么簡單......在編譯libone.a
,無法鏈接libtwo.a
。 靜態庫在編譯時不會鏈接到任何內容,而是在將庫編譯為可執行文件時必須鏈接所有依賴項。
例如,要編譯依賴於另一個靜態庫的靜態庫的main.cpp
,您必須鏈接這兩個庫。 總是。
g++ -o main main.cpp -lone -ltwo
另一個想法是嘗試將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.