gcc和makefile(一)

GCC
Linux平臺上,最流行的編譯系統是GCC(GNU Compile Collection)。GCC也是GNU發佈的最著名的軟件之一。GCC的功能非常強大,主要體現在兩方面。
1) GCC可以爲x86、ARM、MIPS等不同體系結構的硬件平臺編譯程序。
2) GCC可以編譯C、C++、Pascal、Java等數十種高級語言。
GCC的這兩項特性對嵌入式應用開發及其重要。此外,GCC的編譯效率也是非常高的,一般要高出其他編譯系統20%到30%左右。所以在嵌入式Linux開發領域,使用的基本上就是GCC編譯系統。
(一)gcc命令的使用格式爲:
  gcc [選項] [文件名] [選項] [文件名]
gcc命令擁有數量龐大的編譯選項,按類型可以把選項分爲以下幾大類。
1)總體選項:用於控制編譯的整個流程。
常用選項:
-c:對源文件進行編譯或彙編。
-E:對源文件進行預處理。
-S:對源文件進行編譯。
-o file:輸出目標文件file。
-v:顯示編譯階段的命令。
2) 語言選項:用於支持各種版本的C語言程序。
常用選項:
-ansi:支持符合ANSI標準的C程序。
3) 警告選項:用於控制編譯過程中產生的各種警告信息。
常用選項:
-W:屏蔽所有的警告信息。
-Wall:顯示所有類型的警告信息。
-Werror:出現任何警告信息就停止編譯。
4)調試選項:用於控制調試信息。
常用選項:
-g:產生調試信息。
5)優化選項:用於對目標文件進行優化。
常用選項:
-O1:對目標文件的性能進行優化。
-O2:在-O1的基礎上進一步優化,提高目標文件的運行性能。
-O3:在-O2的基礎上進一步優化,支持函數集成優化。
-O0:不進行優化。
6)連接器選項:用於控制鏈接過程。
常用選項:
-static:使用靜態鏈接。
-llibrary:鏈接library函數庫文件。
-L dir:指定連接器的搜索目錄dir
-shared:生成共享文件。
7) 目錄選項:用於指定編譯器的文件搜索目錄。
常用選項:
-Idir:指定頭文件的搜索目錄dir
-Ldir:指定搜索目錄dir。
此外,還有配置選項等其他選項,這裏不做介紹了。
編譯系統本身是一種相當複雜的程序,編寫甚至讀懂這樣的程序都是非常困難的。但是從事嵌入式Linux應用的開發人員都應掌握編譯系統的基本原理和工作流程。
(二)GCC工作流程
C程序的編譯過程中,依次要進行預處理、編譯、彙編、鏈接四個階段。這裏通過編譯C文件test.c來展示GCC的工作流程。
例如:
l test.c
#include <stdio.h>
int main()
{
   printf(“Hello world!\n”);
   return 0;
}
1. 預處理階段
由於在test.c中使用了頭文件stdio.h,所以GCC在編譯時首先要把頭文件stdio.h中的內容加載到test.c中的首部。
shell中輸入命令“gcc -E test.c -o test.i”。其中,參數E告訴gcc命令只進行預編譯,不做其他處理;參數o用來指明輸出的文件名爲test.i。命令運行完畢後就會產生一個名爲test.i的文件。如下所示:
[root@localhost home]#gcc -E test.c -o test.i
[root@localhost home]#ls
test.c test.i
2. 編譯階段
編譯階段是整個編譯過程中最複雜的一個階段。這裏拿自然語言的翻譯過程作個對比。比如在把“I love China”翻譯成中文前,需要依次完成以下幾個步驟:
1)考察這個句子中每個單詞的拼寫是不是正確。
2)考察整個句子的語法(比如主謂賓、定狀補的結構等)是不是正確。
3)考察整個句子的語義是不是正確。
只有以上三個步驟都正常通過了,才能保證句子被正確翻譯。同樣,高級編程語言的編譯階段也必須實現這三個步驟。
1) 步驟1稱爲詞法分析,主要負責檢查關鍵字、標識符等是否正確。
2) 步驟2稱爲語法分析,主要負責檢查程序中語句的語法是否正確。
3) 步驟3稱爲語義分析,主要負責檢查程序中語句的邏輯意義是否正確。
shell中輸入命令“gcc -S test.i -o test.s”。其中,參數S告訴gcc命令只進行編譯,不做其他處理。命令運行完畢後就會產生一個名爲test.s的彙編文件。如下所示:
[root@localhost home]#gcc -S test.i -o test.s
[root@localhost home]#ls
test.c test.i test.s
注意,以上所示的彙編代碼是針對x86平臺的。
3. 彙編階段
彙編階段的任務是把彙編程序翻譯成CPU可以識別的二進制文件,該文件又稱爲目標文件。
shell中輸入命令“gcc -c test.s -o test.o”,其中,參數c告訴gcc命令只進行彙編,不做其他處理。命令運行完畢後就會產生一個名爲test.o的目標文件。如下所示:
[root@localhost home]#gcc -c test.s -o test.o
[root@localhost home]#ls
test.c test.i test.o test.s
Windows系統中,目標文件的後綴是obj。
4. 鏈接階段
目標文件雖然已經可以被CPU直接識別,但是單個目標文件一般是無法運行的。原因在於一個程序往往是由多個源文件組成的,每個源文件只對應一個目標文件。也許有人會問,test程序不就只有一個源文件test.c嗎,爲什麼也不能直接運行呢?原因是test.c使用了stdio.h對應的庫函數,所以必須要把test.o文件和函數庫文件鏈接在一起才能運行。
鏈接階段的任務就是把程序中所有的目標文件和所需的庫文件都鏈接在一起,最終生成一個可以直接運行的文件,稱爲可執行文件。
shell中輸入命令“gcc test.o -o test”,運行完畢後就會產生一個名爲test的可執行文件。輸入命令“./test”執行該文件,就可以得到test文件的運行結果“Hello world!”。 如下所示:
[root@localhost home]#gcc test.o -o test
[root@localhost home]#./test
Hello world!
gcc命令生成的可執行文件的有以下三種格式。
1)a.out(Assembler and Link editor output);
2)COFF(Common object file format);
3)ELF(Executable and linkable format);




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章