參考:《GNU gcc嵌入式系統(tǒng)開發(fā) 作者:董文軍》 (一) gcc的基本用法 (二) 警告提示功能選項 (三) 庫操作選項 (四) 調(diào)試選項 (五) 交叉編譯選項 (一) gcc的基本用法 使用gcc編譯器時,必須給出一系列必要的調(diào)用參數(shù)和文件名稱。不同參數(shù)的先后順序?qū)?zhí)行結(jié)果沒有影響,只有在使用同類參數(shù)時的先后順序才需要考慮。如果使用了多個 -L 的參數(shù)來定義庫目錄,gcc會根據(jù)多個 -L 參數(shù)的先后順序來執(zhí)行相應(yīng)的庫目錄。 因為很多gcc參數(shù)都由多個字母組成,所以gcc參數(shù)不支持單字母的組合,Linux中常被叫短參數(shù)(short options),如 -dr 與 -d -r 的含義不一樣。gcc編譯器的調(diào)用參數(shù)大約有100多個,其中多數(shù)參數(shù)我們可能根本就用不到,這里只介紹其中最基本、最常用的參數(shù)。 gcc最基本的用法是:gcc [options] [filenames] 其中,options就是編譯器所需要的參數(shù),filenames給出相關(guān)的文件名稱,最常用的有以下參數(shù): -c 只編譯,不鏈接成為可執(zhí)行文件。編譯器只是由輸入的 .c 等源代碼文件生成 .o 為后綴的目標(biāo)文件,通常用于編譯不包含主程序的子程序文件。 -o output_filename 確定輸出文件的名稱為output_filename。同時這個名稱不能和源文件同名。如果不給出這個選項,gcc就給出默認(rèn)的可執(zhí)行文件 a.out 。 -g 產(chǎn)生符號調(diào)試工具(GNU的 gdb)所必要的符號信息。想要對源代碼進行調(diào)試,就必須加入這個選項。 -O 對程序進行優(yōu)化編譯、鏈接。采用這個選項,整個源代碼會在編譯、鏈接過程中進行優(yōu)化處理,這樣產(chǎn)生的可執(zhí)行文件的執(zhí)行效率可以提高,但是編譯、鏈接的速度就相應(yīng)地要慢一些,而且對執(zhí)行文件的調(diào)試會產(chǎn)生一定的影響,造成一些執(zhí)行效果與對應(yīng)源文件代碼不一致等一些令人“困惑”的情況。因此,一般在編譯輸出軟件發(fā)行版時使用此選項。 -O2 比 -O 更好的優(yōu)化編譯、鏈接。當(dāng)然整個編譯鏈接過程會更慢。 -Idirname 將 dirname 所指出的目錄加入到程序頭文件目錄列表中,是在預(yù)編譯過程中使用的參數(shù)。 說明: C程序中的頭文件包含兩種情況: #include #include "stdio.h" 其中,使用尖括號(<>),預(yù)處理程序 cpp 在系統(tǒng)默認(rèn)包含文件目錄(如/usr/include)中搜索相應(yīng)的文件;使用雙引號,預(yù)處理程序 cpp 首先在當(dāng)前目錄中搜尋頭文件,如果沒有找到,就到指定的 dirname 目錄中去尋找。 在程序設(shè)計中,如果需要的這種包含文件分別分布在不同的目錄中,就需要逐個使用 -I 選項給出搜索路徑。 -Ldirname 將dirname所指出的目錄加入到程序函數(shù)庫文件的目錄列表中,是在鏈接過程中使用的參數(shù)。在默認(rèn)狀態(tài)下,鏈接程序 ld 在系統(tǒng)默認(rèn)路徑中(如 /usr/lib)尋找所需要的庫文件。這個選項告訴鏈接程序,首先到 -L 指定的目錄中去尋找,然后到系統(tǒng)默認(rèn)路徑中尋找;如果函數(shù)庫存放在多個目錄下,就需要依次使用這個選項,給出相應(yīng)的存放目錄。 -lname 鏈接時裝載名為 libname.a 的函數(shù)庫。該函數(shù)庫位于系統(tǒng)默認(rèn)的目錄或者由 -L 選項確定的目錄下。例如,-lm 表示鏈接名為 libm.a 的數(shù)學(xué)函數(shù)庫。 例子:假定有一個程序名為 test.c 的C語言源代碼文件,要生成一個可執(zhí)行文件。 #include int main(void) { printf("Hello world/n"); return 0; } 最簡單的辦法:gcc test.c -o test 首先,gcc需要調(diào)用預(yù)處理程序 cpp,由它負責(zé)展開在源文件中定義的宏,并向其中插入“#include”語句所包含的內(nèi)容;接著,gcc調(diào)用ccl 和 as,將處理后的源代碼編譯成目標(biāo)代碼;最后,gcc調(diào)用鏈接程序 ld,把生成的目標(biāo)代碼鏈接成一個可執(zhí)行程序。因此,默認(rèn)情況下,預(yù)編譯、編譯鏈接一次完成。 編譯過程的分步執(zhí)行: 為了更好地理解gcc的工作過程,我們可以讓在gcc工作的4個階段中的任何一個階段中停止下來。相關(guān)的參數(shù)有: -E 預(yù)編譯后停下來,生成后綴為 .i 的預(yù)編譯文件。 -c 編譯后停下來,生成后綴為 .o 的目標(biāo)文件。 -S 匯編后停下來,生成后綴為 .s 的匯編源文件。 第一步:進行預(yù)編譯,使用 -E 參數(shù) gcc -E test.c -o test.i 查看 test.i 文件中的內(nèi)容,會發(fā)現(xiàn) stdio.h 的內(nèi)容確實都插到文件里去了,而其他應(yīng)當(dāng)被預(yù)處理的宏定義也都做了相應(yīng)的處理。 第二步:將 test.i 編譯為目標(biāo)代碼,使用 -c 參數(shù) gcc -c test.c -o test.o 第三步:生成匯編源文件 gcc -S test.c -o test.s 第四步:將生成的目標(biāo)文件鏈接成可執(zhí)行文件 gcc test.o - o test 對于稍微復(fù)雜的情況,比如有多個源代碼文件、需要鏈接庫或有其他比較特別的要求,就要給定適當(dāng)?shù)恼{(diào)用選項參數(shù)。 例子:整個源代碼程序由兩個文件 testmain.c 和 testsub.c 組成,程序中使用了系統(tǒng)提供的數(shù)學(xué)庫(所有與浮點相關(guān)的數(shù)學(xué)運算都必須使用數(shù)學(xué)庫)。 gcc testmain.c testsub.c -lm -o test 其中,-lm 表示鏈接系統(tǒng)的數(shù)學(xué)庫 libm.a 。 說明: 在編譯一個包含許多源文件的工程時,若只用一條gcc命令來完成編譯是非常浪費時間的。假如項目中有100個源文件需要編譯,并且每個源文件中都包含一萬行代碼,如果像上面那樣僅用一條gcc命令來完成編譯工作,那么gcc需要將每個源文件都重新編譯一遍,然后再全部鏈接起來。很顯然,這樣浪費的時間相當(dāng)多,尤其是當(dāng)用戶只是修改了其中某個文件的時候,完全沒有必要將每個文件都重新編譯一遍,因為很多已經(jīng)生成的目標(biāo)文件是不會發(fā)生改變的。要解決這個問題,需要借助像make這樣的工具。 (二) 警告提示功能選項 gcc包含完整的出錯檢查和警告提示功能,它們可以幫助Linux程序員寫出更加專業(yè)的代碼。 (1) -pedantic 選項 當(dāng)gcc在編譯不符合ANSI/ISO C 語言標(biāo)準(zhǔn)的源代碼時,將產(chǎn)生相應(yīng)的警告信息。 [cpp] view plain copy print? #include void main(void) { long long int var = 1; printf("It is not standard C code!/n"); } 它有以下問題: > main 函數(shù)的返回值被聲明為 void,但實際上應(yīng)該是 int。 > 使用了 GNU 語法擴展,即使用 long long 來聲明64位整數(shù),不符合 ANSI/ISO C 語言標(biāo)準(zhǔn)。 > main 函數(shù)在終止前沒有調(diào)用 return 語句。 (2) -Wall 選項 除了 -pedantic 之外,gcc 還有一些其他編譯選項,也能夠產(chǎn)生有用的警告信息。這些選項大多以 -W 開頭。其中最有價值的當(dāng)數(shù) -Wall 了,使用它能夠使 gcc 產(chǎn)生盡可能多的警告信息。 gcc 給出的警告信息雖然從嚴(yán)格意義上說不能算作錯誤,但卻和可能成為錯誤來源。一個優(yōu)秀的程序員應(yīng)該盡量避免產(chǎn)生警告信息,使自己的代碼始終保持簡潔、優(yōu)美和健壯的特性。 建議:gcc 給出的警告信息是很有價值的,它們不僅可以幫助程序員寫出更加健壯的程序,而且還是跟蹤和調(diào)試程序的有力工具。建議在用 gcc 編譯源代碼時始終帶上 -Wall 選項,并把它逐漸培養(yǎng)成一種習(xí)慣,這對找出常見的隱式編程錯誤很有幫助。 (3) -Werror 選項 在處理警告方面,另一個常用的編譯選項是 -Werror。它要求 gcc 將所有的警告當(dāng)成錯誤進行處理,這在使用自動編譯工具(如 Make 等)時非常有用。如果編譯時帶上 -Werror 選項,那么 gcc 會在所有產(chǎn)生警告的地方停止編譯,迫使程序員對自己的代碼進行修改。只有當(dāng)相應(yīng)的警告信息消除時,才可能將編譯過程繼續(xù)朝前推進。 (4) -Wcast-align 選項 當(dāng)源程序中地址不需要對齊的指針指向一個地址需要對齊的變量地址時,則產(chǎn)生一個警告。例如,char * 指向一個 int * 地址,而通常在機器中 int 變量類型是需要地址能被2或4整除的對齊地址。 (5) 其他常用選項 -v 輸出 gcc 工作的詳細過程 --target-help 顯示目前所用的gcc支持CPU類型 -Q 顯示編譯過程的統(tǒng)計數(shù)據(jù)和每一個函數(shù)名 (三) 庫操作選項 在Linux下開發(fā)軟件時,完全不使用第三方函數(shù)庫的情況是比較少見的,通常來講都需要借助一個或多個函數(shù)庫的支持才能夠完成相應(yīng)的功能。 從程序員的角度看,函數(shù)庫實際上就是一些頭文件(.h)和庫文件(.so 或 .a)的集合。雖然Linux下的大多數(shù)函數(shù)都默認(rèn)將頭文件放到 /usr/include/ 目錄下,而庫文件則放到 /usr/lib/ 目錄下,但并不是所有的情況都是這樣。正因如此,gcc 在編譯時必須有自己的辦法來查找所需要的頭文件和庫文件。常用的方法有: (1) -I 可以向 gcc 的頭文件搜索路徑中添加新的目錄。 (2) -L 如果使用了不在標(biāo)準(zhǔn)位置的庫文件,那么可以通過 -L 選項向 gcc 的庫文件搜索路徑中添加新的目錄。 (3) -l Linux下的庫文件在命名時有一個約定,就是應(yīng)該以 lib 這3個字母開頭,由于所有的庫文件都遵循了同樣的規(guī)范,因此在用 -l 選項指定鏈接的庫文件名時可以省去 lib 這3個字母。例如,gcc 在對 -lfoo 進行處理時,會自動去鏈接名為 libfoo.so 的文件。 (4) -static Linux下的庫文件分為兩大類,分別是:動態(tài)鏈接庫(通常以 .so 結(jié)尾)和靜態(tài)鏈接庫(通常以 .a 結(jié)尾)。 兩者的差別僅在程序執(zhí)行時所需的代碼是在運行時動態(tài)加載的,還是在編譯時靜態(tài)加載的。 默認(rèn)情況下,gcc 在鏈接時優(yōu)先使用動態(tài)鏈接庫,只有當(dāng)動態(tài)鏈接庫不存在時才考慮使用靜態(tài)鏈接庫。 如果需要的話,可以在編譯時加上 -static 選項,強制使用靜態(tài)鏈接庫。 (5) -shared 生成一個共享的目標(biāo)文件,它能夠與其他的目標(biāo)一起鏈接生成一個可執(zhí)行的文件。 (四) 調(diào)試選項 對于Linux程序員來講,gdb(GNU Debugger)通過與 gcc 的配合使用,為基于Linux的軟件開發(fā)提供了一個完善的調(diào)試環(huán)境。常用的有: (1) -g 和 -ggdb 默認(rèn)情況下,gcc 在編譯時不會將調(diào)試符號插入到生成的二進制代碼中,因為這樣會增加可執(zhí)行文件的大小。如果需要在編譯時生成調(diào)試符號信息,可以使用 gcc 的 -g 或 -ggdb 選項。 gcc 在產(chǎn)生調(diào)試符號時,同樣采用了分級的思路,開發(fā)人員可以通過在 -g 選項后附加數(shù)字1、2、3指定在代碼中加入調(diào)試信息的多少。默認(rèn)的級別是2(-g2),此時產(chǎn)生的調(diào)試信息包括:擴展的符號表、行號、局部或外部變量信息。 級別3(-g3)包含級別2中的所有調(diào)試信息以及源代碼中定義的宏。 級別1(-g1)不包含局部變量和與行號有關(guān)的調(diào)試信息,因此只能夠用于回溯跟蹤和堆棧轉(zhuǎn)儲。 回溯追蹤:指的是監(jiān)視程序在運行過程中函數(shù)調(diào)用歷史。 堆棧轉(zhuǎn)儲:則是一種以原始的十六進制格式保存程序執(zhí)行環(huán)境的方法。 注意:使用任何一個調(diào)試選項都會使最終生成的二進制文件的大小急劇增加,同時增加程序在執(zhí)行時的開銷,因此,調(diào)試選項通常僅在軟件的開發(fā)和調(diào)試階段使用。 (2) -p 和 -pg 會將剖析(Profiling)信息加入到最終生成的二進制代碼中。剖析信息對于找出程序的性能瓶頸很有幫助,是協(xié)助Linux程序員開發(fā)出高性能程序的有力工具。 (3) -save-temps 保存編譯過程中生成的一些列中間文件。 # gcc test.c -o test -save-temps 除了生成執(zhí)行文件test之外,還保存了test.i 和 test.s 中間文件,供用戶查詢調(diào)試。 (五) 交叉編譯選項 通常情況下使用 gcc 編譯的目標(biāo)代碼都與使用的機器是一致的,但 gcc 也支持交叉編譯的功能,能夠編譯其他不同CPU的目標(biāo)代碼。 使用 gcc 開發(fā)嵌入式系統(tǒng),我們幾乎都是以通用的PC機(X86)平臺來做宿主機,通過 gcc 的交叉編譯功能對其他嵌入式CPU的開發(fā)任務(wù)。 (具體的選項設(shè)置,此處省略) GCC常用參數(shù)詳解 簡介 gcc and g++現(xiàn)在是gnu中最主要和最流行的c & c++編譯器 .gcc/g++在執(zhí)行編譯工作的時候,總共需要以下幾步: 1.預(yù)處理,生成.i的文件[預(yù)處理器cpp] 2.將預(yù)處理后的文件不轉(zhuǎn)換成匯編語言,生成文件.s[編譯器egcs] 3.有匯編變?yōu)槟繕?biāo)代碼(機器代碼)生成.o的文件[匯編器as] 4.連接目標(biāo)代碼,生成可執(zhí)行程序[鏈接器ld] GCC能夠處理的后綴有: a. *.c *.C (C語言) b. *.cxx *.cc (C++語言) c. *.m (面向?qū)ο蟮腃) d. *.i (預(yù)處理后的C語言源文件) e. *.ii (預(yù)處理后的C++語言源文件) f. *.s *.S (匯編語言) h. *.h (頭文件) 目標(biāo)文件可以是: a. *.o 編譯連接后的目標(biāo)文件 b. *.a 庫文件 gcc與g++有什么區(qū)別? gcc和g++都是GNU(組織)的一個編譯器。 誤區(qū)一:gcc只能編譯c代碼,g++只能編譯c++代碼 兩者都可以,但是請注意: 1.后綴為.c的,gcc把它當(dāng)作是C程序,而g++當(dāng)作是c++程序;后綴為.cpp的,兩者都會認(rèn)為是c++程序,注意,雖然c++是c的超集,但是兩者對語法的要求是有區(qū)別的。C++的語法規(guī)則更加嚴(yán)謹(jǐn)一些。 2.編譯階段,g++會調(diào)用gcc,對于c++代碼,兩者是等價的,但是因為gcc命令不能自動和C++程序使用的庫聯(lián)接,所以通常用g++來完成鏈接,為了統(tǒng)一起見,干脆編譯/鏈接統(tǒng)統(tǒng)用g++了,這就給人一種錯覺,好像cpp程序只能用g++似的。 誤區(qū)二:gcc不會定義__cplusplus宏,而g++會 實際上,這個宏只是標(biāo)志著編譯器將會把代碼按C還是C++語法來解釋,如上所述,如果后綴為.c,并且采用gcc編譯器,則該宏就是未定義的,否則,就是已定義。 誤區(qū)三:編譯只能用gcc,鏈接只能用g++ 嚴(yán)格來說,這句話不算錯誤,但是它混淆了概念,應(yīng)該這樣說:編譯可以用gcc/g++,而鏈接可以用g++或者gcc -lstdc++。因為gcc命令不能自動和C++程序使用的庫聯(lián)接,所以通常使用g++來完成聯(lián)接。但在編譯階段,g++會自動調(diào)用gcc,二者等價。 參數(shù)詳解 無選項編譯鏈接 將test.c預(yù)處理、匯編、編譯并鏈接形成可執(zhí)行文件。這里未指定輸出文件,默認(rèn)輸出為a.out。 例子用法: gcc test.c 無選項鏈接 gcc test.o -o test 將編譯輸出文件test.o鏈接成最終可執(zhí)行文件test。 -x language filename 設(shè)定文件所使用的語言,使后綴名無效,對以后的多個有效.也就是根據(jù)約定C語言的后綴名稱是.c的,而C++的后綴名是.C或者.cpp,如果你很個性, 決定你的C代碼文件的后綴名是.pig 哈哈,那你就要用這個參數(shù),這個參數(shù)對他后面的文件名都起作用,除非到了下一個參數(shù)的使用。 可以使用的參數(shù)嗎有下面的這些 `c', `objective-c', `c-header', `c++', `cpp-output', `assembler', and `assembler-with-cpp'. 看到英文,應(yīng)該可以理解的。 例子用法: gcc -x c hello.pig -x none filename 關(guān)掉上一個選項,也就是讓gcc根據(jù)文件名后綴,自動識別文件類型 例子用法: gcc -x c hello.pig -x none hello2.c -c 只激活預(yù)處理,編譯,和匯編,也就是他只把程序做成obj文件 例子用法: gcc -c hello.c 他將生成.o的obj文件 gcc -c test.s 將匯編輸出文件test.s編譯輸出test.o文件。 -S 只激活預(yù)處理和編譯,就是指把文件編譯成為匯編代碼。 例子用法: gcc -S hello.c 他將生成.s的匯編代碼,你可以用文本編輯器察看 gcc -S test.i 將預(yù)處理輸出文件test.i匯編成test.s文件 -E 只激活預(yù)處理,這個不生成文件,你需要把它重定向到一個輸出文件里面. 例子用法: gcc -E hello.c >; pianoapan.txt gcc -E hello.c | more 慢慢看吧,一個hello word 也要與處理成800行的代碼 gcc -E test.c -o test.i -o 制定目標(biāo)名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,如果你和我有同感,改掉它,哈哈 例子用法: gcc -o hello.exe hello.c (哦,windows用習(xí)慣了) gcc -o hello.asm -S hello.c -pipe 使用管道代替編譯中臨時文件,在使用非gnu匯編工具的時候,可能有些問題 gcc -pipe -o hello.exe hello.c -ansi 關(guān)閉gnu c中與ansi c不兼容的特性,激活ansi c的專有特性(包括禁止一些asm inline typeof關(guān)鍵字,以及UNIX,vax等預(yù)處理宏, -fno-asm 此選項實現(xiàn)ansi選項的功能的一部分,它禁止將asm,inline和typeof用作關(guān)鍵字。 -fno-strict-prototype 只對g++起作用,使用這個選項,g++將對不帶參數(shù)的函數(shù),都認(rèn)為是沒有顯式的對參數(shù)的個數(shù)和類型說明,而不是沒有參數(shù). 而gcc無論是否使用這個參數(shù),都將對沒有帶參數(shù)的函數(shù),認(rèn)為城沒有顯式說明的類型 -fthis-is-varialble 就是向傳統(tǒng)c++看齊,可以使用this當(dāng)一般變量使用. -fcond-mismatch 允許條件表達式的第二和第三參數(shù)類型不匹配,表達式的值將為void類型 -funsigned-char -fno-signed-char -fsigned-char -fno-unsigned-char 這四個參數(shù)是對char類型進行設(shè)置,決定將char類型設(shè)置成unsigned char(前兩個參數(shù))或者 signed char(后兩個參數(shù)) -include file 包含某個代碼,簡單來說,就是便以某個文件,需要另一個文件的時候,就可以用它設(shè)定,功能就相當(dāng)于在代碼中使用#include; 例子用法: gcc hello.c -include /root/pianopan.h -imacros file 將file文件的宏,擴展到gcc/g++的輸入文件,宏定義本身并不出現(xiàn)在輸入文件中 -Dmacro 以字符串“1”定義 MACRO 宏 相當(dāng)于C語言中的#define macro -Dmacro=defn 以字符串“DEFN”定義 MACRO 宏 相當(dāng)于C語言中的#define macro defn -Umacro 取消對 MACRO 宏的定義 相當(dāng)于C語言中的#undef macro -undef 取消對任何非標(biāo)準(zhǔn)宏的定義 -Idir 在你是用#include"file"的時候,gcc/g++會先在當(dāng)前目錄查找你所制定的頭文件,如果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他 回先在你所制定的目錄查找,然后再按常規(guī)的順序去找. 對于#include;,gcc/g++會到-I制定的目錄查找,查找不到,然后將到系統(tǒng)的缺省的頭文件目錄查找 -I- 就是取消前一個參數(shù)的功能,所以一般在-Idir之后使用 -idirafter dir 在-I的目錄里面查找失敗,講到這個目錄里面查找. -iprefix prefix -iwithprefix dir 一般一起使用,當(dāng)-I的目錄查找失敗,會到prefix+dir下查找 -nostdinc 使編譯器不再系統(tǒng)缺省的頭文件目錄里面找頭文件,一般和-I聯(lián)合使用,明確限定頭文件的位置 -nostdin C++ 規(guī)定不在g++指定的標(biāo)準(zhǔn)路經(jīng)中搜索,但仍在其他路徑中搜索,.此選項在創(chuàng)libg++庫使用 -C 在預(yù)處理的時候,不刪除注釋信息,一般和-E使用,有時候分析程序,用這個很方便的 -M 生成文件關(guān)聯(lián)的信息。包含目標(biāo)文件所依賴的所有源代碼你可以用gcc -M hello.c來測試一下,很簡單。 -MM 和上面的那個一樣,但是它將忽略由#include;造成的依賴關(guān)系。 -MD 和-M相同,但是輸出將導(dǎo)入到.d的文件里面 -MMD 和-MM相同,但是輸出將導(dǎo)入到.d的文件里面 -Wa,option 此選項傳遞option給匯編程序;如果option中間有逗號,就將option分成多個選項,然后傳遞給會匯編程序 -Wl.option 此選項傳遞option給連接程序;如果option中間有逗號,就將option分成多個選項,然后傳遞給會連接程序. -llibrary 制定編譯的時候使用的庫 例子用法 gcc -lcurses hello.c 使用ncurses庫編譯程序 -Ldir 制定編譯的時候,搜索庫的路徑。比如你自己的庫,可以用它制定目錄,不然 編譯器將只在標(biāo)準(zhǔn)庫的目錄找。這個dir就是目錄的名稱。 -O0 -O1 -O2 -O3 編譯器的優(yōu)化選項的4個級別,-O0表示沒有優(yōu)化,-O1為缺省值,-O3優(yōu)化級別最高 例子用法: gcc -O1 test.c -o test 使用編譯優(yōu)化級別1編譯程序。級別為1~3,級別越大優(yōu)化效果越好,但編譯時間越長 -g 只是編譯器,在編譯的時候,產(chǎn)生調(diào)試信息。 -gstabs 此選項以stabs格式聲稱調(diào)試信息,但是不包括gdb調(diào)試信息. -gstabs+ 此選項以stabs格式聲稱調(diào)試信息,并且包含僅供gdb使用的額外調(diào)試信息. -ggdb 此選項將盡可能的生成gdb的可以使用的調(diào)試信息. -static 此選項將禁止使用動態(tài)庫,所以,編譯出來的東西,一般都很大,也不需要什么 動態(tài)連接庫,就可以運行. -share 此選項將盡量使用動態(tài)庫,所以生成文件比較小,但是需要系統(tǒng)由動態(tài)庫. -traditional 試圖讓編譯器支持傳統(tǒng)的C語言特性 -IDIRECTORY 指定額外的頭文件搜索路徑DIRECTORY -LDIRECTORY 指定額外的函數(shù)庫搜索路徑DIRECTORY -lLIBRARY 連接時搜索指定的函數(shù)庫LIBRARY -m486 針對 486 進行代碼優(yōu)化 -shared 生成共享目標(biāo)文件。通常用在建立共享庫時 -static 禁止使用共享連接 -w 不生成任何警告信息 -Wall 生成所有警告信息 -save-temps 一次獲得全部的中文輸出文件,正常的進行編譯連接,.i、.s、.o為后綴,文件名相同 -fsyntax-only 不會執(zhí)行預(yù)處理、編譯、匯編、連接,只會測試輸入文件的語法是否正確 -std 指定C方言,如:-std=c99,gcc默認(rèn)的方言是GNU C 多源文件的編譯方法 如果有多個源文件,基本上有兩種編譯方法: [假設(shè)有兩個源文件為test.c和testfun.c] 1. 多個文件一起編譯 用法:#gcc testfun.c test.c -o test 作用:將testfun.c和test.c分別編譯后鏈接成test可執(zhí)行文件。 2. 分別編譯各個源文件,之后對編譯后輸出的目標(biāo)文件鏈接。 用法: #gcc -c testfun.c //將testfun.c編譯成testfun.o #gcc -c test.c //將test.c編譯成test.o #gcc -o testfun.o test.o -o test //將testfun.o和test.o鏈接成test 以上兩種方法相比較,第一中方法編譯時需要所有文件重新編譯,而第二種方法可以只重新編譯修改的文件,未修改的文件不用重新編譯。 FAQ 1、為什么會出現(xiàn)undefined reference to 'xxxxx'錯誤? 首 先這是鏈接錯誤,不是編譯錯誤,也就是說如果只有這個錯誤,說明你的程序源碼本身沒有問題,是你用編譯器編譯時參數(shù)用得不對,你沒有指定鏈接程序要用到得 庫,比如你的程序里用到了一些數(shù)學(xué)函數(shù),那么你就要在編譯參數(shù)里指定程序要鏈接數(shù)學(xué)庫,方法是在編譯命令行里加入-lm。 2、-l參數(shù)和-L參數(shù) -l參數(shù)就是用來指定程序要鏈接的庫,-l參數(shù)緊接著就是庫名,那么庫名跟真正的庫文 件名有什么關(guān)系呢? 就拿數(shù)學(xué)庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了。 好 了現(xiàn)在我們知道怎么得到庫名了,比如我們自已要用到一個第三方提供的庫名字叫l(wèi)ibtest.so,那么我們只要把libtest.so拷貝到/usr /lib里,編譯時加上-ltest參數(shù),我們就能用上libtest.so庫了(當(dāng)然要用libtest.so庫里的函數(shù),我們還需要與 libtest.so配套的頭文件)。 放在/lib和/usr/lib和/usr/local/lib里的庫直接用-l參數(shù)就能鏈接了,但如果庫文件 沒 放在這三個目錄里,而是放在其他目錄里,這時我們只用-l參數(shù)的話,鏈接還是會出錯,出錯信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是鏈接程序ld在那3個目錄里找不到libxxx.so,這時另外一個參數(shù)-L就派上用場了,比如常用的X11的庫,它放在/usr /X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數(shù),-L參數(shù)跟著的是庫文件所在的目錄名。 再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈接參數(shù)就是-L/aaa/bbb/ccc -ltest 另 外,大部分libxxxx.so只是一個鏈接,以RH9為例,比如libm.so它鏈接到/lib/libm.so.x,/lib/libm.so.6又 鏈到/lib/libm-2.3.2.so,如果沒有這樣的鏈接,還是會出錯,因為ld只會找libxxxx.so,所以如果你要用到xxxx庫,而只有 libxxxx.so.x或者libxxxx-x.x.x.so,做一個鏈接就可以了ln -s libxxxx-x.x.x.so libxxxx.so,手工來寫鏈接參數(shù)總是很麻煩的,還好很多庫開發(fā)包提供了生成鏈接參數(shù)的程序,名字一般叫xxxx-config,一般放在/usr /bin目錄下,比如gtk1.2的鏈接參數(shù)生成程序是gtk-config,執(zhí)行g(shù)tk-config --libs就能得到以下輸出"-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm",這就是編譯一個gtk1.2程序所需的gtk鏈接參數(shù),xxx-config除了--libs參數(shù)外還有一個參數(shù)是--cflags用來生成頭 文件包含目錄的,也就是-I參數(shù),在下面我們將會講到。你可以試試執(zhí)行g(shù)tk-config --libs --cflags,看看輸出結(jié)果?,F(xiàn)在的問題就是怎樣用這些輸出結(jié)果了,最笨的方法就是復(fù)制粘貼或者照抄,聰明的辦法是在編譯命令行里加入這個 `xxxx-config --libs --cflags`,比如編譯一個gtk程序:gcc gtktest.c `gtk-config --libs --cflags`這樣就差不多了。注意`不是單引號,而是1鍵左邊那個鍵。除了xxx-config以外,現(xiàn)在新的開發(fā)包一般都用pkg-config 來生成鏈接參數(shù),使用方法跟xxx-config類似,但xxx-config是針對特定的開發(fā)包,但pkg-config包含很多開發(fā)包的鏈接參數(shù)的生 成,用pkg-config --list-all命令可以列出所支持的所有開發(fā)包,pkg-config的用法就是pkg-config pagName --libs --cflags,其中pagName是包名,是pkg-config--list-all里列出名單中的一個,比如gtk1.2的名字就是 gtk+,pkg-config gtk+ --libs --cflags的作用跟gtk-config --libs --cflags是一樣的。比如:gcc gtktest.c `pkg-config gtk+ --libs --cflags`。 3、-include和-I參數(shù) -include用來包含頭文件,但一般情況下包含頭文件都在源碼 里用#include xxxxxx實現(xiàn),-include參數(shù)很少用。-I參數(shù)是用來指定頭文件目錄,/usr/include目錄一般是不用指定的,gcc知道去那里找,但 是如果頭文件不在/usr/include里我們就要用-I參數(shù)指定了,比如頭文件放在/myinclude目錄里,那編譯命令行就要加上-I /myinclude參數(shù)了,如果不加你會得到一個"xxxx.h: No such file or directory"的錯誤。-I參數(shù)可以用相對路徑,比如頭文件在當(dāng)前目錄,可以用-I.來指定。上面我們提到的--cflags參數(shù)就是用來生成-I 參數(shù)的。 4、幾個相關(guān)的環(huán)境變量 PKG_CONFIG_PATH:用來指定pkg-config用到的pc文件的路徑,默認(rèn)是/usr/lib/pkgconfig,pc文件是文本文件,擴展名是.pc,里面定義開發(fā)包的安裝路徑,Libs參數(shù)和Cflags參數(shù)等等。 CC:用來指定c編譯器。 CXX:用來指定cxx編譯器。 LIBS:跟上面的--libs作用差不多。 CFLAGS:跟上面的--cflags作用差不多。 CC,CXX,LIBS,CFLAGS手動編譯時一般用不上,在做configure時有時用到,一般情況下不用管。 環(huán)境變量設(shè)定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx CPATH、C_INCLUDE_PATH 用逗號隔開的目錄列表,提供頭文件搜索位置 COMPILER_PATH 用逗號隔開的目錄列表,以提供GCC子程序的搜索位置 GCC_EXEC_PREFIX 當(dāng)GCC調(diào)用子程序時,需要“加在前面”的前置名稱 LIBRARY_PATH 用逗號隔開的目錄列表,以提供連接庫的位置 LD_LIBRARY_PATH 用逗號隔開的目錄列表,以提供共享庫文件的搜索位置 TMPDIR 臨時文件所使用的目錄 5、關(guān)于交叉編譯 交叉編譯通俗地講就是在一種平臺上編譯出能運行在體系結(jié)構(gòu)不同的另一種平臺上,比 如在我們地PC平臺(X86 CPU)上編譯出能運行在sparc CPU平臺上的程序,編譯得到的程序在X86 CPU平臺上是不能運行的,必須放到sparc CPU平臺上才能運行。當(dāng)然兩個平臺用的都是linux。 這種方法在異平臺移植和嵌入式開發(fā)時用得非常普遍。 |
|