GCC簡介
1、GCC經(jīng)過那么多年的發(fā)展斑胜,已經(jīng)從最初的C編譯器轉(zhuǎn)變成了編譯器的集合控淡,官方定義是GNU Complier Collection,現(xiàn)在的GCC不僅支持C還支持C++止潘、Java等語言掺炭。
2、GCC是一個(gè)編譯系統(tǒng)的驅(qū)動程序覆山,負(fù)責(zé)解析輸入的參數(shù)竹伸,依次調(diào)用預(yù)處理器(cpp)泥栖、編譯器(ccl/cclplus)簇宽、匯編器(as)勋篓、鏈接器(ld)生成可執(zhí)行文件。
3魏割、GCC 和 G++ 的區(qū)別并不是前者用來編譯C代碼譬嚣,后者用來編譯 C++ 代碼。它們的區(qū)別是GCC把后綴為c的文件當(dāng)C代碼處理(ccl編譯)钞它,而 G++ 則當(dāng)作 C++ 處理(cclplus編譯)拜银,對于后綴為cpp的文件gcc和 g++ 處理過程沒有什么區(qū)別。GCC默認(rèn)是不能編譯 C++ 程序的遭垛,需要加上-lstdc++
選項(xiàng)尼桶,G++ 是可以直接編譯的,G++相當(dāng)于是對GCC的封裝锯仪。
GCC編譯過程
在介紹GCC編譯步驟之前泵督,首先需要了解GCC支持的后綴文件類型。
后綴名 | 對應(yīng)語言 |
---|---|
.c | C程序 |
.C/.cc/.cxx | C++程序 |
.i | 預(yù)處理后的C程序 |
.ii | 預(yù)處理后的C++程序 |
.s/.S | 匯編語言程序 |
.h | 頭文件 |
.o | 目標(biāo)文件 |
.a/.so | 編譯后的庫文件 |
GCC編譯流程分為四個(gè)步驟:預(yù)處理(生成.i/.ii文件)庶喜、編譯(生成.s/.S文件)小腊、匯編(生成.o文件)、鏈接(生成可執(zhí)行文件)久窟。
gcc指令的一般格式為:
gcc [選項(xiàng)] 要編譯的文件 [選項(xiàng)] [目標(biāo)文件]
其中秩冈,目標(biāo)文件可缺省,gcc默認(rèn)生成可執(zhí)行的文件為a.out
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
1斥扛、預(yù)處理
對于該階段入问,gcc將stdio.h文件中的代碼包含進(jìn)這段程序,我們可以利用gcc -E test.c -o test.i
命令來生成預(yù)處理過的.i文件犹赖。-E
選項(xiàng)代表讓gcc在預(yù)處理階段后停止編譯队他。test.i
文件中的內(nèi)容如下所示,可以看出stdio.h
文件中的內(nèi)容被展開峻村。
extern int fprintf (FILE *__restrict __stream,
__const char *__restrict __format, ...);
......
# 8 "test.c" 2
int main()
{
printf("Hello World\n");
return 0;
}
2麸折、編譯
該階段主要是對預(yù)編譯后的.i文件編譯,生成匯編代碼的.s文件粘昨。gcc首先要檢查代碼的規(guī)范性垢啼、是否有語法錯(cuò)誤等,以確定代碼的實(shí)際要做的工作张肾,在檢查無誤后芭析,gcc把代碼翻譯成匯編語言。我們可以使用-S
選項(xiàng)來進(jìn)行查看吞瞪,該選項(xiàng)只進(jìn)行編譯而不進(jìn)行匯編過程馁启,生成匯編代碼。
我們可以利用gcc -S test.i -o test.s
命令進(jìn)行編譯過程。test.s
文件中的內(nèi)容如下所示惯疙。
.file "test.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
.section .note.GNU-stack,"",@progbits
3翠勉、匯編
該階段是將編譯后的.s文件轉(zhuǎn)化成二進(jìn)制文件.o的過程,利用-c
選項(xiàng)就可以生成二進(jìn)制.o文件霉颠。我們可以利用gcc -c test.s -o test.o
生成二進(jìn)制代碼对碌。
4、鏈接
該階段主要將成功編譯的二進(jìn)制文件進(jìn)行鏈接操作蒿偎,生成可執(zhí)行文件朽们。利用gcc test.o -o test
生成可執(zhí)行文件test,運(yùn)行./test
即可打印出hello world
诉位。
總結(jié)一下:
gcc -E test.c -o test.i //把原代碼交給cpp預(yù)處理器生成經(jīng)過預(yù)處理后的中間文件test.i
gcc -S test.i -o test.s //把經(jīng)過預(yù)處理之后的test.i文件交給編譯器cc1生成test.s文件
gcc -c test.s -o test.o //把經(jīng)過編譯后匯編文件test.s交給as進(jìn)行匯編骑脱,生成目標(biāo)test.o文件
gcc test.o -o test //將as匯編之后的目標(biāo)文件交給ld鏈接成一個(gè)可執(zhí)行的文件test
GCC常用編譯選項(xiàng)
1、總體編譯選項(xiàng)
選項(xiàng)名稱 | 作用 |
---|---|
-c | 只是編譯不鏈接苍糠,生成目標(biāo)文件.o |
-S | 只是編譯不匯編惜姐,生成匯編代碼 |
-E | 只進(jìn)行預(yù)編譯榕订,不做其他處理 |
-g | 在可執(zhí)行程序中包含標(biāo)準(zhǔn)調(diào)試信息 |
-o file | 把輸出文件輸出到file里 |
-v | 打印出編譯器內(nèi)部編譯各過程的命令行信息和編譯器的版本 |
-I dir | 在頭文件的搜索路徑列表中添加dir目錄 |
-L dir | 在庫文件的搜索路徑列表中添加dir目錄 |
-static | 鏈接靜態(tài)庫 |
-llibrary | 連接名為library的庫文件 |
表中前邊幾個(gè)選項(xiàng)在GCC編譯步驟中已經(jīng)有所了解炫加,主要對表中后四個(gè)選項(xiàng)進(jìn)行介紹。
當(dāng)我們進(jìn)行程序開發(fā)時(shí)靶瘸,基本都會用到很多函數(shù)庫寝优,從程序員的角度看条舔,函數(shù)庫就是封裝的一些頭文件(.h)和庫文件(.a/.so),Linux系統(tǒng)下頭文件一般默認(rèn)放到/usr/include/
目錄下乏矾,庫文件放在/usr/lib/
目錄下孟抗,如果我們使用的庫不在標(biāo)準(zhǔn)路徑下,我們就需要指定頭文件和庫文件的路徑以便讓gcc找到它們钻心。
舉個(gè)例子凄硼,假設(shè)上一節(jié)test.c
主要實(shí)現(xiàn)C語言連接mysql數(shù)據(jù)庫的功能,我們從官網(wǎng)下載的mysql connectors的頭文件在/usr/local/mysq/include/
路徑下捷沸,庫函數(shù)在/usr/local/mysql/lib/
路徑下摊沉。
我們可以利用
gcc -c -I /usr/local/mysql/include test.c -o test.o
生成test.o
二進(jìn)制文件,再利用
gcc -L /usr/local/mysql/lib -lmysqlclient test.o -o test
進(jìn)行鏈接操作產(chǎn)生可執(zhí)行的test
文件痒给。這兩步也可以合成一步说墨,直接生成可執(zhí)行的test
文件
gcc -I /usr/local/mysql/include -L /usr/local/mysql/lib -lmysqlclient test.c -o test
Linux下的庫文件分為兩大類分別是動態(tài)鏈接庫(通常以.so結(jié)尾)和靜態(tài)鏈接庫(通常以.a結(jié)尾),二者的區(qū)別僅在于程序執(zhí)行時(shí)所需的代碼是在運(yùn)行時(shí)動態(tài)加載的苍柏,還是在編譯時(shí)靜態(tài)加載的尼斧。
默認(rèn)情況下, GCC在鏈接時(shí)優(yōu)先使用動態(tài)鏈接庫试吁,只有當(dāng)動態(tài)鏈接庫不存在時(shí)才考慮使用靜態(tài)鏈接庫棺棵,如果需要使用靜態(tài)鏈接庫可以在編譯時(shí)加上-static
選項(xiàng),強(qiáng)制使用靜態(tài)鏈接庫。
比如在/usr/local/mysql/lib目錄下有鏈接時(shí)所需要的庫文件libmysqlclient.so和libmysqlclient.a烛恤,為了讓GCC在鏈接時(shí)只用到靜態(tài)鏈接庫爬橡,可以使用下面的命令:
gcc –L /usr/local/mysql/lib -static –lmysqlclient test.o –o test
需要注意的是:
-
-I dir
和-L dir
都只是指定了路徑,而沒有指定文件棒动,因此不能在路徑中包含文件名。 - 另外值得詳細(xì)解釋一下的是
-l
選項(xiàng)宾添, 它指示gcc去連接庫文件libXXX.so船惨。由于在Linux下的庫文件命名時(shí)有一個(gè)規(guī)定:必須以lib三個(gè)字母開頭。因此在用-l
選項(xiàng)指定鏈接的庫文件名時(shí)可以省去lib三個(gè)字母缕陕。也就是說gcc在對”-lXXX”進(jìn)行處理時(shí)粱锐,會自動去鏈接名為libXXX.so的文件。
2扛邑、其他常用編譯選項(xiàng)
選項(xiàng)名稱 | 作用 |
---|---|
-ansi | 支持符合ANSI標(biāo)準(zhǔn)的C程序 |
-pedantic | 允許發(fā)出ANSI C標(biāo)準(zhǔn)所列的全部警告信息 |
-pedantic-error | 允許發(fā)出ANSI C標(biāo)準(zhǔn)所列的全部錯(cuò)誤信息 |
-Wall | 允許發(fā)出gcc提供的所有有用的報(bào)警信息 |
-Werror | 把所有的告警信息轉(zhuǎn)化為錯(cuò)誤信息怜浅,并在告警發(fā)生時(shí)終止編譯過程 |
-O | 主要進(jìn)行線程跳轉(zhuǎn)(Thread Jump)和延遲退棧(Deferred Stack Pops)兩種優(yōu)化 |
-O2 | 除了完成所有“-O1”級別的優(yōu)化之外,同時(shí)還要進(jìn)行一些額外的調(diào)整工作蔬崩,如處理器指令調(diào)度等 |
-O3 | 還包括循環(huán)展開和其他一些與處理器特性相關(guān)的優(yōu)化工作 |
-static | 指示鏈接器構(gòu)建一個(gè)完全鏈接的可執(zhí)行程序恶座,即鏈接靜態(tài)庫而不鏈接動態(tài)庫 |
-fPIC | 指示鏈接器創(chuàng)建一個(gè)共享的目標(biāo)文件,即so文件 |
-shared | 生成動態(tài)庫沥阳,一般和上面的-fPIC一起使用 |