gcc 編譯器參數

1、GCC編譯過程html

參考:http://hi.baidu.com/zengzhaonong/item/c00e079f500adccab625314f
-------------------------------------
    Pre-Processing   cpp        預處理
    Compiling        ccl        編譯
    Assembling       as         彙編
    Linking          ld         連接

    命令gcc首先調用cpp進行預處理,在預處理過程當中,對源代碼文件中的文件包含(#include)、預編譯語句(如宏定義#define等)進行分析。
    當全部的目標文件都生成以後,gcc就調用ld來完成最後的關鍵性工做,這個階段就是連接。在連接階段,全部的目標文件被安排在可執行程序中的恰當的位置,同時,該程序所調用到的庫函數也從各自所在的庫中連接到合適的地方。

ld -- The GNU linker
    -l LIBNAME, --library LIBNAME Search for library LIBNAME(默認狀況下會去連接動態共享庫,若是有-static參數時將會去靜態共享庫進行靜態連接)
    -static    Do not link against shared libraries(靜態連接共享庫). 

.c 爲後綴的文件,C語言源代碼文件;
.a 爲後綴的文件,是由目標文件構成的庫文件;
.C、 .cc或.cxx爲後綴的文件,是C++源代碼文件;
.h 爲後綴的文件,是程序所包含的頭文件;
.i 爲後綴的文件,是已經預處理過的C源代碼文件;
.ii爲後綴的文件,是已經預處理過的C++源代碼文件;
.m 爲後綴的文件,是Objective-C源代碼文件;
.o 爲後綴的文件,是編譯後的目標文件;
.s 爲後綴的文件,是彙編語言源代碼文件;
.S 爲後綴的文件,是通過預編譯的彙編語言源代碼文件。c++

2、經常使用命令git

參考:http://www.cnblogs.com/sunyubo/archive/2011/09/06/2282054.htmlweb

1. gcc -E source_file.c
-E,只執行到預編譯。直接輸出預編譯結果。

2. gcc -S source_file.c 
-S,只執行到源代碼到彙編代碼的轉換,輸出彙編代碼。

3. gcc -c source_file.c
-c,只執行到編譯,輸出目標文件。

4. gcc (-E/S/c/) source_file.c -o output_filename
-o, 指定輸出文件名,能夠配合以上三種標籤使用。
-o 參數能夠被省略。這種狀況下編譯器將使用如下默認名稱輸出:
-E:預編譯結果將被輸出到標準輸出端口(一般是顯示器)
-S:生成名爲source_file.s的彙編代碼
-c:生成名爲source_file.o的目標文件。
無標籤狀況:生成名爲a.out的可執行文件。

5. gcc -g source_file.c 
-g,生成供調試用的可執行文件,能夠在gdb中運行。因爲文件中包含了調試信息所以運行效率很低,且文件也大很多。
這裏能夠用strip命令從新將文件中debug信息刪除。這是會發現生成的文件甚至比正常編譯的輸出更小了,這是由於strip把原先正常編譯中的一些額外信息(如函數名之類)也刪除了。用法爲 strip a.out

6. gcc -s source_file.c
-s, 直接生成與運用strip一樣效果的可執行文件(刪除了全部符號信息)。

7. gcc -O source_file.c
-O(大寫的字母O),編譯器對代碼進行自動優化編譯,輸出效率更高的可執行文件。
-O 後面還能夠跟上數字指定優化級別,如:
gcc -O2 source_file.c
數字越大,越加優化。可是一般狀況下,自動的東西都不是太聰明,太大的優化級別可能會使生成的文件產生一系列的bug。通常可選擇2;3會有必定風險。

8. gcc -Wall source_file.c
-W,在編譯中開啓一些額外的警告(warning)信息。-Wall,將全部的警告信息全開。

9. gcc source_file.c -L/path/to/lib -lxxx -I/path/to/include
-l, 指定所使用到的函數庫,本例中連接器會嘗試連接名爲libxxx.a的函數庫。
-L,指定函數庫所在的文件夾,本例中連接器會嘗試搜索/path/to/lib文件夾。
-I, 指定頭文件所在的文件夾,本例中預編譯器會嘗試搜索/path/to/include文件夾。

有興趣的朋友能夠查看gcc的 manpage,找到更詳細的說明。
objective-c

 

3、選項編程

參考:http://www.cppblog.com/mydriverc/articles/33144.htmlwindows

 

-o 設定輸出文件名 
-c 只編譯,不鏈接. 
-E 只作預編譯. 
-pipe 在多個編譯過程之間使用管道. 
--version 顯示版本. 
-static 靜態鏈接. 
-ansi C 模式下支持全部 ISO C90 標準的 C 程序, C++ 模式下去除對 GNU C++ 擴展的支持(GNU擴展會與 ISO C++ 衝突) 
-std= 肯定編譯語言的標準,目前只在編譯 C 和 C++ 時有效 -fno-asm 不將 "asm" "inline" "typeof" 做爲關鍵字,能夠用他們作變量名等. -funsigned-char 將"char"的數據類型設爲"unsigned",即無符號. 
-fsigned-char 正好相反,將"char"設爲"signed". 
-fsyntax-only 只檢查語法錯誤,不作其餘任何事. 
-pedantic 顯示全部的 ISO C 和 ISO C++ 的警告,而且拒絕全部使用禁止擴展的程序 
-Wall 顯示全部警告 
-g 將編譯時的調試信息保存到本地文件中( stabs,COFF,XCOFF,DWARF) 
-ggdb 爲 GDB 產生調試信息,包含 GDB 的擴展. 
-ggdb(level) 設定產生何種等級的調試信息, level 爲 1-3, 1 最少,3 最多. 
-ftime-reprot 統計編譯消耗的時間並顯示報告. 
-fmem-report 顯示全部的靜態內存分配. 
-ftest-coverages 爲 gcov工具產生數據文件. 
gcc 編譯選項,翻譯出來用起來方便.瀏覽器

 

VC編譯選項(轉載)- -
Tag: 編程                                           
/***********************************************************************************************/
VC編譯選項 csdnb3a [原做]框架

 

關鍵字 VC編譯選項 出處 
-優化- 
/O1 最小化空間 minimize space 
/Op[-] 改善浮點數一致性 improve floating-pt consistency 
/O2 最大化速度 maximize speed 
/Os 優選代碼空間 favor code space 
/Oa 假設沒有別名 assume no aliasing 
/Ot 優選代碼速度 favor code speed 
/Ob 內聯展開(默認 n=0) inline expansion (default n=0) 
/Ow 假設交叉函數別名 assume cross-function aliasing 
/Od 禁用優化(默認值) disable optimizations (default) 
/Ox 最大化選項。(/Ogityb2 /Gs) maximum opts. (/Ogityb1 /Gs) 
/Og 啓用全局優化 enable global optimization 
/Oy[-] 啓用框架指針省略 enable frame pointer omission 
/Oi 啓用內建函數 enable intrinsic functions異步

 

-代碼生成- 
/G3 爲 80386 進行優化 optimize for 80386 
/G4 爲 80486 進行優化 optimize for 80486 
/GR[-] 啓用 C++ RTTI enable C++ RTTI 
/G5 爲 Pentium 進行優化 optimize for Pentium 
/G6 爲 Pentium Pro 進行優化 optimize for Pentium Pro 
/GX[-] 啓用 C++ 異常處理(與 /EHsc 相同) enable C++ EH (same as /EHsc) 
/EHs 啓用同步 C++ 異常處理 enable synchronous C++ EH 
/GD 爲 Windows DLL 進行優化 optimize for Windows DLL 
/GB 爲混合模型進行優化(默認) optimize for blended model (default) 
/EHa 啓用異步 C++ 異常處理 enable asynchronous C++ EH 
/Gd __cdecl 調用約定 __cdecl calling convention 
/EHc extern「C」默認爲 nothrow extern "C" defaults to nothrow 
/Gr __fastcall 調用約定 __fastcall calling convention 
/Gi[-] 啓用增量編譯 enable incremental compilation 
/Gz __stdcall 調用約定 __stdcall calling convention 
/Gm[-] 啓用最小從新生成 enable minimal rebuild 
/GA 爲 Windows 應用程序進行優化 optimize for Windows Application 
/Gf 啓用字符串池 enable string pooling 
/QIfdiv[-] 啓用 Pentium FDIV 修復 enable Pentium FDIV fix 
/GF 啓用只讀字符串池 enable read-only string pooling 
/QI0f[-] 啓用 Pentium 0x0f 修復 enable Pentium 0x0f fix 
/Gy 分隔連接器函數 separate functions for linker 
/GZ 啓用運行時調試檢查 enable runtime debug checks 
/Gh 啓用鉤子函數調用 enable hook function call 
/Ge 對全部函數強制堆棧檢查 force stack checking for all funcs 
/Gs[num] 禁用堆棧檢查調用 disable stack checking calls

 

-輸出文件- 
/Fa[file] 命名程序集列表文件 name assembly listing file 
/Fo 命名對象文件 name object file 
/FA[sc] 配置程序集列表 configure assembly listing 
/Fp 命名預編譯頭文件 name precompiled header file 
/Fd[file] 命名 .PDB 文件 name .PDB file 
/Fr[file] 命名源瀏覽器文件 name source browser file 
/Fe 命名可執行文件 name executable file 
/FR[file] 命名擴展 .SBR 文件 name extended .SBR file 
/Fm[file] 命名映射文件 name map file

 

-預處理器- 
/FI 命名強制包含文件 name forced include file 
/C 不吸收註釋 don't strip comments 
/U 移除預約義宏 remove predefined macro 
/D{=|#} 定義宏 define macro 
/u 移除全部預約義宏 remove all predefined macros 
/E 將預處理定向到標準輸出 preprocess to stdout 
/I 添加到包含文件的搜索路徑 add to include search path 
/EP 將預處理定向到標準輸出,不要帶行號 preprocess to stdout, no #line 
/X 忽略「標準位置」 ignore "standard places" 
/P 預處理到文件 preprocess to file

 

-語言- 
/Zi 啓用調試信息 enable debugging information 
/Zl 忽略 .OBJ 中的默認庫名 omit default library name in .OBJ 
/ZI 啓用調試信息的「編輯並繼續」功能 enable Edit and Continue debug info 
/Zg 生成函數原型 generate function prototypes 
/Z7 啓用舊式調試信息 enable old-style debug info 
/Zs 只進行語法檢查 syntax check only 
/Zd 僅要行號調試信息 line number debugging info only 
/vd{0|1} 禁用/啓用 vtordisp disable/enable vtordisp 
/Zp[n] 在 n 字節邊界上包裝結構 pack structs on n-byte boundary 
/vm 指向成員的指針類型 type of pointers to members 
/Za 禁用擴展(暗指 /Op) disable extensions (implies /Op) 
/noBool 禁用「bool」關鍵字 disable "bool" keyword 
/Ze 啓用擴展(默認) enable extensions (default)

 

- 雜項 - 
/?, /help 打印此幫助消息 print this help message 
/c 只編譯,不連接 compile only, no link 
/W 設置警告等級(默認 n=1) set warning level (default n=1) 
/H 最大化外部名稱長度 max external name length 
/J 默認 char 類型是 unsigned default char type is unsigned 
/nologo 取消顯示版權消息 suppress copyright message 
/WX 將警告視爲錯誤 treat warnings as errors 
/Tc 將文件編譯爲 .c compile file as .c 
/Yc[file] 建立 .PCH 文件 create .PCH file 
/Tp 將文件編譯爲 .cpp compile file as .cpp 
/Yd 將調試信息放在每一個 .OBJ 中 put debug info in every .OBJ 
/TC 將全部文件編譯爲 .c compile all files as .c 
/TP 將全部文件編譯爲 .cpp compile all files as .cpp 
/Yu[file] 使用 .PCH 文件 use .PCH file 
/V 設置版本字符串 set version string 
/YX[file] 自動的 .PCH 文件 automatic .PCH 
/w 禁用全部警告 disable all warnings 
/Zm 最大內存分配(默認爲 %) max memory alloc (% of default)

 

-連接- 
/MD 與 MSVCRT.LIB 連接 link with MSVCRT.LIB 
/MDd 與 MSVCRTD.LIB 調試庫連接 link with MSVCRTD.LIB debug lib 
/ML 與 LIBC.LIB 連接 link with LIBC.LIB 
/MLd 與 LIBCD.LIB 調試庫連接 link with LIBCD.LIB debug lib 
/MT 與 LIBCMT.LIB 連接 link with LIBCMT.LIB 
/MTd 與 LIBCMTD.LIB 調試庫連接 link with LIBCMTD.LIB debug lib 
/LD 建立 .DLL Create .DLL 
/F 設置堆棧大小 set stack size 
/LDd 建立 .DLL 調試庫 Create .DLL debug libary 
/link [連接器選項和庫] [linker options and libraries]

 4、編譯知識

參考:http://www.cnblogs.com/yc_sunniwell/archive/2010/07/22/1782678.html

1. gcc/g++在執行編譯工做的時候,總共須要4步

(1).預處理,生成.i的文件[預處理器cpp] 
(2).將預處理後的文件不轉換成彙編語言,生成文件.s[編譯器egcs] 
(3).有彙編變爲目標代碼(機器代碼)生成.o的文件[彙編器as] 
(4).鏈接目標代碼,生成可執行程序[連接器ld]

[參數詳解] 
-x language filename 
    設定文件所使用的語言,使後綴名無效,對之後的多個有效.也就是根據約定C語言的後綴名稱是.c的,而C++的後綴名是.C或者.cpp,若是你很個性,決定你的C代碼文件的後綴名是.pig 哈哈,那你就要用這參數,這個參數對他後面的文件名都起做用,除非到了下一個參數的使用。可使用的參數嗎有下面的這些 :
     `c', `objective-c', `c-header', `c++', `cpp-output', 
     `assembler', and `assembler-with-cpp'. 
   看到英文,應該能夠理解的。例子用法: gcc -x c hello.pig 
-x none filename 
  關掉上一個選項,也就是讓gcc根據文件名後綴,自動識別文件類型. 例子用法: gcc -x c hello.pig -x none hello2.c 
-c 
  只激活預處理,編譯,和彙編,也就是他只把程序作成obj文件.例子用法: gcc -c hello.c (他將生成.o的obj文件)

-S 
  只激活預處理和編譯,就是指把文件編譯成爲彙編代碼。例子用法: gcc -S hello.c (他將生成.s的彙編代碼,你能夠用文本編輯器察看 )

-E 
  只激活預處理,這個不生成文件,你須要把它重定向到一個輸出文件裏面.例子用法: gcc -E hello.c > pianoapan.txt 
  gcc -E hello.c | more (慢慢看吧,一個hello word 也要與處理成800行的代碼 )

-o 
  制定目標名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,若是你和我有同感,改掉它,哈哈 .例子用法 :
  gcc -o hello.exe hello.c (哦,windows用習慣了) 
  gcc -o hello.asm -S hello.c

-pipe 
  使用管道代替編譯中臨時文件,在使用非gnu彙編工具的時候,可能有些問題. 例子用法 :gcc -pipe -o hello.exe hello.c

-ansi 
  關閉gnu c中與ansi c不兼容的特性,激活ansi c的專有特性(包括禁止一些asm inline typeof關鍵字,以及UNIX,vax等預處理宏.)

-fno-asm 
  此選項實現ansi選項的功能的一部分,它禁止將asm,inline和typeof用做關鍵字。     
-fno-strict-prototype 
  只對g++起做用,使用這個選項,g++將對不帶參數的函數,都認爲是沒有顯式的對參數的個數和類型說明,而不是沒有參數. 
  而gcc不管是否使用這個參數,都將對沒有帶參數的函數,認爲城沒有顯式說明的類型 
-fthis-is-varialble 
  就是向傳統c++看齊,可使用this當通常變量使用. 
-fcond-mismatch 
  容許條件表達式的第二和第三參數類型不匹配,表達式的值將爲void類型 
-funsigned-char 
-fno-signed-char 
-fsigned-char 
-fno-unsigned-char 
    這四個參數是對char類型進行設置,決定將char類型設置成unsigned char(前兩個參數)或者 signed char(後兩個參數) 
-include file 
  包含某個代碼,簡單來講,就是便以某個文件,須要另外一個文件的時候,就能夠用它設定,功能就至關於在代碼中使用#include<filename> 
  例子用法: gcc hello.c -include /root/pianopan.h 
-imacros file 
  將file文件的宏,擴展到gcc/g++的輸入文件,宏定義自己並不出如今輸入文件中-Dmacro .至關於C語言中的#define macro 
-Dmacro=defn 
  至關於C語言中的#define macro=defn 
-Umacro 
  至關於C語言中的#undef macro

-undef 
  取消對任何非標準宏的定義 
-Idir 
  在你是用#include"file"的時候,gcc/g++會先在當前目錄查找你所制定的頭文件,若是沒有找到,他回到缺省的頭文件目錄找,若是使用-I制定了目錄,他回先在你所制定的目錄查找,而後再按常規的順序去找. 對於#include<file>,gcc/g++會到-I制定的目錄查找,查找不到,而後將到系統的缺省的頭文件目錄查找 .
-I- 
  就是取消前一個參數的功能,因此通常在-Idir以後使用  
-idirafter dir 
  在-I的目錄裏面查找失敗,講到這個目錄裏面查找.  
-iprefix prefix 
-iwithprefix dir 
  通常一塊兒使用,當-I的目錄查找失敗,會到prefix+dir下查找   
-nostdinc 
  使編譯器再也不繫統缺省的頭文件目錄裏面找頭文件,通常和-I聯合使用,明確限定頭文件的位置  
-nostdin C++ 
  規定不在g++指定的標準路經中搜索,但仍在其餘路徑中搜索,.此選項在建立libg++庫使用   
-C 
  在預處理的時候,不刪除註釋信息,通常和-E使用,有時候分析程序,用這個很方便的.
-M 
  生成文件關聯的信息。包含目標文件所依賴的全部源代碼.你能夠用gcc -M hello.c來測試一下,很簡單。   
-MM 
  和上面的那個同樣,可是它將忽略由#include<file>形成的依賴關係。  
-MD 
  和-M相同,可是輸出將導入到.d的文件裏面  
-MMD 
  和-MM相同,可是輸出將導入到.d的文件裏面  
-Wa,option 
  此選項傳遞option給彙編程序;若是option中間有逗號,就將option分紅多個選項,而後傳遞給會彙編程序  
-Wl.option 
  此選項傳遞option給鏈接程序;若是option中間有逗號,就將option分紅多個選項,而後傳遞給會鏈接程序.

-llibrary 
  制定編譯的時候使用的庫.例子用法 : gcc -lcurses hello.c (使用ncurses庫編譯程序 )
-Ldir 
  制定編譯的時候,搜索庫的路徑。好比你本身的庫,能夠用它制定目錄,否則編譯器將只在標準庫的目錄找。這個dir就是目錄的名稱。  
-O0 
-O1 
-O2 
-O3 
  編譯器的優化選項的4個級別,-O0表示沒有優化,-O1爲缺省值,-O3優化級別最高    
-g 
  只是編譯器,在編譯的時候,產生條是信息。  
-gstabs 
  此選項以stabs格式聲稱調試信息,可是不包括gdb調試信息.  
-gstabs+ 
  此選項以stabs格式聲稱調試信息,而且包含僅供gdb使用的額外調試信息.  
-ggdb 
  此選項將盡量的生成gdb的可使用的調試信息. 
-static 
  此選項將禁止使用動態庫,因此,編譯出來的東西,通常都很大,也不須要什麼動態鏈接庫,就能夠運行. 
-share 
  此選項將盡可能使用動態庫,因此生成文件比較小,可是須要系統由動態庫. 
-traditional 
  試圖讓編譯器支持傳統的C語言特性

2. 源文件爲main.c, x.c, y.c, z.c,頭文件爲x.h,y.h,z.h, 如何編譯成.so動態庫?

# 聲稱動代鏈接庫,假設名稱爲libtest.so
gcc x.c y.c z.c -fPIC -shared -o libtest.so

# 將main.c和動態鏈接庫進行鏈接生成可執行文件
gcc main.c -L. -ltest -o main

# 輸出LD_LIBRARY_PATH環境變量,一邊動態庫裝載器可以找到須要的動態庫
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

# 測試是否動態鏈接,若是列出libtest.so,那麼應該是鏈接正常了
ldd main

說明:

(1) -fPIC:表示編譯爲位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的因此動態載入時是經過代碼拷貝的方式來知足不一樣進程的須要,而不能達到真正代碼段共享的目的。

(2) -L.:表示要鏈接的庫在當前目錄中

(3) -ltest:編譯器查找動態鏈接庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so來肯定庫的名稱

(4) LD_LIBRARY_PATH:這個環境變量指示動態鏈接器能夠裝載動態庫的路徑。
    固然若是有root權限的話,能夠修改/etc/ld.so.conf文件,而後調用/sbin/ldconfig來達到一樣的目的,不過若是沒有root權限,那麼只能採用輸出LD_LIBRARY_PATH的方法了。

3. Linux下如何用GCC編譯動態庫

本文主要解決如下幾個問題

1) 爲何要使用庫?

2) 庫的分類

3) 建立本身的庫

    或許你們對本身初學 Linux時的情形仍記憶尤新吧。若是沒有一個能較好的解決依賴關係的包管理器,在Linux下安裝軟件將是一件及其痛苦的工做。你裝a包時,可能會提示你要先裝b包,當你費盡心力找到b包時,可能又會提示你要先安裝c包。我就曾被這樣的事搞的焦頭爛額,至今一提起rpm仍心有餘悸,頭皮發麻。說是一朝被蛇咬,十年怕井繩怕也不爲過。

    Linux下之因此有這許多的依賴關係,其中一個開發原則真是功不可沒。這個原則就是:儘可能不重複作別人已經作過的事。換句話說就是儘可能充分利用別人的勞動成果。

這就涉及到如何有效的進行代碼複用。

(1) 爲何要使用庫?

    關於代碼複用的途徑,通常有兩種。這是最沒有技術含量的一種方案。若是代碼小,則工做量還能夠忍受,若是代碼很龐大,則此法不可取。即使有人原意這樣作,但誰又能保證全部的代碼均可獲得呢?而庫的出現很好的解決了這個問題。庫,是一種封裝機制,簡單說把全部的源代碼編譯成目標代碼後打成的包。那麼用戶怎麼能知道這個庫提供什麼樣的接口呢?難道要用nm等工具逐個掃描?不用擔憂,庫的開發者早以把一切都作好了。除了包含目標代碼的庫外,www.Linuxidc.com通常還會提供一系列的頭文件,頭文件中就包含了庫的接口。爲了讓方便用戶,再加上一個使用說明就差很少完美了。

(2) 庫的分類

(2.1) 庫的分類

    根據連接時期的不一樣,庫又有靜態庫和動態庫之分。靜態庫是在連接階段被連接的(好像是廢話,但事實就是這樣),因此生成的可執行文件就不受庫的影響了,即便庫被刪除了,程序依然能夠成功運行。有別於靜態庫,動態庫的連接是在程序執行的時候被連接的。因此,即便程序編譯完,庫仍須保留在系統上,以供程序運行時調用。(TODO:連接動態庫時連接階段到底作了什麼)

(2.2) 靜態庫和動態庫的比較

    連接靜態庫其實從某種意義上來講也是一種粘貼複製,只不過它操做的對象是目標代碼而不是源碼而已。由於靜態庫被連接後庫就直接嵌入可執行文件中了,這樣就帶來了兩個問題。首先就是系統空間被浪費了。這是顯而易見的,想象一下,若是多個程序連接了同一個庫,則每個生成的可執行文件就都會有一個庫的副本,必然會浪費系統空間。再者,人非聖賢,即便是精心調試的庫,也不免會有錯。一旦發現了庫中有bug,挽救起來就比較麻煩了。必須一一把連接該庫的程序找出來,而後從新編譯。而動態庫的出現正彌補了靜態庫的以上弊端。由於動態庫是在程序運行時被連接的,因此磁盤上只須保留一份副本,所以節約了磁盤空間。若是發現了bug或要升級也很簡單,只要用新的庫把原來的替換掉就好了。那麼,是否是靜態庫就一無可取了呢?答曰:非也非也。不是有句話麼:存在便是合理。靜態庫既然沒有湮沒在滔滔的歷史長河中,就必然有它的用武之地。想象一下這樣的狀況:若是你用libpcap庫編了一個程序,要給被人運行,而他的系統上沒有裝pcap庫,該怎麼解決呢?最簡單的辦法就是編譯該程序時把全部要連接的庫都連接它們的靜態庫,這樣,就能夠在別人的系統上直接運行該程序了。

    所謂有得必有失,正由於動態庫在程序運行時被連接,故程序的運行速度和連接靜態庫的版本相比必然會打折扣。然而瑕不掩瑜,動態庫的不足相對於它帶來的好處在現今硬件下簡直是微不足道的,因此連接程序在連接時通常是優先連接動態庫的,除非用-static參數指定連接靜態庫。

(2.3) 如何判斷一個程序有沒有連接動態庫? 答案是用file實用程序。

    file程序是用來判斷文件類型的,在file命令下,全部文件都會原形畢露的。順便說一個技巧。有時在 windows下用瀏覽器下載tar.gz或tar.bz2文件,後綴名會變成奇怪的tar.tar,到Linux有些新手就不知怎麼解壓了。但 Linux下的文件類型並不受文件後綴名的影響,因此咱們能夠先用命令file xxx.tar.tar看一下文件類型,而後用tar加適當的參數解壓。

     另外,還能夠藉助程序ldd實用程序來判斷。ldd是用來打印目標程序(由命令行參數指定)所連接的全部動態庫的信息的,若是目標程序沒有連接動態庫,則打印「not a dynamic executable」,ldd的用法請參考manpage。

(3) 建立本身的庫

(3.1) 建立動態庫

    建立文件hello.c,內容以下:

#include

void hello(void)

{

printf("Hello World\n");

}

    用命令gcc -shared hello.c -o libhello.so編譯爲動態庫。能夠看到,當前目錄下多了一個文件libhello.so。

[leo@leo test]$ file libhello.so

libhello.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

    看到了吧,文件類型是shared object了。再編輯一個測試文件test.c,內容以下:

int main()

{

hello();

return 0;

}

    這下能夠編譯了:)

[leo@leo test]$ gcc test.c

/tmp/ccm7w6Mn.o: In function `main':

test.c:(.text+0x1d): undefined reference to `hello'

collect2: ld returned 1 exit status

    連接時gcc找不到hello函數,編譯失敗:(。緣由是hello在咱們本身建立的庫中,若是gcc能找到那才教見鬼呢!ok,再接再礪。

[leo@leo test]$ gcc test.c -lhello

/usr/lib/gcc/i686-pc-Linux-gnu/4.0.0/http://www.cnblogs.com/http://www.cnblogs.com/i686-pc-Linux-gnu/bin/ld: cannot find -lhello

collect2: ld returned 1 exit status

[leo@leo test]$ gcc test.c -lhello -L.

[leo@leo test]$

    第一次編譯直接編譯,gcc默認會連接標準c庫,但符號名hello解析不出來,故鏈接階段通不過了。如今用gcc test.c -lhello -L.已經編譯成功了,默認輸出爲a.out。如今來試着運行一下:

[leo@leo test]$ ./a.out

./a.out: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

咦,怎麼回事?原來雖然連接時連接器(dynamic linker)找到了動態庫libhello.so,但動態加載器(dynamic loader, 通常是/lib/ld-Linux.so.2)卻沒找到。再來看看ldd的輸出:

[leo@leo test]$ ldd a.out

Linux-gate.so.1 => (0xffffe000)

libhello.so => not found

libc.so.6 => /lib/libc.so.6 (0x40034000)

/lib/ld-Linux.so.2 (0x40000000)

    果真如此,看到沒有,libhello.so => not found。Linux爲咱們提供了兩種解決方法:

1).能夠把當前路徑加入 /etc/ld.so.conf中而後運行ldconfig,或者以當前路徑爲參數運行ldconfig(要有root權限才行)。

2).把當前路徑加入環境變量LD_LIBRARY_PATH中

    固然,若是你以爲不會引發混亂的話,能夠直接把該庫拷入/lib,/usr/lib/等位置(無可避免,這樣作也要有權限),這樣連接器和加載器就均可以準確的找到該庫了。咱們採用第二種方法:

[leo@leo test]$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

 [leo@leo test]$ ldd a.out

Linux-gate.so.1 => (0xffffe000)

libhello.so => ./libhello.so (0x4001f000)

libc.so.6 => /lib/libc.so.6 (0x40036000)

/lib/ld-Linux.so.2 (0x40000000)

    哈哈,這下ld-Linux.so.2就能夠找到libhello.so這個庫了。如今能夠直接運行了:

[leo@leo test]$ ./a.out

Hello World

(3.2) 建立靜態庫

    仍使用剛纔的hello.c和test.c。第一步,生成目標文件。

[leo@leo test]$ gcc -c hello.c

[leo@leo test]$ ls hello.o -l

-rw-r--r-- 1 leo users 840 5月 6 12:48 hello.o

    第二步,把目標文件歸檔。

[leo@leo test]$ ar r libhello.a hello.o

ar: creating libhello.a

OK,libhello.a就是咱們所建立的靜態庫了,簡單吧:)

[leo@leo test]$ file libhello.a

libhello.a: current ar archive

    下面一行命令就是教你如何在程序中連接靜態庫的:

[leo@leo test]$ gcc test.c -lhello -L. -static -o hello.static

    咱們來用file命令比較一下用動態庫和靜態庫連接的程序的區別:

[leo@leo test]$ gcc test.c -lhello -L. -o hello.dynamic

    正如前面所說,連接器默認會連接動態庫(這裏是libhello.so),因此只要把上個命令中的 -static參數去掉就能夠了。用file實用程序驗證一下是否按咱們的要求生成了可執行文件:

[leo@leo test]$ file hello.static hello.dynamic

hello.static: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.6, statically linked, not stripped

hello.dynamic: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.6, dynamically linked (uses shared libs), not stripped

    不妨順便練習一下ldd的用法:

[leo@leo test]$ ldd hello.static hello.dynamic

hello.static:

not a dynamic executable

hello.dynamic:

Linux-gate.so.1 => (0xffffe000)

libhello.so => ./libhello.so (0x4001f000)

libc.so.6 => /lib/libc.so.6 (0x40034000)

/lib/ld-Linux.so.2 (0x40000000)

    OK,看來沒有問題,那就比較一下大小先:

[leo@leo test]$ ls -l hello.[ds]*

-rwxr-xr-x 1 leo users 5911 5月 6 12:54 hello.dynamic

-rwxr-xr-x 1 leo users 628182 5月 6 12:54 hello.static

    看到區別了吧,連接靜態庫的目標程序和連接動態庫的程序比起來簡直就是一個龐然大物!這麼小的程序,很難看出執行時間的差異,不過爲了完整起見,仍是看一下time的輸出吧:

[leo@leo test]$ time ./hello.static

Hello World

real 0m0.001s

user 0m0.000s

sys 0m0.001s

[leo@leo test]$ time ./hello.dynamic

Hello World

real 0m0.001s

user 0m0.000s

sys 0m0.001s

    若是程序比較大的話,應該效果會很明顯的。

相關文章
相關標籤/搜索