天天看點

5.15 vs2019 靜态編譯_連結過程中靜态庫先後順序的影響分析

問題描述

項目中準備引入redis,采用acl的c++庫對redis進行通路。acl的示例代碼如下所示

#include 
           

對示例代碼進行編譯連結

`
           

報了許多連結的錯誤

(aio_listen_stream.o
           

問題分析

acl和acl_cpp均為靜态庫,acl是最基礎的庫,以C語言實作,其它庫均依賴于該庫; acl_cpp庫用C++封裝了acl庫,提供給C++程式調用。

連結錯誤集中表現為acl_cpp庫引用了acl庫中的函數但未能找到其定義。

問題解決

在編譯指令的參數中已給出了acl庫的路徑和名稱,不應該找不到。嘗試把acl_cpp庫在指令行中的順序放在acl庫之前

`
           

順利編譯通過。

原理探究

建立一個示例工程,包含main.c、comp1_func1.c、comp1_func2.c、comp2_func1.c四個檔案,其函數調用關系如下所示:

5.15 vs2019 靜态編譯_連結過程中靜态庫先後順序的影響分析
  • 編譯main.c
0000000000000000         *UND*  
           

main.o中有兩個未定義的符号:comp1_func1和comp2_func1

  • 編譯靜态庫
0000000000000000 g     F .text  000000000000000e comp1_func1

comp1_func2.o:     檔案格式 elf64-x86-64
           

libcomp2.a中有一個未定義的符号comp1_func2

  • 增量連結 将main.o和libcomp1.a先進行連結
0000000000000000 l    df *ABS*  
           

連結器并不是把靜态庫檔案看做一個整體,而是将打包在其中的目标檔案(.o)作為連結單元。在連結過程中,如果某個目标檔案中的符号被用到了,那麼這個目标檔案會單獨從庫檔案中提取出來并入可執行程式,而其餘的目标檔案則會被丢棄。

main.o中引用了libcomp1.a中comp1_func1.o的comp1_func1函數,是以将comp1_func1.o并入,而comp1_func2.o中的comp1_func2函數未被引用,是以被丢棄。

  • 全量連結 将main.o和libcomp1.a、libcomp2.a進行連結
0000000000000000         *UND*  
           

libcomp2.a中引用的comp1_func2函數雖然已在libcomp1.a中定義,但由于comp1_func2.o被丢棄,導緻該函數找不到定義

0000000000000021 g     F .text  000000000000000e comp1_func1
           

整個分析的過程可參考下圖:

5.15 vs2019 靜态編譯_連結過程中靜态庫先後順序的影響分析

将靜态庫的順序調換後,所有符号都找到了定義。是以在連結靜态庫的時候,應該将被依賴的庫放在最右邊。

繼續閱讀