不常見但是很有用的gcc命令行選項(xiàng)(一)
軟件工具通常情況下會(huì)提供多個(gè)功能以供選擇,但是如你所知的,不是所有的功能都能被每個(gè)人用到的。公正地講,這并不是設(shè)計(jì)上的錯(cuò)誤,因?yàn)槊總€(gè)用戶都會(huì)有自己的需求,他們只在他們的領(lǐng)域內(nèi)使用該工具。然而,深入了解你所使用的工具也是很有益處的,因?yàn)槟阌肋h(yuǎn)不知道它的某個(gè)功能會(huì)在什么時(shí)候派上用場(chǎng),從而節(jié)省下你寶貴的時(shí)間。
舉一個(gè)例子:編譯器。一個(gè)優(yōu)秀的編程語言編譯器總是會(huì)提供極多的選項(xiàng),但是用戶一般只知道和使用其中很有限的一部分功能。更具體點(diǎn)來說,比如你是 C 語言開發(fā)人員,并將 Linux 作為你的開發(fā)平臺(tái),那么你很有可能會(huì)用到 gcc 編譯器,這個(gè)編譯器提供了 (幾乎) 數(shù)不清的命令行選項(xiàng)列表。
你知道,你可以讓 gcc 保存每個(gè)編譯階段的輸出嗎?你知道用于生成警告的 -Wall 選項(xiàng),它并不會(huì)包含一些特殊的警告嗎?gcc 的很多命令行選項(xiàng)都不會(huì)經(jīng)常用到,但是它們?cè)谀承┨囟ǖ那闆r下會(huì)變得非常有用,例如,當(dāng)你在調(diào)試代碼的時(shí)候。
所以在本文中,我們會(huì)介紹這樣的幾個(gè)選項(xiàng),提供所有必要的細(xì)節(jié),并通過簡(jiǎn)單易懂的例子來解釋它們。
但是在開始前,請(qǐng)注意本文中所有的例子所使用的環(huán)境:基于 Ubuntu 16.04 LTS 操作系統(tǒng),gcc 版本為 5.4.0。
在每個(gè)編譯階段查看中間代碼的輸出
你知道在通過 gcc 編譯 c 語言代碼的時(shí)候大體上共分為四個(gè)階段嗎?分別為預(yù)處理 -> 編譯 -> 匯編 -> 鏈接。在每個(gè)階段之后,gcc 都會(huì)產(chǎn)生一個(gè)將移交給下一個(gè)階段的臨時(shí)輸出文件。但是生成的都是臨時(shí)文件,因此我們并不能看到它們——我們所看到的只是我們發(fā)起編譯命令,然后它生成的我們可以直接運(yùn)行的二進(jìn)制文件或可執(zhí)行文件。
但是比如說在預(yù)處理階段,如果調(diào)試時(shí)需要查看代碼是如何進(jìn)行處理的,你要怎么做呢?好消息是 gcc 編譯器提供了相應(yīng)的命令行選項(xiàng),你可以在標(biāo)準(zhǔn)編譯命令中使用這些選項(xiàng)獲得原本被編譯器刪除的中間文件。我們所說的選項(xiàng)就是-save-temps。
以下是 gcc 手冊(cè)中對(duì)該選項(xiàng)的介紹:
永久存儲(chǔ)臨時(shí)的中間文件,將它們放在當(dāng)前的文件夾下并根據(jù)源文件名稱為其命名。因此,用 -c -save-temps 命令編譯 foo.c 文件時(shí)會(huì)生成 foo.i foo.s 和 foo.o 文件。即使現(xiàn)在編譯器大多使用的是集成的預(yù)處理器,這命令也會(huì)生成預(yù)處理輸出文件 foo.i。
當(dāng)與 -x 命令行選項(xiàng)結(jié)合使用時(shí),-save-temps 命令會(huì)避免覆寫與中間文件有著相同擴(kuò)展名的輸入源文件。相應(yīng)的中間文件可以通過在使用 -save-temps 命令之前重命名源文件獲得。
以下是怎樣使用這個(gè)選項(xiàng)的例子:
- gcc -Wall -save-temps test.c -o test-exec
下圖為該命令的執(zhí)行結(jié)果,驗(yàn)證其確實(shí)產(chǎn)生了中間文件:
因此,在截圖中你所看到的 test.i、test.s、 test.o 文件都是由 -save-temps 選項(xiàng)產(chǎn)生的。這些文件分別對(duì)應(yīng)于預(yù)處理、編譯和鏈接階段。
讓你的代碼可調(diào)試和可分析
你可以使用專有的工具調(diào)試和分析代碼。如 gdb 就是專用于調(diào)試的工具,而 gprof 則是熱門的分析工具。但你知道 gcc 特定的命令行選項(xiàng)也可以讓你的代碼可調(diào)試和可分析嗎?
讓我們開始調(diào)試之路吧!為了能在代碼調(diào)試中使用 gdb,你需要在編譯代碼的時(shí)候使用 gcc 編譯器提供的 -g 選項(xiàng)。這個(gè)選項(xiàng)讓 gcc 生成 gdb 需要的調(diào)試信息從而能成功地調(diào)試程序。
如果你想要使用此選項(xiàng),建議您詳細(xì)閱讀 gcc 手冊(cè)提供的有關(guān)此選項(xiàng)的詳細(xì)信息——在某些情況下,其中的一些內(nèi)容可能是至關(guān)重要的。 例如,以下是從手冊(cè)頁中摘錄的內(nèi)容:
GCC 允許在使用 -g 選項(xiàng)的時(shí)候配合使用 -O 選項(xiàng)。優(yōu)化代碼采用的便捷方式有時(shí)可能會(huì)產(chǎn)生意想不到的結(jié)果:某些你聲明的變量可能不復(fù)存在;控制流可能會(huì)突然跳轉(zhuǎn)到你未曾預(yù)期的位置;一些語句也許不會(huì)執(zhí)行,因?yàn)樗鼈円呀?jīng)把常量結(jié)果計(jì)算了或值已經(jīng)被保存;一些語句可能會(huì)在不同地方執(zhí)行,因?yàn)樗鼈円呀?jīng)被移出循環(huán)。
然而優(yōu)化的輸出也是可以調(diào)試的。這就使得讓優(yōu)化器可以合理地優(yōu)化或許有 bug 的代碼。
不只是 gdb,使用 -g 選項(xiàng)編譯代碼,還可以開啟使用 Valgrind 內(nèi)存檢測(cè)工具,從而完全發(fā)揮出該選項(xiàng)的潛力?;蛟S還有一些人不知道,mencheck 工具被程序員們用來檢測(cè)代碼中是否存在內(nèi)存泄露。你可以在這里參見這個(gè)工具的用法。
繼續(xù)往下,為了能夠在代碼分析中使用 gprof 工具,你需要使用 -pg 命令行選項(xiàng)來編譯代碼。這會(huì)讓 gcc 生成額外的代碼來寫入分析信息,gprof 工具需要這些信息來進(jìn)行代碼分析。gcc 手冊(cè) 中提到:當(dāng)編譯你需要數(shù)據(jù)的源文件時(shí),你必須使用這個(gè)選項(xiàng),當(dāng)然鏈接時(shí)也需要使用它。為了能了解 gprof 分析代碼時(shí)具體是如何工作的,你可以轉(zhuǎn)到我們的網(wǎng)站專用教程進(jìn)行了解。
注意:-g 和 -pg 選項(xiàng)的用法類似于上一節(jié)中使用 -save-temps 選項(xiàng)的方式。
結(jié)論
我相信除了 gcc 的專業(yè)人士,都可以在這篇文章中得到了一些啟發(fā)。嘗試一下這些選項(xiàng),然后觀察它們是如何工作的。同時(shí),請(qǐng)期待本教程系列的下一部分,我們將會(huì)討論更多有趣和有用的 gcc 命令行選項(xiàng)。