[英]A g++ link error - why the workaround works
我在一個大項目中工作。 現在遇到鏈接錯誤。
解決方法可以避免此錯誤,但我無法弄清楚它為何起作用。
這是與我的問題相關的文件結構:
project |-package_a |--a.cpp |--... |-package_b |--b.cpp |--c.cpp |--... |-package_others
package_a中的所有* .o將打包到aa中,package_b中的* .o將打包到ba中
"g++ -o exec -Bstatic ba aa ..."
用於生成二進制文件。
在package_b / b.cpp中,我添加了一個函數foo()。
在package_a / a.cpp中,我使用了這個函數。
但是在這里我會得到一個鏈接錯誤,說明在ao中未定義的foo()引用
我可以驗證(通過objdump)foo()已經在bo中
通過將link命令更改為"g++ -o exec -Bstatic aa ba ..."
,可以成功構建二進制文件。 我現在明白鏈接器確實關心鏈接列表中的順序 。 但請理解這是一個大項目,我無權更改項目配置,因此必須保留原始鏈接順序。
然后我在package_b / c.cpp中添加了一個虛擬函數bar(),除了調用foo()之外什么都不做,然后原始的"g++ -o exec -Bstatic ba aa ..."
會在沒有任何鏈接錯誤的情況下運行。
任何人都可以告訴我為什么在這種情況下在同一個包中添加一個虛擬函數會有效嗎?
我正在使用g ++ 4.4.4和linux 2.6.18-194.el5
任何評論將不勝感激
這很正常。 鏈接時,鏈接器經過對象的文件列表中,找到未定義的引用,然后由后它的到來,其他目標文件/庫納。
您可以通過以下方式更改此行為
包括其中一個檔案兩次,如
g++ -o exec aa ba aa
使用-(
構造
g++ -o exec -( aa ba -)
但請理解這是一個大項目,我無權更改項目配置,因此必須保留原始鏈接順序。
運氣好......也許經理或者只是不想讓你使用b
函數a
。
然后我在package_b / c.cpp中添加了一個虛擬函數bar(),除了調用foo()之外什么都不做,然后原始的“g ++ -o exec -Bstatic ba aa ...”會在沒有任何鏈接錯誤的情況下運行。
可能是package_b/c.cpp
另一個函數已被引用,並且鏈接器使用了bar()
(因為它們在同一個文件中)並且這引用了foo()
,它隨后也包含在輸出中。 它成功了,因為foo
也在ba
。
您可能希望了解鏈接器的工作原理 。 BTW, -Bstatic
標志是不必要的,因為.a.
目標文件僅以靜態方式存檔鏈接(就好像命令行中指定了.a
中包含的目標文件列表而不是.a
)。
或者,您始終可以使用--start-group
/ --end-group
選項包裝存檔列表,以使鏈接器多次掃描存檔列表,這樣就不需要對存檔進行排序(如MS VC ++ ):
g++ -o exec -Wl,--start-group a.a b.a -Wl,--end-group
見man ld
:
-( archives -)
--start-group archives --end-group
The archives should be a list of archive files. They may be either
explicit file names, or -l options.
The specified archives are searched repeatedly until no new
undefined references are created. Normally, an archive is searched
only once in the order that it is specified on the command line.
If a symbol in that archive is needed to resolve an undefined
symbol referred to by an object in an archive that appears later on
the command line, the linker would not be able to resolve that
reference. By grouping the archives, they all be searched
repeatedly until all possible references are resolved.
Using this option has a significant performance cost. It is best
to use it only when there are unavoidable circular references
between two or more archives.
與Visual-C ++鏈接器不同,GCC需要按順序提供靜態庫,以便在使用之前定義引用。 不要問我為什么,但是你總是要檢查你是否正確列出了與GCC正確連接的文件。
有一個深入的解釋在這里 。
當您使用靜態庫中的函數時,必須首先在命令行上放置使用該函數的文件,然后是定義函數的庫。 否則,如果首先放置定義,gcc(或更具體地說,ld)將丟棄“未使用”函數。 這就是gcc的工作原理,抱歉。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.