我讀過gcc編譯器在編譯引用靜態庫的應用程序時可以執行某些優化,例如 - 它只會從靜態中「拉」代碼應用程序依賴的庫。如果應用程序未使用靜態庫的某些部分,這有助於將應用程序的可執行文件的大小降至最低。GCC如何編譯引用靜態庫的應用程序
1)這是真的嗎?
2)GCC如何知道應用程序實際使用的靜態庫中的代碼?它是否只查看包含(直接和間接)應用程序中的頭文件,然後相應地提取代碼?或者它真的在查看靜態庫中的哪些方法被調用?
我讀過gcc編譯器在編譯引用靜態庫的應用程序時可以執行某些優化,例如 - 它只會從靜態中「拉」代碼應用程序依賴的庫。如果應用程序未使用靜態庫的某些部分,這有助於將應用程序的可執行文件的大小降至最低。GCC如何編譯引用靜態庫的應用程序
1)這是真的嗎?
2)GCC如何知道應用程序實際使用的靜態庫中的代碼?它是否只查看包含(直接和間接)應用程序中的頭文件,然後相應地提取代碼?或者它真的在查看靜態庫中的哪些方法被調用?
靜態庫只是一大堆目標文件。鏈接器(ld)將跟蹤使用哪些目標文件(即包含從某處引用的函數),並且不包括最終可執行映像中的未引用代碼。
gcc
沒有做任何事情。你所描述的一切是鏈接,這是由ld
處理。
ld檢查目標文件的符號表以確定哪些符號需要鏈接,然後從庫中提取相關目標文件並將它們鏈接到可執行文件中。
答案
1)是的,只有引用的代碼纔會被引入。除了較小的尺寸外,由於靜態庫包含庫導出的所有符號的索引表,因此鏈接速度也有所增加。在這個表中查找更快,而不是逐個查找目標文件。
或者,如果您想要引用靜態庫中的所有符號,無論引用如何。您可以將--whole-archive開關傳遞給ld。
2)在ld(gnu鏈接器)的上下文中提出這個問題會更正確,因爲這實際上是引用了引用。 GCC在完成編譯後調用鏈接器(除非你做了gcc -c,這會導致它在編譯後停止)。 因此,編譯完成後,ld會使用對象(.o)文件和庫的有序列表調用。 ld逐個處理.o文件,併爲每個鏈接器 a)記下此文件所需的外部符號,該符號還無法解析。將這些添加到(說)未解決的表中。 b)查看由該文件導出的符號(函數,全局變量),並解析它可以解決的以前的任何參考。 這是一個非常簡化的鏈接過程的概述。 現在,當鏈接器來到靜態庫時,它實質上做同樣的事情,這次使用靜態庫來解析符號。但是有一個區別,鏈接程序只會提取未解析的符號及其依賴關係。因此,假設我們有 a.o和libstatic.a,它們又包含b.o和c.o.
b.o定義bar()和moreBar();
c.o定義了baz()和moreBaz();
a.o定義foo();
foo調用調用baz的bar。現在,當你做 gcc -o app a.o libstatic.a 處理完a.o後,鏈接器知道它需要解析條形圖,這會從靜態庫中解析出來,然而在解析條形時,鏈接器會注意到條形圖需要baz。這再次從libstatic.a解析。 moreBar()和moreBaz()沒有引用並被忽略。