小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

技巧:Linux 動(dòng)態(tài)庫與靜態(tài)庫制作及使用詳解

 rookie 2012-06-27

兩個(gè)要知道的基本知識(shí)

Linux 應(yīng)用程序因?yàn)?Linux 版本的眾多與各自獨(dú)立性,在工程制作與使用中必須熟練掌握如下兩點(diǎn)才能有效地工作和理想地運(yùn)行。

  1. Linux 下標(biāo)準(zhǔn)庫鏈接的三種方式(全靜態(tài) , 半靜態(tài) (libgcc,libstdc++), 全動(dòng)態(tài))及其各自利弊。

  2. Linux 下如何巧妙構(gòu)建 achrive(*.a),并且如何設(shè)置鏈接選項(xiàng)來解決 gcc 比較特別的鏈接庫的順序問題。

三種標(biāo)準(zhǔn)庫鏈接方式選項(xiàng)及對比

為了演示三種不同的標(biāo)準(zhǔn)庫鏈接方式對最終應(yīng)用程序產(chǎn)生的區(qū)別, 這里用了一個(gè)經(jīng)典的示例應(yīng)用程序 HelloWorld 做演示,見 清單 1 HelloWorld。 整個(gè)工程可以在文章末尾下載。


清單 1. HelloWorld
				
 #include <stdio.h> 
 #include <iostream> 
 using std::cout; 
 using std::endl; 


 int main(int argc, char* argv[]) 
 { 
  printf("HelloWorld!(Printed by printf)\n"); 

  cout<<"HelloWorld!(Printed by cout)"<<endl; 

  return 0; 
 } 
   

三種標(biāo)準(zhǔn)庫鏈接方式的選項(xiàng)及區(qū)別見 表 1


表 1. 三種標(biāo)準(zhǔn)庫鏈接方式的選項(xiàng)及區(qū)別
標(biāo)準(zhǔn)庫連接方式示例連接選項(xiàng)優(yōu)點(diǎn)缺點(diǎn)
全靜態(tài)-static -pthread -lrt -ldl不會(huì)發(fā)生應(yīng)用程序在 不同 Linux 版本下的標(biāo)準(zhǔn)庫不兼容問題。生成的文件比較大,
應(yīng)用程序功能受限(不能調(diào)用動(dòng)態(tài)庫等)
全動(dòng)態(tài)-pthread -lrt -ldl生成文件是三者中最小的比較容易發(fā)生應(yīng)用程序在
不同 Linux 版本下標(biāo)準(zhǔn)庫依賴不兼容問題。
半靜態(tài) (libgcc,libstdc++)-static-libgcc -L. -pthread -lrt -ldl靈活度大,能夠針對不同的標(biāo)準(zhǔn)庫采取不同的鏈接策略,
從而避免不兼容問題發(fā)生。
結(jié)合了全靜態(tài)與全動(dòng)態(tài)兩種鏈接方式的優(yōu)點(diǎn)。
比較難識(shí)別哪些庫容易發(fā)生不兼容問題,
目前只有依靠經(jīng)驗(yàn)積累。
某些功能會(huì)因選擇的標(biāo)準(zhǔn)庫版本而喪失。

上述三種標(biāo)準(zhǔn)庫鏈接方式中,比較特殊的是 半靜態(tài)鏈接方式,主要在于其還需要在鏈接前增加額外的一個(gè)步驟:
ln -s `g++ -print-file-name=libstdc++.a`,作用是將 libstdc++.a(libstdc++ 的靜態(tài)庫)符號(hào)鏈接到本地工程鏈接目錄。
-print-file-name 在 gcc 中的解釋如下:
-print-file-name=<lib> Display the full path to library <lib>

為了區(qū)分三種不同的標(biāo)準(zhǔn)庫鏈接方式對最終生成的可執(zhí)行文件的影響,本文從兩個(gè)不同的維度進(jìn)行分析比較:

維度一:最終生成的可執(zhí)行文件對標(biāo)準(zhǔn)庫的依賴方式(使用 ldd 命令進(jìn)行分析)

ldd 簡介:該命令用于打印出某個(gè)應(yīng)用程序或者動(dòng)態(tài)庫所依賴的動(dòng)態(tài)庫
涉及語法:ldd [OPTION]... FILE...
其他詳細(xì)說明請參閱 man 說明。

三種標(biāo)準(zhǔn)庫鏈接方式最終產(chǎn)生的應(yīng)用程序的可執(zhí)行文件對于標(biāo)準(zhǔn)庫的依賴方式具體差異見 圖 1、圖 2、圖 3所示:


圖 1. 全靜態(tài)標(biāo)準(zhǔn)庫鏈接方式
全靜態(tài)標(biāo)準(zhǔn)庫鏈接方式

圖 2. 全動(dòng)態(tài)標(biāo)準(zhǔn)庫鏈接方式
全動(dòng)態(tài)標(biāo)準(zhǔn)庫鏈接方式

圖 3. 半靜態(tài)(libgcc,libstdc++) 標(biāo)準(zhǔn)庫鏈接方式
半靜態(tài)(libgcc,libstdc++) 標(biāo)準(zhǔn)庫鏈接方式


通過上述三圖,可以清楚的看到,當(dāng)用 全靜態(tài)標(biāo)準(zhǔn)庫的鏈接方式時(shí),所生成的可執(zhí)行文件最終不依賴任何的動(dòng)態(tài)標(biāo)準(zhǔn)庫,
全動(dòng)態(tài)標(biāo)準(zhǔn)庫的鏈接方式會(huì)導(dǎo)致最終應(yīng)用程序可執(zhí)行文件依賴于所有用到的標(biāo)準(zhǔn)動(dòng)態(tài)庫。
區(qū)別于上述兩種方式的 半靜態(tài)鏈接方式則有針對性的將 libgcc 和 libstdc++ 兩個(gè)標(biāo)準(zhǔn)庫非動(dòng)態(tài)鏈接。
(對比 圖 2圖 3,可見在 圖 3中這兩個(gè)標(biāo)準(zhǔn)庫的動(dòng)態(tài)依賴不見了)

從實(shí)際應(yīng)用當(dāng)中發(fā)現(xiàn),最理想的標(biāo)準(zhǔn)庫鏈接方式就是半靜態(tài)鏈接,通常會(huì)選擇將 libgcc 與 libstdc++ 這兩個(gè)標(biāo)準(zhǔn)庫靜態(tài)鏈接,
從而避免應(yīng)用程序在不同 Linux 版本間標(biāo)準(zhǔn)庫依賴不兼容的問題發(fā)生。

維度二 : 最終生成的可執(zhí)行文件大?。ㄊ褂?size 命令進(jìn)行分析)

size 簡介:該命令用于顯示出可執(zhí)行文件的大小
涉及語法:size objfile...
其他詳細(xì)說明請參閱 man 說明。

三種標(biāo)準(zhǔn)庫鏈接方式最終產(chǎn)生的應(yīng)用程序的可執(zhí)行文件的大小具體差異見 圖 4、圖 5圖 6所示:


圖 4. 全靜態(tài)標(biāo)準(zhǔn)庫鏈接方式
全靜態(tài)標(biāo)準(zhǔn)庫鏈接方式

圖 5. 全動(dòng)態(tài)標(biāo)準(zhǔn)庫鏈接方式
全動(dòng)態(tài)標(biāo)準(zhǔn)庫鏈接方式

圖 6. 半靜態(tài)(libgcc,libstdc++) 標(biāo)準(zhǔn)庫鏈接方式
半靜態(tài)(libgcc,libstdc++) 標(biāo)準(zhǔn)庫鏈接方式


通過上述三圖可以看出,最終可執(zhí)行文件的大小隨最終所依賴的標(biāo)準(zhǔn)動(dòng)態(tài)庫的數(shù)量增加而減小。
從實(shí)際應(yīng)用當(dāng)中發(fā)現(xiàn),最理想的是 半靜態(tài)鏈接方式,因?yàn)樵摲绞侥軌蛟诒苊鈶?yīng)用程序于
不同 Linux 版本間標(biāo)準(zhǔn)庫依賴不兼容的問題發(fā)生的同時(shí),使最終生成的可執(zhí)行文件大小最小化。

示例鏈接選項(xiàng)中所涉及命令(引用 GCC 原文):

-llibrary
-l library:指定所需要的額外庫
-Ldir:指定庫搜索路徑
-static:靜態(tài)鏈接所有庫
-static-libgcc:靜態(tài)鏈接 gcc 庫
-static-libstdc++:靜態(tài)鏈接 c++ 庫
關(guān)于上述命令的詳細(xì)說明,請參閱 GCC 技術(shù)手冊


Linux 下靜態(tài)庫(archive)的制作方式:

涉及命令:ar

ar 簡介:處理創(chuàng)建、修改、提取靜態(tài)庫的操作

涉及選項(xiàng):
t - 顯示靜態(tài)庫的內(nèi)容
r[ab][f][u] - 更新或增加新文件到靜態(tài)庫中
[s] - 創(chuàng)建文檔索引
ar -M [<mri-script] - 使用 ar 腳本處理
其他詳細(xì)說明請參閱 man 說明。

示例情景:

假設(shè)現(xiàn)有如 圖 7所示兩個(gè)庫文件


圖 7. 示例靜態(tài)庫文件
示例靜態(tài)庫文件

圖 7中可以得知,CdtLog.a 只包含 CdtLog.o 一個(gè)對象文件 , 而 xml.a 包含 TXmlParser.o 和 xmlparser.o 兩個(gè)對象文件
現(xiàn)將 CdtLog.o 提取出來,然后通過 圖 8方式創(chuàng)建一個(gè)新的靜態(tài)庫 demo.a,可以看出,demo.a 包含的是 CdtLog.o 以及 xml.a,
而不是我們所預(yù)期的 CdtLog.o,TXmlParser.o 和 xmlparser.o。這正是區(qū)別于 Windows 下靜態(tài)庫的制作。


圖 8. 示例靜態(tài)庫制作方式 1
示例靜態(tài)庫制作方式 1

這樣的 demo.a 當(dāng)被鏈接入某個(gè)工程時(shí),所有在 TXmlParser.o 和 xmlparser.o 定義的符號(hào)都不會(huì)被發(fā)現(xiàn),從而會(huì)導(dǎo)致鏈接錯(cuò)誤,
提示無法找到對應(yīng)的符號(hào)。顯然,通過圖 8 方式創(chuàng)建 Linux 靜態(tài)庫是不正確的。

正確的方式有兩種:

  1. 將所有靜態(tài)庫中包含的對象文件提取出來然后重新打包成新的靜態(tài)庫文件。

  2. 用一種更加靈活的方式創(chuàng)建新的靜態(tài)庫文件:ar 腳本

顯然,方式 1 是比較麻煩的,因?yàn)樯婕暗教嗟奈募幚?,可能還要通過不斷創(chuàng)建臨時(shí)目錄用于保存中間文件。
推薦使用如 清單 2 createlib.sh所示的 ar 腳本方式進(jìn)行創(chuàng)建:


清單 2 createlib.sh
				
 rm demo.a 
 rm ar.mac 
 echo CREATE demo.a > ar.mac 
 echo SAVE >> ar.mac 
 echo END >> ar.mac 
 ar -M < ar.mac 
 ar -q demo.a CdtLog.o 
 echo OPEN demo.a > ar.mac 
 echo ADDLIB xml.a >> ar.mac 
 echo SAVE >> ar.mac 
 echo END >> ar.mac 
 ar -M < ar.mac 
 rm ar.mac 
   

如果想在 Linux makefile 中使用 ar 腳本方式進(jìn)行靜態(tài)庫的創(chuàng)建,可以編寫如 清單 3 BUILD_LIBRARY所示的代碼:


清單 3 BUILD_LIBRARY
				
 define BUILD_LIBRARY 
 $(if $(wildcard $@),@$(RM) $@) 
 $(if $(wildcard ar.mac),@$(RM) ar.mac) 
 $(if $(filter %.a, $^), 
 @echo CREATE $@ > ar.mac 
 @echo SAVE >> ar.mac 
 @echo END >> ar.mac 
 @$(AR) -M < ar.mac 
 ) 
 $(if $(filter %.o,$^),@$(AR) -q $@ $(filter %.o, $^)) 
 $(if $(filter %.a, $^), 
 @echo OPEN $@ > ar.mac 
 $(foreach LIB, $(filter %.a, $^), 
 @echo ADDLIB $(LIB) >> ar.mac 
 ) 
 @echo SAVE >> ar.mac 
 @echo END >> ar.mac 
 @$(AR) -M < ar.mac 
 @$(RM) ar.mac 
 ) 
 endef 

 $(TargetDir)/$(TargetFileName):$(OBJS) 
    $(BUILD_LIBRARY) 
   

通過 圖 9,我們可以看到,用這種方式產(chǎn)生的 demo.a 才是我們想要的結(jié)果。


圖 9. 巧妙創(chuàng)建的靜態(tài)庫文件結(jié)果
巧妙創(chuàng)建的靜態(tài)庫文件結(jié)果

Linux 靜態(tài)庫鏈接順序問題及解決方法:

正如 GCC 手冊中提到的那樣:
It makes a difference where in the command you write this option; the linker
searches and processes libraries and object files in the order they are specified.
Thus, ‘ foo.o -lz bar.o ’ searches library ‘ z ’ after file ‘ foo.o ’ but before
‘ bar.o ’ . If ‘ bar.o ’ refers to functions in ‘ z ’ , those functions may not be loaded.

為了解決這種庫鏈接順序問題,我們需要增加一些鏈接選項(xiàng) :

$(CXX) $(LINKFLAGS) $(OBJS) -Xlinker "-(" $(LIBS) -Xlinker "-)" -o $@

通過將所有需要被鏈接的靜態(tài)庫放入 -Xlinker "-(" 與 -Xlinker "-)" 之間,可以是 g++ 鏈接過程中, 自動(dòng)循環(huán)鏈接所有靜態(tài)庫,從而解決了原本的鏈接順序問題。

涉及鏈接選項(xiàng):-Xlinker

-Xlinker option
Pass option as an option to the linker. You can use this to supply system-specific
linker options which GCC does not know how to recognize.


小結(jié)

本文介紹了 Linux 下三種標(biāo)準(zhǔn)庫鏈接的方式及各自利弊,同時(shí)還介紹了 Linux 下靜態(tài)庫的制作及使用方法,相信能夠給 大多數(shù)需要部署 Linux 應(yīng)用程序和編寫 Linux Makefile 的工程師提供有用的幫助。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多