簡體   English   中英

g ++鏈接錯誤 - 解決方法的工作原理

[英]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.

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