同一个编译脚本下 arm 交叉编译 生成文件大小不一致的问题分析
最近在工作中需要編譯一個(gè)庫(kù)文件,使用gcc的交叉編譯環(huán)境。遇到了一個(gè)令人迷惑的問(wèn)題:同樣的編譯環(huán)境,同樣的代碼,只是因?yàn)樵谟脖P(pán)上存放的位置不同,編譯出來(lái)的.o文件大小就會(huì)產(chǎn)生差異。此刻,終于搞明白了原因。記錄一下。
背景知識(shí):先了解下gcc編譯選項(xiàng):(以下內(nèi)容均載自網(wǎng)絡(luò),有的翻譯可能有點(diǎn)拗口,湊合看吧)
參考鏈接https://www.cnblogs.com/lsgxeva/p/7605141.html
GCC的-g選項(xiàng)用于配置GDB調(diào)試級(jí)別
如果不打開(kāi)-g或者-ggdb(GDB專(zhuān)用)調(diào)試開(kāi)關(guān),GCC編譯時(shí)不會(huì)加入調(diào)試信息,因?yàn)檫@會(huì)增大生成代碼的體積。GCC采用了分級(jí)調(diào)試,通過(guò)在-g選項(xiàng)
后附加數(shù)字1、2或3來(lái)指定在代碼中加入調(diào)試信息量。默認(rèn)的級(jí)別是2(-g2),此時(shí)調(diào)試信息包括擴(kuò)展的符號(hào)表、行號(hào)、局部或外部變量信息。
級(jí)別3(-g3)包含級(jí)別2中的調(diào)試信息和源代碼中定義的宏。
級(jí)別1(-g1)不包含局部變量和與行號(hào)有關(guān)的調(diào)試信息,只能用于回溯跟蹤和堆棧轉(zhuǎn)儲(chǔ)之用。
回溯跟蹤指的是監(jiān)視程序在運(yùn)行過(guò)程中的函數(shù)調(diào)用歷史,堆棧轉(zhuǎn)儲(chǔ)則是一種以原始的十六進(jìn)制格式保存程序執(zhí)行環(huán)境的方法,兩者都是經(jīng)常用到的調(diào)試手段。
順別學(xué)習(xí)下GCC的-O選項(xiàng),這是用來(lái)優(yōu)化代碼的(優(yōu)化指的是速度和體積)
-O0:這個(gè)等級(jí)(字母“O”后面跟個(gè)零)關(guān)閉所有優(yōu)化選項(xiàng),也是CFLAGS或CXXFLAGS中沒(méi)有設(shè)置-O等級(jí)時(shí)的默認(rèn)等級(jí)。這樣就不會(huì)優(yōu)化代碼,這通常不是我們想要的。
-O1:這是最基本的優(yōu)化等級(jí)。編譯器會(huì)在不花費(fèi)太多編譯時(shí)間的同時(shí)試圖生成更快更小的代碼。這些優(yōu)化是非?;A(chǔ)的,但一般這些任務(wù)肯定能順利完成。
-O2:-O1的進(jìn)階。這是推薦的優(yōu)化等級(jí),除非你有特殊的需求。-O2會(huì)比-O1啟用多一些標(biāo)記。設(shè)置了-O2后,編譯器會(huì)試圖提高代碼性能而不會(huì)增大體積和大量占用的編譯時(shí)間。
-O3:這是最高最危險(xiǎn)的優(yōu)化等級(jí)。用這個(gè)選項(xiàng)會(huì)延長(zhǎng)編譯代碼的時(shí)間,并且在使用gcc4.x的系統(tǒng)里不應(yīng)全局啟用。自從3.x版本以來(lái)gcc的行為已經(jīng)有了極大地改變。在3.x,-O3生成的代碼也只是比-O2快一點(diǎn)點(diǎn)而已,而gcc4.x中還未必更快。用-O3來(lái)編譯所有的軟件包將產(chǎn)生更大體積更耗內(nèi)存的二進(jìn)制文件,大大增加編譯失敗的機(jī)會(huì)或不可預(yù)知的程序行為(包括錯(cuò)誤)。這樣做將得不償失,記住過(guò)猶不及。在gcc 4.x.中使用-O3是不推薦的。
-Os:這個(gè)等級(jí)用來(lái)優(yōu)化代碼尺寸。其中啟用了-O2中不會(huì)增加磁盤(pán)空間占用的代碼生成選項(xiàng)。這對(duì)于磁盤(pán)空間極其緊張或者CPU緩存較小的機(jī)器非常有用。但也可能產(chǎn)生些許問(wèn)題,因此軟件樹(shù)中的大部分ebuild都過(guò)濾掉這個(gè)等級(jí)的優(yōu)化。使用-Os是不推薦的。
GCC提供選項(xiàng)控制代碼的優(yōu)化等級(jí):
這些選項(xiàng)可以實(shí)現(xiàn)不同程度的優(yōu)化。
沒(méi)有任何優(yōu)化選項(xiàng)的話(huà),編譯時(shí)的目標(biāo)是降低編譯成本,并使調(diào)試產(chǎn)生預(yù)期的結(jié)果。語(yǔ)句是獨(dú)立的:如果你使程序停止在語(yǔ)句之間設(shè)置的斷點(diǎn)處,你可以改變?nèi)魏巫兞康闹祷蛘吒淖兂绦蛴?jì)數(shù)器的值使程序執(zhí)行任意函數(shù)中的語(yǔ)句并得到源代碼中期望的結(jié)果。
打開(kāi)優(yōu)化標(biāo)志使編譯器嘗試以編譯時(shí)間和可能的調(diào)試程序的能力為代價(jià)來(lái)改進(jìn)性能和/或代碼大小。
編譯器根據(jù)程序的信息執(zhí)行優(yōu)化。 一次編譯多個(gè)文件生成單個(gè)可執(zhí)行文件的模式允許編譯器在編譯每個(gè)文件時(shí)使用從所有文件中獲取的信息。
并非所有優(yōu)化都由標(biāo)志直接控制。以下僅列出具有標(biāo)志的優(yōu)化。
只有在命令行上設(shè)置-O或其他等級(jí)的優(yōu)化選項(xiàng)時(shí),才會(huì)啟用大多數(shù)優(yōu)化。 否則,即使指定了單獨(dú)的優(yōu)化標(biāo)志,它們也會(huì)被禁用。
根據(jù)目標(biāo)和GCC的配置方式,可以在每個(gè)-O級(jí)別啟用略有不同的優(yōu)化集。
-O0:減少編譯時(shí)間并使調(diào)試可以產(chǎn)生預(yù)期的結(jié)果,這也是默認(rèn)的優(yōu)化等級(jí)。
-O、-O1:優(yōu)化編譯需要更多時(shí)間,并且大型函數(shù)需要更多內(nèi)存。使用-O選項(xiàng),編譯器會(huì)嘗試減小代碼尺寸減少執(zhí)行時(shí)間,不執(zhí)行任何需要大量編譯時(shí)間的優(yōu)化。
-O選項(xiàng)打開(kāi)了如下優(yōu)化標(biāo)志:
-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments -fcompare-elim -fcprop-registers -fdce -fdefer-pop
-fdelayed-branch -fdse -fforward-propagate -fguess-branch-probability -fif-conversion2 -fif-conversion
-finline-functions-called-once -fipa-pure-const -fipa-profile -fipa-reference -fmerge-constants -fmove-loop-invariants
-fshrink-wrap -fsplit-wide-types -ftree-bit-ccp -ftree-ccp -fssa-phiopt -ftree-ch -ftree-copy-prop -ftree-copyrename -ftree-dce
-ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre -ftree-phiprop -ftree-sink -ftree-slsr -ftree-sra -ftree-pta
-ftree-ter -funit-at-a-time
-O2:相對(duì)-O優(yōu)化更多。 GCC幾乎執(zhí)行所有支持的優(yōu)化,但不涉及空速權(quán)衡。 與-O相比,此選項(xiàng)增加了編譯時(shí)間和生成代碼的性能。
-O2除了打開(kāi)所有-O指定的優(yōu)化標(biāo)志,還打開(kāi)了如下優(yōu)化標(biāo)志:
-fthread-jumps
-falign-functions? -falign-jumps -falign-loops? -falign-labels -fcaller-saves -fcrossjumping -fcse-follow-jumps
-fcse-skip-blocks -fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively -fexpensive-optimizations -fgcse
-fgcse-lm -fhoist-adjacent-loads -finline-small-functions -findirect-inlining -fipa-cp -fipa-cp-alignment -fipa-sra -fipa-icf
-fisolate-erroneous-paths-dereference -flra-remat -foptimize-sibling-calls -foptimize-strlen -fpartial-inlining -fpeephole2
-freorder-blocks -freorder-blocks-and-partition -freorder-functions -frerun-cse-after-loop -fsched-interblock? -fsched-spec
-fschedule-insns? -fschedule-insns2 -fstrict-aliasing -fstrict-overflow -ftree-builtin-call-dce -ftree-switch-conversion
-ftree-tail-merge -ftree-pre -ftree-vrp -fipa-ra
-O3:相對(duì)-O2優(yōu)化更多。
-O3除了打開(kāi)所有-O2指定的優(yōu)化標(biāo)志,還打開(kāi)了如下優(yōu)化標(biāo)志:
-finline-functions, -funswitch-loops,
-fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-loop-distribute-patterns, -ftree-slp-vectorize,
-fvect-cost-model, -ftree-partial-pre and -fipa-cp-clone
-Os:優(yōu)化尺寸。 -Os啟用所有通常不會(huì)增加代碼大小的-O2優(yōu)化。 它還執(zhí)行旨在減少代碼大小的進(jìn)一步優(yōu)化。
-Os關(guān)閉如下優(yōu)化標(biāo)志:
-falign-functions? -falign-jumps? -falign-loops -falign-labels? -freorder-blocks
-freorder-blocks-and-partition -fprefetch-loop-arrays
-Ofast:無(wú)視嚴(yán)格的標(biāo)準(zhǔn)合規(guī)性。 -Ofast啟用所有-O3優(yōu)化。 它還打開(kāi)并非對(duì)所有符合標(biāo)準(zhǔn)的程序有效的優(yōu)化。 它打開(kāi)
-ffast-math和Fortran特定的-fno-protect-parens和-fstack-arrays。
-Og:優(yōu)化調(diào)試體驗(yàn)。 -Og啟用不會(huì)干擾調(diào)試的優(yōu)化。 它是標(biāo)準(zhǔn)編輯 - 編譯 - 調(diào)試周期可以選擇的優(yōu)化級(jí)別,提供合理的優(yōu)化級(jí)別,同時(shí)保持快速編譯和良好的調(diào)試體驗(yàn)。
如果使用多個(gè)-O選項(xiàng)(包含或不包含級(jí)別編號(hào)),則最后一個(gè)選項(xiàng)是有效的選項(xiàng)。
背景知識(shí)了解后,問(wèn)題顯而易見(jiàn)
引起上述問(wèn)題的原因就是GDB調(diào)試級(jí)別。因?yàn)榫幾g腳本使用了-g選項(xiàng),因此導(dǎo)致生成的二進(jìn)制文件包含了適應(yīng)本地環(huán)境的調(diào)試信息,諸如代碼的完整路徑。這會(huì)導(dǎo)致同樣的編譯腳本在不同的目錄中進(jìn)行編譯時(shí)所生成的二進(jìn)制文件的大小會(huì)有差異。要避免這個(gè)差異,只要將-g選項(xiàng)刪掉即可?;蛘邔?xiě)成-g0也可以。
貼出我的Makefile腳本
=============================
TOOLCHAIN_PREFIX = arm-none-eabi-
TARGET = LIBRARY
CC = $(TOOLCHAIN_PREFIX)gcc
CXX = $(TOOLCHAIN_PREFIX)g++
AR = $(TOOLCHAIN_PREFIX)ar
OUT_FILE_NAME = lib$(TARGET).a
COMMON_FLAGS =? -mcpu=cortex-m33 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 -Og -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -Wall? -g0(原先這里是-g3) -T
CFLAGS = -std=c11
CXXFLASG = -std=c++14
INC = -Iinclude
OBJS = $(patsubst %.cpp,%.cpp.o,$(wildcard *.cpp)) $(patsubst %.c,%.c.o,$(wildcard *.c))
DEPS = $(patsubst %.o,%.d,$(OBJS))
# Enumerating of every *.cpp as *.o and using that as dependency
$(OUT_FILE_NAME): $(OBJS)
?? ?$(AR) -r -o $@ $^
%.cpp.o: %.cpp
?? ?$(CXX) -c $(INC) $(COMMON_FLAGS) $(CXXFLAGS) -o $@? $<
%.c.o: %.c
?? ?$(CC) -c $(INC) $(COMMON_FLAGS) $(CFLAGS) -o $@? $<
clean:
?? ?rm -f $(OBJS) $(DEPS) $(OUT_FILE_NAME)
check:
?? ?@echo $(OBJS)
?? ?@echo $(DEPS)
==================================
?
總結(jié)
以上是生活随笔為你收集整理的同一个编译脚本下 arm 交叉编译 生成文件大小不一致的问题分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: PostgreSql中使用ctid去重
- 下一篇: 学习新技能_如何学习新技能