為什麼gcc g 編譯鏈結靜態庫,會有順序問題呢?

時間 2021-06-02 02:37:39

1樓:

鏈結器在考察庫檔案(.a)的時候,不是把庫檔案看做乙個整體,而是將打包在其中的目標檔案(.o)作為考察單元。

在整個連線過程中,如果某個目標檔案中的符號被用到了,那麼這個目標檔案會單獨從庫檔案中提取出來,而不會把整個庫檔案連線進來。

然後,鏈結器在工作過程中,維護3個集合:需要參與連線的目標檔案集合E、乙個未解析符號集合U、乙個在E中所有目標檔案定義過的所有符號集合D。目標檔案按照順序解析, 因此不會把沒有用到的.

a庫里的.o 檔案加入U集合導致, 編譯錯誤.

因此, 需要把最基礎的.a檔案放在最後面, 可以重複-lxx.a檔案也可解決

2樓:蒼穹浪

為了鏈結效能,不做交叉搜尋。

有需要的話可以寫兩次,追加鏈結來解決

gcc libb.a liba.a libb.a liba.aCMake靜態庫可以互相新增依賴關係,最後鏈結命令就像上面那樣,但是動態庫不行。

3樓:kevin

主要為了改善鏈結器的效能,按順序來就不用重複掃瞄庫檔案了。但這樣做之後,對於有循壞依賴引用的情況(無論怎麼調整順序,前乙個庫總會依賴後乙個庫),就會鏈結失敗。

所以GCC提供了乙個Xlinker 選項,來解決這個問題,具體使用方法,可以查一下GCC手冊。

4樓:

憑記憶寫的,為了簡潔有些地方不嚴謹不過應該可以解決題主的問題。

每個庫只掃瞄一次。

每個庫中沒有用到的符號(的.o檔案)會被丟棄。

關於第2點,每個庫中都會用到很多符號,不嚴謹的說,其中有些符號是在這個庫中被定義的,而其中有些符號是在其他庫中被定義的。

然後鏈結器在掃瞄庫時,對於每個庫中的符號,會維護乙個未定義的符號的表,稱為ut吧。然後掃瞄每個庫時,會掃瞄其中的. o檔案,是否包含了ut中的符號,如果有的話,就鏈結該.

o檔案,去掉ut中相應的符號,將該. o檔案中的未定義符號加入到ut中。如果沒有的話就將該.

o檔案丟掉了。最後當鏈結器掃瞄了所有庫檔案後,ut中還有符號,這時候就會報錯。

說到這裡,題主應該能明白為什麼鏈結庫會有順序問題了,就不舉例子了。

接下來說下解決辦法,解決辦法有兩個,第乙個是鏈結器(ld)有個範圍引數,鏈結器會往復的掃瞄該範圍內的靜態庫,不過這個引數我忘了,題主有興趣可以查查。

第二個就是排列靜態庫的順序,排列靜態庫的順序需要知道每個庫中有那些定義的和未定義的符號,使用 nm -AC 命令可以查得到(使用其他選項可以只看未定義的)。

動態鏈結庫與靜態鏈結庫有什麼區別?

秀才 動態就是乙個檔案在自己工作的地方,可以重複多次使用的,比如像優秀的導購乙個人可以為6個人同時服務,然而呼叫是複製了N份而不是像CPU或者導購一樣輪詢。靜態就是編譯生成的 不能重複利用 Gavin 靜態庫應該就是和自己的程式編譯在一起的那種庫。動態庫就是不和自己的程式編譯在一起,而是執行的時候才...

java物件呼叫靜態方法為什麼會增加編譯成本

Loongson 3A4000 如果用物件名呼叫,Eclipse會提示The static method should be accessed in a static way Butters 因為編譯器會優化,即便是用物件去呼叫靜態方法,在編譯的時候編譯器直接優化了,優化成用類呼叫。所以這個規範的意...

vs2010為什麼設定了靜態編譯還是需要dll檔案才能執行exe呢?

你的sqlite是怎麼獲得的?如果是通過Visual Studio外掛程式安裝的,你拿到得應該是dll版,你編譯鏈結的lib是dll的stub,發行時就得帶著dll。這和你設定 MT沒關係。你要把sqlite靜態編譯到exe裡,要麼找到它的靜態lib發行版,要麼自己下原始碼編譯乙個出來。 叛逆者 M...