成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C靜態(tài)庫連接的順序問題

開發(fā) 開發(fā)工具
C語言的靜態(tài)連接,簡單的說就是將編譯得到的目標(biāo)文件.o(.obj),打包在一起,并修改目標(biāo)文件中函數(shù)調(diào)用地址偏移量的過程。當(dāng)在大一點(diǎn)的項目中,可能會遇到連接時,由于靜態(tài)庫在鏈接器命令行中出現(xiàn)順序的問題,造成undefined reference錯誤。本文深入探討一下這個問題,以及如何解決。

C語言的靜態(tài)連接,簡單的說就是將編譯得到的目標(biāo)文件.o(.obj),打包在一起,并修改目標(biāo)文件中函數(shù)調(diào)用地址偏移量的過程。當(dāng)在大一點(diǎn)的項目中,可能會遇到連接時,由于靜態(tài)庫在鏈接器命令行中出現(xiàn)順序的問題,造成undefined reference錯誤。本文深入探討一下這個問題,以及如何解決。

問題

如下圖。假設(shè)有這么一個場景,在我們的構(gòu)建系統(tǒng)中,構(gòu)建了一個兩個靜態(tài)庫文件liba.a和libb.a,其中l(wèi)iba.a包含兩個目標(biāo)文件a1.o和a2.o,而libb.a包含一個目標(biāo)文件b1.o。希望將main.o靜態(tài)連接liba.a和libb.a。

注意到黃色的箭頭表示調(diào)用關(guān)系:b1.o需要調(diào)用a1.o中的某函數(shù),而main.o調(diào)用了a2.o和b1.o中的函數(shù)。你可以把.o文件理解為對應(yīng)的.c文件。

那么如下的兩個命令哪個會成功執(zhí)行呢?注意到這兩個命令唯一的區(qū)別是對liba.a和libb.a的書寫順序

  1. # gcc -o a.out main.o liba.a libb.a 
  2.  
  3. ...undefined reference... 
  4. error: ld returned 1 exit status  
  1. # gcc -o a.out main.o libb.a liba.a 

靜態(tài)連接的算法

要理解上面這個問題,需要理解鏈接器在處理靜態(tài)連接時候的算法。此處的闡述參考《深入理解計算機(jī)系統(tǒng)》中的“鏈接”章節(jié)。

首先,需要明確的是,鏈接器在考察庫文件(.a)的時候,不是把庫文件看做一個整體,而是將打包在其中的目標(biāo)文件(.o)作為考察單元。在整個連接過程中,如果某個目標(biāo)文件中的符號被用到了,那么這個目標(biāo)文件會單獨(dú)從庫文件中提取出來,而不會把整個庫文件連接進(jìn)來。

然后,鏈接器在工作過程中,維護(hù)3個集合:需要參與連接的目標(biāo)文件集合E、一個未解析符號集合U、一個在E中所有目標(biāo)文件定義過的所有符號集合D。

以上面第一條命令gcc -o a.out main.o liba.a libb.a為例,我們來一步步看看鏈接器的工作過程:

當(dāng)輸入main.o后,由于main調(diào)用了a2.o和b1.o中的函數(shù),而此時并沒有在D中找到該符號,于是將引用的兩個函數(shù)保存在U中,此處假設(shè)兩個函數(shù)分別為a2_func和b1_func: 

  1.         E               U               D          
  2. +---------------+---------------+---------------+ 
  3. |     main.o    |    a2_func    |               | 
  4. +---------------+---------------+---------------+ 
  5. |               |    b1_func    |               | 
  6. +---------------+---------------+---------------+ 

 接下來,輸入liba.a,鏈接器發(fā)現(xiàn),a2_func存在于liba.a的a2.o中,于是將a2.o加入到E,并在D中加入a2.o中所有定義的符號,其中包括a2_func,最后移除U中的a2_func,因為這個符號已經(jīng)在a2.o中找到了的。然而,U中還有b1_func,所以連接還沒有完成。 

  1.        E               U               D          
  2. +---------------+---------------+---------------+ 
  3. |     main.o    |               |    a2_func    | 
  4. +---------------+---------------+---------------+ 
  5. |     a2.o      |    b1_func    | a2_func_other | 
  6. +---------------+---------------+---------------+ 

 接著,輸入libb.a,同理,鏈接器發(fā)現(xiàn)b1_func定義在b1.o中,所以在E中加入b1.o,移除U中的b1_func,在D中加入b1.o里面所有定義的符號 

  1.         E               U               D          
  2. +---------------+---------------+---------------+ 
  3. |     main.o    |               |    a2_func    | 
  4. +---------------+---------------+---------------+ 
  5. |     a2.o      |               | a2_func_other | 
  6. +---------------+---------------+---------------+ 
  7. |     b1.o      |               |    b1_func    | 
  8. +---------------+---------------+---------------+ 

 然而,由于b1.o調(diào)用到a1.o中的函數(shù),我們假設(shè)是a1_func,但在D中并沒有找到這個函數(shù),所以a1_func還需要加入到U中 

  1.         E               U               D          
  2. +---------------+---------------+---------------+ 
  3. |     main.o    |               |    a2_func    | 
  4. +---------------+---------------+---------------+ 
  5. |     a2.o      |               | a2_func_other | 
  6. +---------------+---------------+---------------+ 
  7. |     b1.o      |    a1_func    |    b1_func    | 
  8. +---------------+---------------+---------------+ 

 但是,輸入結(jié)束了!鏈接器發(fā)現(xiàn)U中還有未解析的符號,所以報錯了!

可以看到由于鏈接器的算法實現(xiàn),導(dǎo)致a1.o并沒有被鏈接器考察,所以產(chǎn)生了未解析符號。仔細(xì)分析,可以知道,只要將liba.a和libb.a換一下順序,就可以鏈接成功!

解決辦法

一般來說有兩種辦法,一種是仔細(xì)分析依賴關(guān)系,并按照正確的順序書寫庫文件的引用。原則是被依賴的盡量寫在右邊。但是在有些大型項目中,依賴關(guān)系可能并不容易梳理清楚。此時可以在命令行參數(shù)中重復(fù)對庫文件的引用: 

  1. # gcc -o a.out main.o liba.la libb.la liba.a 

在上面的命令中,liba.a重復(fù)書寫了兩次。

如果你使用automake,可以用xxx_LIBADD和xxx_LDADD來控制目標(biāo)文件的引用關(guān)系:

  • xxx_LIBADD:對于目標(biāo)文件為庫文件或可執(zhí)行文件,需使用這個選項。表示在打包目標(biāo)庫文件的時候,就將依賴的文件一并打包進(jìn)來。
  • xxx_LDADD:對于可執(zhí)行文件可用這個選項,來控制鏈接器的參數(shù),如果你能分析清楚依賴關(guān)系,可以在這個選項中按照正確的順序書寫,從而成功連接。
責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2015-05-13 09:57:14

C++靜態(tài)庫與動態(tài)庫

2023-01-05 08:55:00

2021-07-11 06:45:18

Linux內(nèi)核靜態(tài)

2010-10-27 16:05:53

oracle查詢

2010-05-14 15:23:03

2023-10-07 15:53:05

C/C++靜態(tài)變量內(nèi)存

2009-08-12 14:23:01

C#連接MySql數(shù)據(jù)

2011-07-27 16:36:03

iphone Objective- 靜態(tài)庫

2011-06-29 17:00:26

QT 靜態(tài)編譯 Debug

2010-06-02 16:36:38

連接MySQL中文亂碼

2010-06-12 15:53:22

MySQL數(shù)據(jù)庫

2009-08-28 12:41:49

靜態(tài)方法與非靜態(tài)方法

2010-06-09 14:54:29

2009-08-18 11:23:11

2010-05-27 18:44:14

MySQL遠(yuǎn)程連接

2011-05-24 16:58:52

CC++

2010-02-03 11:01:18

C++類靜態(tài)成員初始化

2009-09-04 17:23:21

C#數(shù)據(jù)庫連接對象

2009-08-25 14:05:06

C#連接數(shù)據(jù)庫代碼

2010-01-18 18:04:28

靜態(tài)成員
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 五月天婷婷久久 | 一区在线免费视频 | 亚洲人人 | 精品一区二区免费视频 | 97av视频在线 | 午夜视频在线免费观看 | 国产成视频在线观看 | 午夜免费在线 | 日韩精品在线一区二区 | 久久日韩精品一区二区三区 | 亚洲色综合 | 一级片免费观看 | 777777777亚洲妇女 | 黑人精品欧美一区二区蜜桃 | 国产高清精品在线 | 亚洲精品99999| 一级片在线观看视频 | 国产精品激情小视频 | 四虎永久在线精品免费一区二 | 青青久草 | 欧美日韩久久精品 | 一区二区三区四区国产 | 精品国产一区二区三区性色 | 国产免费av在线 | 欧美午夜精品理论片a级按摩 | 午夜在线观看视频 | 欧美二区乱c黑人 | 一级毛片大全免费播放 | 成人二区| 狠狠操av| 欧美性大战xxxxx久久久 | 国产亚洲一区二区在线观看 | 日韩国产在线 | 狠狠干天天干 | 国产乱码精品一区二区三区中文 | 中文字幕成人网 | 国产在线视频一区二区 | 久久久久99 | 国产精品高潮呻吟久久av黑人 | 97avcc| 成人av网站在线观看 |