簡體   English   中英

通過`-l <libname> `vs通過`lib <libname> .a`直接鏈接到鏈接器?

[英]Passing `-l<libname>` vs passing `lib<libname>.a` directly to linker?

假設我有兩個檔案

// a.c
int a() {return 1;}

// b.c
int a();
int b() {return a();}

我將它們分別編譯為aobo

為了創建可執行文件或共享庫,可以調用gcc ao bo -o libab.so -shared 但我也注意到,也可以稱gcc bo -L. -l:ao -o libab.so -shared gcc bo -L. -l:ao -o libab.so -shared以生成(顯然)相同的輸出。 令我驚訝的是,甚至運行gcc ao -L. -l:bo -shared gcc ao -L. -l:bo -shared導致同時a()b() (鏈接器不應該丟棄未使用的庫bo因為ao不依賴它嗎?)

后兩個大概傳遞a好像ao是一個庫。 現在,如果我運行ar rcs liba.a ao ,則gcc bo -L. -l:liba.a -shared gcc bo -L. -l:liba.a -sharedgcc bo liba.a -shared都可以正常運行,並提供相同的輸出。

但是,我也看到了這種技巧不起作用並導致未定義引用的情況。 因此,我的問題就如標題所述:將對象作為庫和普通對象文件傳遞之間有什么區別?在C ++中有什么區別?

這個問題出現在一個更大的項目中。 很抱歉缺少mcve,因為我似乎無法隔離問題。

[如何]將-l<libname>與直接將lib<libname>.a傳遞給鏈接器[不同]?

傳遞-llibname.so將使GNU鏈接程序在搜索符號時僅遍歷庫一次(如果不在--whole-archive選項之后)。 直接向鏈接器指定.a文件會使它在.a文件內的所有目標文件中搜索每個符號的每個符號,而不僅是搜索一次。

GCC鏈接器選項 (重點是我的):

-llibrary

...

在命令中寫入此選項的位置會有所不同。 鏈接器按照指定的順序搜索和處理庫和目標文件。 因此,'foo.o -lz bar.o'在文件foo.o之后但在bar.o之前搜索庫'z'。 如果bar.o在“ z”中引用函數,則可能不會加載這些函數。

binutils ld選項

-l名稱規范

...

鏈接器僅在命令行上指定的位置搜索一次存檔。 如果歸檔文件定義了在命令行上歸檔文件之前出現的某個對象中未定義的符號,則鏈接器將包含歸檔文件中的相應文件。 但是,稍后出現在命令行中的對象中未定義的符號將不會導致鏈接程序再次搜索檔案。

將對象作為庫和普通對象文件傳遞之間有什么區別,在C ++方面有什么區別?

這取決於實現方式。 在最一般的意義上,諸如Unix風格的鏈接程序要求您在庫搜索路徑中搜索通過-l選項命名對象,而如果直接命名文件,則必須指定確切的文件。

另外,如果使用-l選項指定要鏈接的文件,則通常情況下,鏈接器通過在參數前添加“ lib”並附加“ .a”,或通過其他方式(例如,通過搜索或搜索“ .so”文件。 (當參數的第一個字符是:時,您似乎正在使用的GNU鏈接器對此行為提供了例外。在這種情況下,它將參數的其余部分作為精確的文件名,並進行搜索。)

許多鏈接器還接受在命令行上指定的顯式庫名稱(例如, libfoo.a而不是-lfoo ),因此它們需要能夠確定每個文件的類型。 通常,這是通過檢查文件而不是依靠文件名來進行的。 並且GNU ld至少將此文件類型檢測擴展到通過-l選項指定的文件。

在命令行上以任何特定形式指定對象和庫的順序對於典型的鏈接程序實現都很重要。 例如, GNU ld的文檔指定

相對於目標文件和其他文件選項,引用文件的選項(例如“ -l”或“ -T”)導致文件在命令行中出現該選項的位置被讀取

這很重要,因為

鏈接器僅在命令行上指定的位置搜索一次存檔。 如果歸檔文件定義了在命令行上歸檔文件之前出現的某個對象中未定義的符號,則鏈接器將包含歸檔文件中的相應文件。 但是,稍后出現在命令行中的對象中未定義的符號將不會導致鏈接程序再次搜索檔案。

但是當然

您可以在命令行上多次列出同一檔案。

這些文檔尚不完全清楚,但是從經驗上講,上述術語“存檔”的使用意義重大。 實際上,僅適用“僅搜索一次”規定的存檔文件-靜態庫。 初步估算,無論如何指定,GNU鏈接器命令行上不同普通對象文件和共享庫的相對順序都不會影響符號解析。

所以,是的,它並不管你是否指定您指定它們沒關系常規對象文件或靜態歸檔或共享庫的(GNU)連接器和它們的順序問題在一定程度上,但方式

我還看到了這種技巧不起作用並導致未定義引用的情況。

使用GNU鏈接器,這是因為確實缺少庫或對象,或者是因為靜態歸檔相對於其他對象文件或歸檔的順序不合適。 其他一些鏈接器更加敏感。

簡短的答案:

  1. -L-l選項提供了用於查找庫歸檔文件(和共享庫)的快捷方式。 但是,一旦使用-l定位了一個庫(在標准位置或-L指定的位置),該庫的讀取就與您指定其文件名(例如/lib/libx.a )在命令行上的同一位置。

  2. 當您指定單個對象( .o )文件時,該文件的全部內容將無條件加載。 當您指定一個庫歸檔文件( .a )文件時,僅加載其中必需的那些文件(以滿足未定義的未定義引用)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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