在《Python中擴展C語言加快執行速度的實現方法》中提到了在linux下經過GCC命令編譯生成動態連接庫的方法,同時咱們也能夠經過《Linux平臺上部署Mongoose服務器的方法介紹》中介紹的利用make工具解析makefile文件的編譯規則來更高效率的處理多個源文件,其實萬變不離其宗,makefile文件中仍然是以GCC命令調用編譯器來編譯源文件的,但對於開發者而言更加的簡單有效。linux
相信大多數開發者有在使用Eclipse軟件編輯代碼,但Eclipse並不只僅是一款編輯器,它是跨平臺的自由集成開發環境,經過各類插件能夠構建各類語言的開發環境。本文介紹在linux平臺上使用Eclipse工具編譯C工程生成靜態和動態連接庫方法。程序員
C/C++的編譯器不少,在Linux平臺上多數是以GCC爲主。GCC全稱爲GNU Compiler Collection,目前能夠編譯的語言包括:C,C++,Objective-C,Fortran,Java和Ada。GCC是GNU公社的一個項目,是一個用於編程開發的自由編譯器。最初,GCC只是一個C語言編譯器,它是GNU C Compiler 的英文縮寫。隨着衆多自由開發者的加入和GCC自身的發展,現在的GCC已是一個包含衆多語言的編譯器了。
(1)gcc命令語法格式爲選項和參數的結合:gcc [options] file1 file2...編程
經常使用選項包括: -E:只進行預處理,不編譯 -S:只編譯,不彙編 -c:只編譯、彙編,不連接 -g:包含調試信息 -I dir:在頭文件的搜索路徑列表中添加dir目錄 -L dir:在庫文件的搜索路徑列表中添加dir目錄 -v:打印編譯器內部編譯各過程的命令行信息和編譯器的版本號 -o:輸出成指定文件名 -O0:關閉全部優化選項 -O1:第一級別優化,使用此選項可以使可執行文件更小、運行更快,並不會增長太多編譯時間,能夠簡寫爲-O -O2:第二級別優化,採用了幾乎全部的優化技術,使用此選項會延長編譯時間 -O3:第三級別優化,在-O2的基礎上增長了產生inline函數、使用寄存器等優化技術 -Os:此選項相似於-O2,做用是優化所佔用的空間,但不會進行性能優化,經常使用於生成最終版本 -w:忽略全部警告 -Werror:不區分警告和錯誤,遇到任何警告都中止編譯 -Wall:開啓大部分警告提示注:gcc –o 和 gcc –c的區別。gcc –o是將.c源文件默認編譯鏈接生成一個可執行的二進制代碼(未加-c選項),輸出文件名稱由-o選項指定。該過程調用GCC的C編譯器(ccl),彙編器(as)和連接器(ld)。而gcc –c在將源文件轉化爲目標代碼以後結束,在這個過程當中只調用了C編譯器(ccl)和彙編器(as),而連接器(ld)並無被執行,目標代碼可在以後被鏈接到一個程序。segmentfault
經常使用參數包括: .c後綴文件——C語言源文件 .a後綴文件——由目標文件構成的檔案庫文件 .C或.cc或.cxx後綴文件——C++源文件 .h後綴文件——頭文件; .i 後綴文件——通過預處理的C源文件 .ii後綴文件——通過預處理的C++源文件 .m後綴文件——Objective-C源文件 .o後綴文件——編譯後的目標文件 .s後綴文件——彙編語言源碼文件 .S/.sx後綴文件——通過預編譯的彙編語言源碼文件
(2)經過GCC編譯的預處理(Preprocessing)、編譯(Compilation)、彙編(Assembly)、連接(Linking)4個階段來舉例說明GCC命令的使用。性能優化
根據連接時期的不一樣分爲靜態庫和動態庫兩種。靜態庫是在連接階段被鏈接至可執行文件中,所以即便庫被刪除了,程序依然能夠成功運行。而動態庫的連接是在程序執行的時候被鏈接的,在連接階段僅鏈接函數的引用,所以程序編譯完成後,須要將庫保留在系統中,供程序運行時調用。C的標準庫就是動態連接庫,系統中全部運行的程序共享着同一個C標準庫的代碼段。服務器
對於靜態連接庫來講,多個程序連接了同一個庫,那麼每個生成的可執行文件都會有這個庫的副本,雖然能夠避免程序在其餘系統上運行時缺乏相關庫文件,可是卻致使了系統空間的浪費。而動態連接庫直接在程序運行時被連接,程序的運行速度相比靜態連接庫會略有影響,卻大大的節省了系統的資源。另外當動態連接庫升級時無需像靜態連接庫那樣從新編譯連接其餘原有的代碼。編輯器
動態連接庫的後綴名爲.so,建立命令須要添加-fPIC標籤告訴編譯器相對跳轉、-shared標籤告訴編譯器創建動態連接庫。函數
命令gcc -shared -fPIC hello.c -o libhello.so
靜態庫的後綴名爲.a,文件名的命名規範爲libxxxx.a,lib爲前綴,xxxx爲lib的名稱。例如:建立的靜態庫名爲mystatic,則靜態庫文件名就是libmystatic.a。工具
關於在linux下經過GCC命令編譯生成動態連接庫的方法可參考《Python中擴展C語言加快執行速度的實現方法》一文,接下來本文詳細介紹下經過GCC命令編譯生成和鏈接靜態庫的方法。性能
(1).c源程序編譯成.o文件
gcc -c static_share.c
(2)ar命令將.o轉換成.a靜態庫
ar rcs libmystatic.a static_share.o ar:歸檔工具命令,把多個目標文件打包到一個歸檔文件中,每個目標文件都是歸檔文件的一個成員。 r:插入目標文件到歸檔文件中,若歸檔文件中已存在此目標文件,則替換。若歸檔文件中不存在此目標文件,則建立。 c:建立歸檔文件,即靜態連接庫。 s:寫入一個目標文件索引到歸檔文件中,或者更新已經存在的歸檔文件索引。對一個庫作ar s等同於對該庫作ranlib。randlib工具的做用爲對靜態庫的符號索引表進行更新。
注:ar rcs libmystatic.a static_share.c生成.a靜態庫,應用於連接時會出現報錯:./libmystatic.a: 沒法添加符號: 歸檔沒有索引;運行 ranlib 以添加一個collect2: error: ld returned 1 exit status。此處須要先生成.o目標文件,由.o文件生成靜態庫,不然沒法添加符號至符號表。
(3)連接靜態庫
使用靜態庫中函數時,須要在源程序中包含靜態庫的頭文件,然後使用GCC命令連接靜態庫生成可執行文件。
gcc -o test test.c -static -L. -lmystatic (-I/home/yuanxiao/static_share_test) -L:指定靜態庫的查找位置,.表示靜態庫在當前目錄下查找。Linux下庫文件默認的路徑爲/usr/lib/ -l:指定靜態庫名,因爲靜態庫的命名規則是以lib開頭且以.a結尾,gcc會在靜態庫名前加上前綴lib,而後追加擴展名.a後獲得的靜態庫文件名來查找靜態庫文件,所以如libmystatic.a的庫,只寫:-lmystatic便可。當多個靜態庫連接時每一個靜態庫名前都要加-l。 -static:-lmystatic 連接libhello.so 或者libhello.a庫文件, 當同時存在靜態庫和共享庫時共享庫文件優先,此時可使用-static強制使用靜態庫
注:include頭文件時< >引用的是系統指定路徑內的頭文件(linux下頭文件默認路徑爲/usr/include/)," "引用的是程序目錄的相對路徑中的頭文件,當編譯器在程序目錄的相對路徑中找不到該頭文件時會繼續在類庫路徑裏搜尋該頭文件。所以有時須要-I選項指定所須要的頭文件路徑。
(4)運行可執行文件
靜態連接庫中的函數已經連接到目標文件中,所以刪除靜態庫文件後程序仍然正常運行。
./test
(1)在Eclipse中創建新的C Project,選擇Shared Library,選擇Linux GCC。
注:因爲是Linux環境,選擇Linux GCC時Eclipse無需額外配置,編譯生成的目標文件基於X86-64。選擇Cross Gcc時須要配置prefix和path選項才能編譯成功。
(2)添加源文件。將源文件存於項目文件夾下,在項目上右擊選擇「refresh」直接更新至項目路徑下
(3)C/C++Build--->Setting--->Include下添加路徑信息後,GCC C Compiler下會同步顯示。
注:在GCC C Linker選項卡下,能夠發現手動建立動態連接庫時-shared選項。
(4)點擊工程Project,Build All完成編譯,能夠看到.so後綴文件。
注:此處有Debug和Release兩種編譯方式。Debug爲調試版本,包含調試信息,而且不做任何優化,便於程序員調試程序。Release爲發佈版本,每每進行了各類優化,使得程序在代碼大小和運行速度上都是最優的,以便用戶很好地使用。 能夠看到Debug方式編譯選項爲-O0,而 Release方式編譯選項爲-O3。
生成靜態連接庫時,將Project工程的Build Artifact選項配置爲Static Library生成類型。其他也參考動態連接庫的生成方法。
在GCC C Linker選項卡下,能夠發現手動建立靜態連接庫時ar命令。
點擊工程Project,Build All完成編譯,能夠看到.a後綴文件生成。
當一個Project工程須要連接靜態連接庫時,將Project的Build Artifact選項配置爲Excutable生成類型。
同時須要將添加靜態連接庫文件和頭文件路徑,使其包含至工程文件中。點擊工程Project,Build All完成編譯,能夠看到可執行文件生成。