- 論壇徽章:
- 0
|
編譯優(yōu)化指南作者:
金步國(guó)
版權(quán)聲明
本文作者是一位自由軟件愛好者,所以本文雖然不是軟件,但是本著 GPL
的精神發(fā)布。任何人都可以自由使用、轉(zhuǎn)載、復(fù)制和再分發(fā),但必須保留作者署名,亦不得對(duì)聲明中的任何條款作任何形式的修改,也不得附加任何其它條件。您可
以自由鏈接、下載、傳播此文檔,但前提是必須保證全文完整轉(zhuǎn)載,包括完整的版權(quán)信息和作譯者聲明。
其他作品
本文作者十分愿意與他人共享勞動(dòng)成果,如果你對(duì)我的其他翻譯作品或者技術(shù)文章有興趣,可以在如下位置查看現(xiàn)有作品的列表:
BUG報(bào)告,切磋與探討
由于作者水平有限,因此不能保證作品內(nèi)容準(zhǔn)確無(wú)誤,請(qǐng)?jiān)陂喿x中自行鑒別。如果你發(fā)現(xiàn)了作品中的錯(cuò)誤,請(qǐng)您來(lái)信指出,哪怕是錯(cuò)別字也好,任何提高作品
質(zhì)量的建議我都將虛心接納。如果你愿意就作品中的相關(guān)內(nèi)容與我進(jìn)行進(jìn)一步切磋與探討,也歡迎你與我聯(lián)系。聯(lián)系方式:Email:
csfrank@citiz.net ; QQ: 70171448 ; MSN: csfrank122@hotmail.com
前言
網(wǎng)上關(guān)于編譯優(yōu)化的文章很多,但大多零零散散,不成體系,本文試圖給出一個(gè)完整和清晰的優(yōu)化思路,同時(shí)提供在實(shí)踐中如何進(jìn)行優(yōu)化的詳盡參考。但是,
在介紹所有優(yōu)化知識(shí)之前首先引用LFS-Book中的一句忠告:“使用編譯器優(yōu)化得到的小幅度性能提升,與它帶來(lái)的風(fēng)險(xiǎn)相比微不足道”。你還要進(jìn)行優(yōu)化
嗎?
%@&#=^%~*# ...
OK, crazy guy! Let's Go!!
在繼續(xù)之前,作者還是奉勸各位:如果追求極致的優(yōu)化,那么它將是一件既耗時(shí)又麻煩的事情,你會(huì)陷入無(wú)止盡的測(cè)試、測(cè)試、再測(cè)試……另外
Gentoo wiki 上有這么一句話:"GCC has well over a hundred individual
optimization flags and it would be insane to try and describe them
all."所以本文不會(huì)涉及全部GCC優(yōu)化選項(xiàng)。最后作者還是再羅唆一句:優(yōu)化應(yīng)當(dāng)適可而止為好,將精力留出來(lái)做一些其它事情會(huì)更有意義!
先決條件
本文的主要讀者是 LFS/Gentoo 的玩家,基本上比較 crazy 的玩家都接觸過,如果你之前從未使用過 LFS/Gentoo ,請(qǐng)先按照
《Linux From Scratch 6.2 中文版》
做一遍 LFS ,然后再來(lái)閱讀此文將會(huì)更有意義。另外,本文是建立在
《深入理解軟件包的配置、編譯與安裝》
一文基礎(chǔ)之上的,在開始閱讀本文之前,請(qǐng)先閱讀它。
基本原理
我們首先從三個(gè)方面來(lái)看與優(yōu)化相關(guān)的內(nèi)容:
從運(yùn)行時(shí)的依賴關(guān)系來(lái)看,對(duì)性能有較大影響的組件有 kernel 和 glibc ,雖然這嚴(yán)格說來(lái)這不屬于本文的話題,但是經(jīng)過精心選擇、精心配置、精心編譯的內(nèi)核與C庫(kù)將對(duì)提高系統(tǒng)的運(yùn)行速度起著基礎(chǔ)性的作用。從被編譯的軟件包來(lái)看,每個(gè)軟件包的 configure 腳本都提供了許多配置選項(xiàng),其中有許多選項(xiàng)是與性能息息相關(guān)的。比如,對(duì)于
Apache-2.2.3 而言,你可以使用 --enable-MODULE=static 將模塊靜態(tài)編譯進(jìn)核心,使用
--disable-MODULE 禁用不需要的模塊,使用 --with-mpm=MPM
選擇一個(gè)高效的多路處理模塊,在不需要IPv6的情況下使用 --disable-ipv6 禁用IPv6支持,在不使用線程化的MPM時(shí)使用
--disable-threads
禁用線程支持,等等……這部分內(nèi)容顯然不可能在本文中進(jìn)行完整的講述,本文只能講述與優(yōu)化相關(guān)的通用選項(xiàng)。針對(duì)特定的軟件包,請(qǐng)?jiān)诰幾g前使用
configure --help 查看所有選項(xiàng),并精心選擇。從編譯過程自身來(lái)看,將源代碼編譯為二進(jìn)制文件是在 Makefile 文件的指導(dǎo)下,由 make
程序調(diào)用一條條編譯命令完成的。而將源代碼編譯為二進(jìn)制文件又需要經(jīng)過以下四個(gè)步驟:預(yù)處理(cpp) → 編譯(gcc或g++) → 匯編(as)
→ 連接(ld) ;括號(hào)中表示每個(gè)階段所使用的程序,它們分別屬于 GCC 和 Binutils
軟件包。顯然的,優(yōu)化應(yīng)當(dāng)從編譯工具自身的選擇以及控制編譯工具的行為入手。
大體上編譯優(yōu)化就這"三板斧"(其實(shí)是"三腳貓")了,本文接下來(lái)的內(nèi)容將討論這只貓的后兩只腳。
編譯工具的選擇
對(duì)于編譯工具自身的選擇,在假定使用 Binutils 和 GCC 以及 Make
的前提下,沒什么好說的,基本上新版本都能帶來(lái)性能提升,同時(shí)比老版本對(duì)新硬件的支持更好,所以應(yīng)當(dāng)盡量選用新版本。不過追新也可能帶來(lái)系統(tǒng)的不穩(wěn)定,這
就要針對(duì)實(shí)際情況進(jìn)行權(quán)衡了。本文以 Binutils-2.17 和 GCC-4.1.1 以及 Make-3.81 為例進(jìn)行說明。
configure 選項(xiàng)
這里我們只講解通用的"體系結(jié)構(gòu)選項(xiàng)",由于"特性選項(xiàng)"在每個(gè)軟件包之間千差萬(wàn)別,所以不可能在此處進(jìn)行講解。
這部分內(nèi)容很簡(jiǎn)單,并且其含義也是不言而喻的,下面只列出常用的值:
- i586-pc-linux-gnu
- i686-pc-linux-gnu
- x86_64-pc-linux-gnu
- powerpc-unknown-linux-gnu
- powerpc64-unknown-linux-gnu
如果你實(shí)在不知道應(yīng)當(dāng)使用哪一個(gè),那么就干脆不使用這幾個(gè)選項(xiàng),讓 config.guess 腳本自己去猜吧,反正也挺準(zhǔn)的。
編譯選項(xiàng)
讓我們先看看 Makefile 規(guī)則中的編譯命令通常是怎么寫的。
大多數(shù)軟件包遵守如下約定俗成的規(guī)范:
#1,首先從源代碼生成目標(biāo)文件(預(yù)處理,編譯,匯編),"-c"選項(xiàng)表示不執(zhí)行鏈接步驟。
$(CC) $(CPPFLAGS) $(CFLAGS) example.c -c -o example.o
#2,然后將目標(biāo)文件連接為最終的結(jié)果(連接),"-o"選項(xiàng)用于指定輸出文件的名字。
$(CC) $(LDFLAGS) example.o -o example
#有一些軟件包一次完成四個(gè)步驟:
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) example.c -o example
當(dāng)然也有少數(shù)軟件包不遵守這些約定俗成的規(guī)范,比如:
#1,有些在命令行中漏掉應(yīng)有的Makefile變量(注意:有些遺漏是故意的)
$(CC) $(CFLAGS) example.c -c -o example.o
$(CC) $(CPPFLAGS) example.c -c -o example.o
$(CC) example.o -o example
$(CC) example.c -o example
#2,有些在命令行中增加了不必要的Makefile變量
$(CC) $(CFLAGS) $(LDFLAGS) example.o -o example
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) example.c -c -o example.o
當(dāng)然還有極個(gè)別軟件包完全是"胡來(lái)":亂用變量(增加不必要的又漏掉了應(yīng)有的)者有之,不用$(CC)者有之,不一而足.....
盡管將源代碼編譯為二進(jìn)制文件的四個(gè)步驟由不同的程序(cpp,gcc/g++,as,ld)完成,但是事實(shí)上 cpp, as, ld 都是由
gcc/g++ 進(jìn)行間接調(diào)用的。換句話說,控制了 gcc/g++ 就等于控制了所有四個(gè)步驟。從 Makefile
規(guī)則中的編譯命令可以看出,編譯工具的行為全靠 CC/CXX CPPFLAGS CFLAGS/CXXFLAGS LDFLAGS
這幾個(gè)變量在控制。當(dāng)然理論上控制編譯工具行為的還應(yīng)當(dāng)有 AS ASFLAGS ARFLAGS 等變量,但是實(shí)踐中基本上沒有軟件包使用它們。
那么我們?nèi)绾慰刂七@些變量呢?一種簡(jiǎn)易的做法是首先設(shè)置與這些 Makefile 變量同名的環(huán)境變量并將它們 export 為全局,然后運(yùn)行
configure 腳本,大多數(shù) configure 腳本會(huì)使用這同名的環(huán)境變量代替 Makefile 中的值。但是少數(shù) configure
腳本并不這樣做,你必須手動(dòng)編輯生成的 Makefile 文件,在其中尋找這些變量并修改它們的值。一些源碼包在每個(gè)子文件夾中都有
Makefile 文件,真是一件很累人的事!
CC 與 CXX
這是 C 與 C++ 編譯器命令。默認(rèn)值一般是 "gcc" 與
"g++"。這個(gè)變量本來(lái)與優(yōu)化沒有關(guān)系,但是有些人因?yàn)閾?dān)心軟件包不遵守那些約定俗成的規(guī)范,害怕自己苦心設(shè)置的
CFLAGS/CXXFLAGS/LDFLAGS 之類的變量被忽略了,而索性將原本應(yīng)當(dāng)放置在其它變量中的選項(xiàng)一股老兒塞到 CC 或 CXX
中,比如:CC="gcc -march=k8 -O2 -s"。這是一種怪異的用法,本文不提倡這種做法,而是提倡按照變量本來(lái)的含義使用變量。
CPPFLAGS
這是用于預(yù)處理階段的選項(xiàng)。不過能夠用于此變量的選項(xiàng),看不出有哪個(gè)與優(yōu)化相關(guān)。如果你實(shí)在想設(shè)一個(gè),那就使用下面這個(gè)吧:
-DNDEBUG"NDEBUG"是一個(gè)標(biāo)準(zhǔn)的 ANSI 宏,表示不進(jìn)行調(diào)試編譯。
CFLAGS 與 CXXFLAGS
CFLAGS 表示用于 C 編譯器的選項(xiàng),CXXFLAGS 表示用于 C++
編譯器的選項(xiàng)。這兩個(gè)變量實(shí)際上涵蓋了編譯和匯編兩個(gè)步驟。大多數(shù)程序和庫(kù)在編譯時(shí)默認(rèn)的優(yōu)化級(jí)別是"2"(使用"-O2"選項(xiàng))并且在
Intel/AMD平臺(tái)上默認(rèn)按照i386處理器來(lái)編譯,也就是 CFLAGS="-O2 -march=i386",
CXXFLAGS=$CFLAGS
。事實(shí)上,"-O2"已經(jīng)啟用絕大多數(shù)安全的優(yōu)化選項(xiàng)了。另一方面,由于大部分選項(xiàng)可以同時(shí)用于這兩個(gè)變量,所以僅在最后講述只能用于其中一個(gè)變量的選
項(xiàng)。[提醒]下面所列選項(xiàng)皆為非默認(rèn)選項(xiàng),你只要按需添加即可。
先說說"-O3"在"-O2"基礎(chǔ)上增加的幾項(xiàng):
-finline-functions允許編譯器選擇某些簡(jiǎn)單的函數(shù)在其被調(diào)用處展開,比較安全的選項(xiàng),特別是在CPU二級(jí)緩存較大時(shí)建議使用。-funswitch-loops將循環(huán)體中不改變值的變量移動(dòng)到循環(huán)體之外。-fgcse-after-reload為了清除多余的溢出,在重載之后執(zhí)行一個(gè)額外的載入消除步驟。
另外:
-fomit-frame-pointer對(duì)于不需要棧指針的函數(shù)就不在寄存器中保存指針,因此可以忽略存儲(chǔ)和檢索地址的代
碼,同時(shí)對(duì)許多函數(shù)提供一個(gè)額外的寄存器。所有"-O"級(jí)別都打開它,但僅在調(diào)試器可以不依靠棧指針運(yùn)行時(shí)才有效。在AMD64平臺(tái)上此選項(xiàng)默認(rèn)打開,但
是在x86平臺(tái)上則默認(rèn)關(guān)閉。建議顯式的設(shè)置它(已知在x86上會(huì)造成glibc-2.3.4出現(xiàn)nptl測(cè)試錯(cuò)誤)。-falign-functions=N
-falign-jumps=N
-falign-loops=N
-falign-labels=N這四個(gè)對(duì)齊選項(xiàng)在"-O2"中打開,但是其中的N使用的是默認(rèn)值。如果你想指定不同于默認(rèn)值的N,也可以單獨(dú)指定。比如,對(duì)于L2-cache>=512K的cpu而言,指定 -falign-functions=64 可能會(huì)獲得更好的性能。
調(diào)試選項(xiàng):
-fpretend-float交叉編譯的時(shí)候,假定目標(biāo)機(jī)和宿主機(jī)使用同樣的浮點(diǎn)格式。它導(dǎo)致輸出錯(cuò)誤的浮點(diǎn)常數(shù),但是在目標(biāo)機(jī)上運(yùn)行的時(shí)候,真實(shí)的指令序列有可能和GNU CC希望的一樣。-fprofile-arcs在使用這一選項(xiàng)編譯程序并運(yùn)行它以創(chuàng)建包含每個(gè)代碼塊的執(zhí)行次數(shù)的文件后,程序可以再次使用
-fbranch-probabilities
編譯,文件中的信息可以用來(lái)優(yōu)化那些經(jīng)常選取的分支。如果沒有這些信息,gcc將猜測(cè)哪個(gè)分支將被經(jīng)常運(yùn)行以進(jìn)行優(yōu)化。這類優(yōu)化信息將會(huì)存放在一個(gè)以源文
件為名字的并以".da"為后綴的文件中。
全局選項(xiàng):
-pipe在編譯過程的不同階段之間使用管道而非臨時(shí)文件進(jìn)行通信,可以加快編譯速度。建議使用。
目錄選項(xiàng):
--sysroot=dir將dir作為邏輯根目錄。比如編譯器通常會(huì)在 /usr/include 和 /usr/lib
中搜索頭文件和庫(kù),使用這個(gè)選項(xiàng)后將在 dir/usr/include 和 dir/usr/lib 目錄中搜索。如果使用這個(gè)選項(xiàng)的同時(shí)又使用了
-isysroot 選項(xiàng),則此選項(xiàng)僅作用于庫(kù)文件的搜索路徑,而 -isysroot 選項(xiàng)將作用于頭文件的搜索路徑。這個(gè)選項(xiàng)與優(yōu)化無(wú)關(guān),但是在
CLFS 中有著神奇的作用。
代碼生成選項(xiàng):
-fno-bounds-check關(guān)閉所有對(duì)數(shù)組訪問的邊界檢查。該選項(xiàng)將提高數(shù)組索引的性能,但當(dāng)超出數(shù)組邊界時(shí),可能會(huì)造成不可接受的行為。-freg-struct-return如果struct和union足夠小就通過寄存器返回,這將提高較小結(jié)構(gòu)的效率。如果不夠小,無(wú)法容納在一個(gè)寄存器中,將使用內(nèi)存返回。這是一個(gè)比較安全的選項(xiàng)。-fpic生成可用于共享庫(kù)的位置獨(dú)立代碼。所有的內(nèi)部尋址均通過全局偏移表完成。要確定一個(gè)地址,需要將代碼自身的內(nèi)存位置作為表中一項(xiàng)插入。該選項(xiàng)產(chǎn)生可以在共享庫(kù)中存放并從中加載的目標(biāo)模塊。-fstack-check為防止程序棧溢出而進(jìn)行必要的檢測(cè),僅在多線程環(huán)境中運(yùn)行時(shí)才可能需要它。-fvisibility=hidden設(shè)置默認(rèn)的ELF鏡像中符號(hào)的可見性為隱藏。使用這個(gè)特性可以非常充分的提高連接和加
載共享庫(kù)的性能,生成更加優(yōu)化的代碼,提供近乎完美的API輸出和防止符號(hào)碰撞。我們強(qiáng)烈建議你在編譯任何共享庫(kù)的時(shí)候使用該選項(xiàng)。參見
-fvisibility-inlines-hidden 選項(xiàng)。
硬件體系結(jié)構(gòu)相關(guān)選項(xiàng)[僅僅針對(duì)x86與x86_64]:
-march=cpu-type為特定的cpu-type編譯二進(jìn)制代碼(不能在更低級(jí)別的cpu上運(yùn)行)。Intel可以
用:pentium2, pentium3(=pentium3m), pentium4(=pentium4m), pentium-m,
prescott, nocona 。AMD可以用:k6-2(=k6-3), athlon(=athlon-tbird),
athlon-xp(=athlon-mp), k8(=opteron=athlon64=athlon-fx)-mfpmath=sseP3和athlon-xp級(jí)別及以上的cpu支持"sse"浮點(diǎn)指令。不過由于glibc頭文件的限制,"sse"常常使編譯出的二進(jìn)制文件運(yùn)行更慢,建議不要使用該選項(xiàng)。-malign-double將double, long double, long long對(duì)齊于雙字節(jié)邊界上;有助于生成更高速的代碼,但是程序的尺寸會(huì)變大,并且可能不能與未使用該選項(xiàng)編譯的程序一起工作。-m128bit-long-double指定long double為128位,pentium以上的cpu更喜歡這種標(biāo)準(zhǔn),并且符合x86-64的ABI標(biāo)準(zhǔn),但是卻不附合i386的ABI標(biāo)準(zhǔn)。-mregparm=N指定用于傳遞整數(shù)參數(shù)的寄存器數(shù)目(默認(rèn)不使用寄存器)。00時(shí)你必須使用同一參數(shù)重新構(gòu)建所有的模塊,包括所有的庫(kù)。-msseregparm使用SSE寄存器傳遞float和double參數(shù)和返回值。注意:當(dāng)你使用了這個(gè)選項(xiàng)以后,你必須使用同一參數(shù)重新構(gòu)建所有的模塊,包括所有的庫(kù)。-mmmx
-mno-mmx
-msse
-mno-sse
-msse2
-mno-sse2
-msse3
-mno-sse3
-m3dnow
-mno-3dnow是否使用相應(yīng)的擴(kuò)展指令集以及內(nèi)置函數(shù),按照自己的cpu選擇吧!-maccumulate-outgoing-args指定在函數(shù)引導(dǎo)段中計(jì)算輸出參數(shù)所需最大空間,這在大部分現(xiàn)代cpu中是較快的方法;缺點(diǎn)是會(huì)增加代碼尺寸。-mthreads支持Mingw32的線程安全異常處理。對(duì)于依賴于線程安全異常處理的程序,必須啟用這個(gè)選項(xiàng)。使用這個(gè)選項(xiàng)時(shí)會(huì)定義"-D_MT",它將包含使用選項(xiàng)"-lmingwthrd"連接的一個(gè)特殊的線程輔助庫(kù),用于為每個(gè)線程清理異常處理數(shù)據(jù)。-minline-all-stringops內(nèi)聯(lián)所有的字符串操作。可以提高字符串操作的性能,但是會(huì)增加代碼尺寸。-momit-leaf-frame-pointer不為葉子函數(shù)在寄存器中保存棧指針,這樣可以節(jié)省寄存器,但是將會(huì)使調(diào)試變的困難。注意:不要與 -fomit-frame-pointer 同時(shí)使用,因?yàn)闀?huì)造成代碼效率低下。-m64生成專門運(yùn)行于64位環(huán)境的代碼,不能運(yùn)行于32位環(huán)境,僅用于x86_64[含EMT64]環(huán)境。-mcmodel=small[默認(rèn)值]程序和它的符號(hào)必須位于2GB以下的地址空間。指針仍然是64位。程序可以靜態(tài)連接也可以動(dòng)態(tài)連接。僅用于x86_64[含EMT64]環(huán)境。-mcmodel=kernel內(nèi)核運(yùn)行于2GB地址空間之外。在編譯linux內(nèi)核時(shí)必須使用該選項(xiàng)!僅用于x86_64[含EMT64]環(huán)境。-mcmodel=medium程序必須位于2GB以下的地址空間,但是它的符號(hào)可以位于任何地址空間。程序可以靜態(tài)連接也可以動(dòng)態(tài)連接。注意:共享庫(kù)不能使用這個(gè)選項(xiàng)編譯!僅用于x86_64[含EMT64]環(huán)境。
其它優(yōu)化選項(xiàng):
-fforce-addr必須將地址復(fù)制到寄存器中才能對(duì)他們進(jìn)行運(yùn)算。由于所需地址通常在前面已經(jīng)加載到寄存器中了,所以這個(gè)選項(xiàng)可以改進(jìn)代碼。-finline-limit=n對(duì)偽指令數(shù)超過n的函數(shù),編譯程序?qū)⒉贿M(jìn)行內(nèi)聯(lián)展開,默認(rèn)為600。增大此值將增加編譯時(shí)間和編譯內(nèi)存用量,但是可以得到更優(yōu)化的結(jié)果。-fmerge-all-constants試圖將跨編譯單元的所有常量值和數(shù)組合并在一個(gè)副本中。但是標(biāo)準(zhǔn)C/C++要求每個(gè)變量都必須有不同的存儲(chǔ)位置。-fgcse-sm在全局公共子表達(dá)式消除之后運(yùn)行存儲(chǔ)移動(dòng),以試圖將存儲(chǔ)移出循環(huán)。gcc-3.4中曾屬于"-O2"級(jí)別的選項(xiàng)。-fgcse-las在全局公共子表達(dá)式消除之后消除多余的在存儲(chǔ)到同一存儲(chǔ)區(qū)域之后的加載操作。gcc-3.4中曾屬于"-O2"級(jí)別的選項(xiàng)。-floop-optimize2使用 -floop-optimize 循環(huán)優(yōu)化(包含在"-O1"中)的改進(jìn)版本。-funsafe-loop-optimizations假定循環(huán)不會(huì)溢出,并且循環(huán)的退出條件不是無(wú)窮。這將可以在一個(gè)比較廣的范圍內(nèi)進(jìn)行循環(huán)優(yōu)化,即使優(yōu)化器自己也不能斷定這樣做是否正確。-fsched-spec-load允許一些裝載指令執(zhí)行一些投機(jī)性的動(dòng)作。-ftree-loop-linear在trees上進(jìn)行線型循環(huán)轉(zhuǎn)換。它能夠改進(jìn)緩沖性能并且允許進(jìn)行更進(jìn)一步的循環(huán)優(yōu)化。-fivopts在trees上執(zhí)行歸納變量?jī)?yōu)化。-ftree-vectorize在trees上執(zhí)行循環(huán)向量化。-ftracer執(zhí)行尾部復(fù)制以擴(kuò)大超級(jí)塊的尺寸,它簡(jiǎn)化了函數(shù)控制流,從而允許其它的優(yōu)化措施做的更好。據(jù)說挺有效。-funroll-loops僅對(duì)循環(huán)次數(shù)能夠在編譯時(shí)或運(yùn)行時(shí)確定的循環(huán)進(jìn)行展開,生成的代碼尺寸將變大,執(zhí)行速度可能變快也可能變慢。-fprefetch-loop-arrays生成數(shù)組預(yù)讀取指令,對(duì)于使用巨大數(shù)組的程序可以加快代碼執(zhí)行速度,適合數(shù)據(jù)庫(kù)相關(guān)的大型軟件等。具體效果如何取決于代碼。-fweb為每個(gè)web結(jié)構(gòu)體分配一個(gè)偽寄存器,提供更佳的緩存器使用率。gcc-3.4中曾屬于"-O3"級(jí)別的選項(xiàng)。-ffast-math違反IEEE/ANSI標(biāo)準(zhǔn)以提高浮點(diǎn)數(shù)計(jì)算速度,是個(gè)危險(xiǎn)的選項(xiàng),僅在編譯不需要嚴(yán)格遵守IEEE規(guī)范且浮點(diǎn)計(jì)算密集的程序考慮采用。-fsingle-precision-constant將浮點(diǎn)常量作為單精度常量對(duì)待,而不是隱式地將其轉(zhuǎn)換為雙精度。-fbranch-probabilities在使用 -fprofile-arcs
選項(xiàng)編譯程序并執(zhí)行它來(lái)創(chuàng)建包含每個(gè)代碼塊執(zhí)行次數(shù)的文件之后,程序可以利用這一選項(xiàng)再次編譯,文件中所產(chǎn)生的信息將被用來(lái)優(yōu)化那些經(jīng)常發(fā)生的分支代碼。
如果沒有這些信息,gcc將猜測(cè)那一分支可能經(jīng)常發(fā)生并進(jìn)行優(yōu)化。這類優(yōu)化信息將會(huì)存放在一個(gè)以源文件為名字的并以".da"為后綴的文件中。-frename-registers試圖驅(qū)除代碼中的假依賴關(guān)系,這個(gè)選項(xiàng)對(duì)具有大量寄存器的機(jī)器很有效。gcc-3.4中曾屬于"-O3"級(jí)別的選項(xiàng)。-fbranch-target-load-optimize
-fbranch-target-load-optimize2在執(zhí)行序啟動(dòng)以及結(jié)尾之前執(zhí)行分支目標(biāo)緩存器加載最佳化。-fstack-protector在關(guān)鍵函數(shù)的堆棧中設(shè)置保護(hù)值。在返回地址和返回值之前,都將驗(yàn)證這個(gè)保護(hù)值。如果出現(xiàn)了緩沖區(qū)溢出,保護(hù)值不再匹配,程序就會(huì)退出。程序每次運(yùn)行,保護(hù)值都是隨機(jī)的,因此不會(huì)被遠(yuǎn)程猜出。-fstack-protector-all同上,但是在所有函數(shù)的堆棧中設(shè)置保護(hù)值。--param max-gcse-memory=xxM執(zhí)行GCSE優(yōu)化使用的最大內(nèi)存量(xxM),太小將使該優(yōu)化無(wú)法進(jìn)行,默認(rèn)為50M。--param max-gcse-passes=n執(zhí)行GCSE優(yōu)化的最大迭代次數(shù),默認(rèn)為 1。
傳遞給匯編器的選項(xiàng):
-Wa,optionsoptions是一個(gè)或多個(gè)由逗號(hào)分隔的可以傳遞給匯編器的選項(xiàng)列表。其中的每一個(gè)均可作為命令行選項(xiàng)傳遞給匯編器。-Wa,--strip-local-absolute從輸出符號(hào)表中移除局部絕對(duì)符號(hào)。-Wa,-R合并數(shù)據(jù)段和正文段,因?yàn)椴槐卦跀?shù)據(jù)段和代碼段之間轉(zhuǎn)移,所以它可能會(huì)產(chǎn)生更短的地址移動(dòng)。-Wa,--64設(shè)置字長(zhǎng)為64。僅用于x86_64,并且僅對(duì)ELF格式的目標(biāo)文件有效。
僅可用于 CFLAGS 的選項(xiàng):
-fhosted按宿主環(huán)境編譯,其中需要有完整的標(biāo)準(zhǔn)庫(kù),入口必須是main()函數(shù)且具有int型的返回值。內(nèi)核以外幾乎所有的程序都是如此。該選項(xiàng)隱含設(shè)置了 -fbuiltin,且與 -fno-freestanding 等價(jià)。-ffreestanding按獨(dú)立環(huán)境編譯,該環(huán)境可以沒有標(biāo)準(zhǔn)庫(kù),且對(duì)main()函數(shù)沒有要求。最典型的例子就是操作系統(tǒng)內(nèi)核。該選項(xiàng)隱含設(shè)置了 -fno-builtin,且與 -fno-hosted 等價(jià)。
僅可用于 CXXFLAGS 的選項(xiàng):
-fno-enforce-eh-specsC++標(biāo)準(zhǔn)要求強(qiáng)制檢查異常違例,但是該選項(xiàng)可以關(guān)閉違例檢查,從而減小生成代碼的體積。該選項(xiàng)類似于定義了"NDEBUG"宏。-fno-rtti如果沒有使用'dynamic_cast'和'typeid',可以使用這個(gè)選項(xiàng)禁止為包含虛方法的類生成運(yùn)行時(shí)表示代碼,從而節(jié)約空間。此選項(xiàng)對(duì)于異常處理無(wú)效(仍然按需生成rtti代碼)。-ftemplate-depth-n將最大模版實(shí)例化深度設(shè)為'n',符合標(biāo)準(zhǔn)的程序不能超過17,默認(rèn)值為500。-fno-optional-diags禁止輸出診斷消息,C++標(biāo)準(zhǔn)并不需要這些消息。-fno-threadsafe-staticsGCC自動(dòng)在訪問C++局部靜態(tài)變量的代碼上加鎖,以保證線程安全。如果你不需要線程安全,可以使用這個(gè)選項(xiàng)。-fvisibility-inlines-hidden默認(rèn)隱藏所有內(nèi)聯(lián)函數(shù),從而減小導(dǎo)出符號(hào)表的大小,既能縮減文件的大小,還能提高運(yùn)行性能,我們強(qiáng)烈建議你在編譯任何共享庫(kù)的時(shí)候使用該選項(xiàng)。參見 -fvisibility=hidden 選項(xiàng)。
LDFLAGS
LDFLAGS 是傳遞給連接器的選項(xiàng)。這是一個(gè)常被忽視的變量,事實(shí)上它對(duì)優(yōu)化的影響也是很明顯的。
-s刪除可執(zhí)行程序中的所有符號(hào)表和所有重定位信息。其結(jié)果與運(yùn)行命令 strip 所達(dá)到的效果相同。-static連接器將忽略動(dòng)態(tài)連接庫(kù),同時(shí)通過將靜態(tài)目標(biāo)文件直接包含到結(jié)果目標(biāo)文件完成對(duì)所有引用的解析。-shared鏈接器將生成共享目標(biāo)代碼,該共享庫(kù)可在運(yùn)行時(shí)動(dòng)態(tài)鏈接到程序形成完整可執(zhí)行體。而且,如果使用 gcc
命令創(chuàng)建共享庫(kù)作為其輸出,該選項(xiàng)可以防止鏈接器將缺失 main() 方法視為錯(cuò)誤。為了可以正確工作,應(yīng)該一致地使用選項(xiàng) -fpic 和
-fPIC
以及目標(biāo)平臺(tái)選項(xiàng)編譯構(gòu)成同一庫(kù)的所有共享目標(biāo)模塊。特別是,該選項(xiàng)可能需要生成特殊代碼來(lái)讓構(gòu)造函數(shù)正常工作。由于不正確的選項(xiàng)設(shè)定而產(chǎn)生的錯(cuò)誤可能很
不明顯,而且也沒有警告消息。-shared-libgcc鏈接共享版本的libgcc 。當(dāng)應(yīng)用程序需要從一個(gè)共享庫(kù)代碼拋出另一個(gè)共享庫(kù)捕獲的異常時(shí),需要使用共享版本的libgcc 。-static-libgcc鏈接靜態(tài)版本的libgcc 。該選項(xiàng)可能會(huì)引起 C++ 和 Java 中的異常處理問題。-Wl,optionsoptions是由一個(gè)或多個(gè)逗號(hào)分隔的傳遞給鏈接器的選項(xiàng)列表。其中的每一個(gè)選項(xiàng)均會(huì)作為命令行選項(xiàng)提供給鏈接器。-Wl,-On當(dāng)n>0時(shí)將會(huì)優(yōu)化輸出,但是會(huì)明顯增加連接操作的時(shí)間,這個(gè)選項(xiàng)是比較安全的。-Wl,--sort-common把全局公共符號(hào)按照大小排序后放到適當(dāng)?shù)妮敵龉?jié),以防止符號(hào)間因?yàn)榕挪枷拗贫霈F(xiàn)間隙。-Wl,--no-keep-memory按需讀取符號(hào)表而不是將它們緩存在內(nèi)存中,這樣可以減少內(nèi)存用量,但是會(huì)降低運(yùn)行速度。僅在連接大型可執(zhí)行文件時(shí)有些意義。-Wl,-s剝離輸出文件中所有的符號(hào)信息,這個(gè)選項(xiàng)是比較安全的。-Wl,-z now默認(rèn)僅在需要時(shí)才動(dòng)態(tài)加載共享代碼,這樣減少了內(nèi)存用量,但是可能降低運(yùn)行速度。而使用這個(gè)選項(xiàng)可以強(qiáng)制在啟動(dòng)時(shí)就加載共享代碼,這可能導(dǎo)致啟動(dòng)速度減慢,并且占用更多的內(nèi)存,但是運(yùn)行速度時(shí)速度可能加快。-Wl,--enable-new-dtags在ELF中創(chuàng)建新式的"dynamic tags",但在老式的ELF系統(tǒng)上無(wú)法識(shí)別。-Wl,--as-needed移除不必要的符號(hào)引用,僅在實(shí)際需要的時(shí)候才連接,可以生成更高效的代碼。
最后說兩個(gè)與優(yōu)化無(wú)關(guān)的系統(tǒng)環(huán)境變量,因?yàn)闀?huì)影響GCC編譯程序的方式,下面兩個(gè)是咱中國(guó)人比較關(guān)心的:
LANG指定編譯程序使用的字符集,可用于創(chuàng)建寬字符文件、串文字、注釋;默認(rèn)為英文。[目前只支持日文"C-JIS,C-SJIS,C-EUCJP",不支持中文]LC_ALL指定多字節(jié)字符的字符分類,主要用于確定字符串的字符邊界以及編譯程序使用何種語(yǔ)言發(fā)出診斷消息;默認(rèn)設(shè)置與
LANG相同。中文相關(guān)的幾項(xiàng):"zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8
, zh_TW.BIG5"。
本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u1/44419/showart_468601.html |
|