1. 前言
UBOOT版本:uboot2018.03,開發板myimx8mmek240,
2. 函式 cc-option
編譯選項變數cc-option 定義在 scripts/Kbuild.include中:
# scripts/Kbuild.include
# output directory for tests below
TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
# Exit code chooses option. "$$TMP" is can be used as temporary file and
# is automatically cleaned up.
# modifed for U-Boot: prevent cc-option from leaving .*.su files
try-run = $(shell set -e; \
TMP="$(TMPOUT).$$$$.tmp"; \
TMPO="$(TMPOUT).$$$$.o"; \
TMPSU="$(TMPOUT).$$$$.su"; \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
fi; \
rm -f "$$TMP" "$$TMPO" "$$TMPSU")
# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
cc-option = $(call try-run,\
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
2.1 command >/dev/null 2>&1
command >/dev/null 2>&1 == command 1>/dev/null 2>&1
- ‘command’ : 表示shell命令或者為一個可執行程式;
- ‘>’ : 表示重定向到哪里;
- ‘/dev/null’ : 表示Linux的空設備檔案;
- ‘2’ : 表示標準錯誤輸出;
- ‘&1’ : &表示等同于的意思,2>&1,表示2的輸出重定向等于于1;
(1)1>/dev/null:表示標準輸出重定向到空設備檔案,也就是不輸出任何資訊到終端,不顯示任何資訊,
(2)2>&1:表示標準錯誤輸出重定向等同于標準輸出,因為之前標準輸出已經重定向到了空設備檔案,所以標準錯誤輸出也重定向到空設備檔案,
這條命令的意思就是:將錯誤輸出2重定向到標準輸出1,然后將標準輸出1全部放到/dev/null檔案,也就是清空,所以可以看出" >/dev/null 2>&1 "常用來避免shell命令或者程式等運行中有內容輸出到終端,
2.2 cc-option決議
舉例:
PLATFORM_CPPFLAGS += $(call cc-option,-marm,)
函式cc-option
- 第一個引數賦給$ (1)(這里是指-marm),
- 第二個引數給$(2)(這里為空),
變數cc-option的值是函式try-run的執行結果,函式try-run又是$(shell ....)輸出的結果;也就是if ...else...的結果,在函式try-run中:
- $(1) : $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "
- $(2) : 函式cc-option的 $(1) (這里是指-marm)
- $(3) : 函式cc-option的 $(2) (這里為空)
如果函式try-run的$(1)能執行,那么echo $(2),否則echo $(3);echo 的值正是cc-option的值 ,
綜上:該例子的意思是如果交叉編譯工具$(CC)支持cc-optionl函式的引數一表示的選項(也就是指-marm),那么cc-option函式的回傳就是該選項(指-marm),否則回傳的是call函式的引數二表示的選項,
cc-option:檢測$(CC) 是否支持給定的選項
3. 平臺代碼重定位需要的編譯選項$(PLATFORM_RELFLAGS))
#(1) 頂層config.mk
PLATFORM_RELFLAGS :=
#(2) arch/arm/config.mk
PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections \
-fno-common -ffixed-r9
PLATFORM_RELFLAGS += $(call cc-option, -msoft-float) \
$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) //空
......
PLATFORM_RELFLAGS += $(LLVM_RELFLAGS) //空
#(3) arch/arm/cpu/armv8/config.mk
PLATFORM_RELFLAGS += -fno-common -ffixed-x18
展開為:
PLATFORM_RELFLAGS= -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18
引數講解見本文末尾參考小節,
4. 平臺代碼預處理需要的編譯選項$(PLATFORM_CPPFLAGS)
#(1) 頂層config.mk
PLATFORM_CPPFLAGS :=
......
ifdef FTRACE
PLATFORM_CPPFLAGS += -finstrument-functions -DFTRACE //除錯時使用,一般不會打開
endif
# Allow use of stdint.h if available
ifneq ($(USE_STDINT),)
PLATFORM_CPPFLAGS += -DCONFIG_USE_STDINT //空
endif
RELFLAGS := $(PLATFORM_RELFLAGS) //見上一小節
PLATFORM_CPPFLAGS += $(RELFLAGS)
PLATFORM_CPPFLAGS += -pipe
export PLATFORM_CPPFLAGS
#(2) arch/arm/config.mk
# Choose between ARM/Thumb instruction sets
ifeq ($(CONFIG_$(SPL_)SYS_THUMB_BUILD),y)
AFLAGS_IMPLICIT_IT := $(call as-option,-Wa$(comma)-mimplicit-it=always)
PF_CPPFLAGS_ARM := $(AFLAGS_IMPLICIT_IT) \
$(call cc-option, -mthumb -mthumb-interwork,\
$(call cc-option,-marm,)\
$(call cc-option,-mno-thumb-interwork,)\
)
else //走else分支
PF_CPPFLAGS_ARM := $(call cc-option,-marm,) \
$(call cc-option,-mno-thumb-interwork,) //空
endif
......
# Try if EABI is supported, else fall back to old API,
# i. e. for example:
# - with ELDK 4.2 (EABI supported), use:
# -mabi=aapcs-linux
# - with ELDK 4.1 (gcc 4.x, no EABI), use:
# -mabi=apcs-gnu
# - with ELDK 3.1 (gcc 3.x), use:
# -mapcs-32
PF_CPPFLAGS_ABI := $(call cc-option,\ //空
-mabi=aapcs-linux,\
$(call cc-option,\
-mapcs-32,\
$(call cc-option,\
-mabi=apcs-gnu,\
)\
)\
)
......
PLATFORM_CPPFLAGS += -D__ARM__ //定義宏__ARM__
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARM) $(PF_CPPFLAGS_ABI) //空
ifneq ($(CONFIG_SPL_BUILD),y) //編譯SPL的時候才會傳納-DCONFIG_SPL_BUILD
......
# The movt / movw can hardcode 16 bit parts of the addresses in the
# instruction. Relocation is not supported for that case, so disable
# such usage by requiring word relocations.
PLATFORM_CPPFLAGS += $(call cc-option, -mword-relocations)
PLATFORM_CPPFLAGS += $(call cc-option, -fno-pic) //不編譯SPL的時候支持
endif
#(3) arch/arm/cpu/armv8/config.mk
PF_NO_UNALIGNED := $(call cc-option, -mstrict-align) //支持
PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
#(4) arch/arm/Makefile
# This selects which instruction set is used.
arch-$(CONFIG_ARM64) =-march=armv8-a -mgeneral-regs-only
# On Tegra systems we must build SPL for the armv4 core on the device
# but otherwise we can use the value in CONFIG_SYS_ARM_ARCH
ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TEGRA),yy)
arch-y += -D__LINUX_ARM_ARCH__=4
else
arch-y += -D__LINUX_ARM_ARCH__=$(CONFIG_SYS_ARM_ARCH)
endif
# Evaluate arch cc-option calls now
arch-y := $(arch-y) //-march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8
# Evaluate tune cc-option calls now
tune-y := $(tune-y)
PLATFORM_CPPFLAGS += $(arch-y) $(tune-y)
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) //我使用的單板未定義machine-y
PLATFORM_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))//空
展開為:
PLATFORM_CPPFLAGS= -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8
引數講解見本文末尾參考小節,
5. 編譯系統kbuild需要的預處理選項$(KBUILD_CPPFLAGS)
# /scripts/Makefile.spl
KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD
#(1) 頂層config.mk
KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__ //定義__KERNEL__和__UBOOT__ 宏
# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
KBUILD_CPPFLAGS += $(KCPPFLAGS)
......
展開為:
KBUILD_CPPFLAGS=-D__KERNEL__ -D__UBOOT__
引數講解見本文末尾參考小節,
6. 編譯系統kbuild需要的編譯選項$(KBUILD_CFLAGS)
# /scripts/Makefile.spl
KBUILD_CFLAGS := -Wall -Wstrict-prototypes \
-Wno-format-security \
-fno-builtin -ffreestanding
KBUILD_CFLAGS += -fshort-wchar
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os
else
KBUILD_CFLAGS += -O2
endif
KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks)
KBUILD_CFLAGS += -g
KBUILD_CFLAGS += $(call cc-option,-Wno-format-nonliteral)
# Prohibit date/time macros, which would make the build non-deterministic
KBUILD_CFLAGS += $(call cc-option,-Werror=date-time)
# Report stack usage if supported
ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-stack-usage.sh $(CC)),y)
KBUILD_CFLAGS += -fstack-usage
endif
#(1) 頂層config.mk
KBUILD_CFLAGS += $(KCFLAGS)
展開為:
KBUILD_CFLAGS=-Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time
引數講解見本文末尾參考小節,
7. 預處理需要的編譯選項$(cpp_flags)
#(1) 頂層config.mk
# Use UBOOTINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
UBOOTINCLUDE := \
-Iinclude \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
$(if $(CONFIG_$(SPL_)SYS_THUMB_BUILD), \
$(if $(CONFIG_HAS_THUMB2),, \
-I$(srctree)/arch/$(ARCH)/thumb1/include),) \
-I$(srctree)/arch/$(ARCH)/include \ //-I./arch/arm/include
-include $(srctree)/include/linux/kconfig.h //-include ./include/linux/kconfig.h
......
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
// $(CC) -print-file-name=include : 列印GCC默認搜索include頭檔案的路徑
......
# FIX ME
cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) $(NOSTDINC_FLAGS)
預處理編譯選項$(cpp_flags)定義在頂層Makefile中,主要由:編譯系統kbuild需要的預處理選項 $(KBUILD_CPPFLAGS)、平臺代碼預處理需要的編譯選項 $(PLATFORM_CPPFLAGS)、UBOOT要使用的頭檔案路徑、CC默認搜索include頭檔案的路徑組成,
展開為:
cpp_flags=-D__KERNEL__ -D__UBOOT__ -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include
8. 編譯需要的編譯選項$(c_flags)
#(1) 頂層config.mk
c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
編譯選項$(c_flags)定義在頂層Makefile中,主要由 $(KBUILD_CFLAGS) (編譯系統kbuild需要的編譯選項)和 $(cpp_flags)(uboot整體代碼預處理需要的編譯選項)組成,
展開為:
c_flags=-Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -fshort-wchar -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__KERNEL__ -D__UBOOT__ -D__ARM__ -fno-pic -mstrict-align -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -fno-common -ffixed-x18 -pipe -march=armv8-a -mgeneral-regs-only -D__LINUX_ARM_ARCH__=8 -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -nostdinc -isystem /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.3.1/include
引數講解見本文末尾參考小節,
9. 鏈接需要的編譯選項$(LDFLAGS_FINAL)
#(1) 頂層config.mk
LDFLAGS_FINAL :=
......
LDFLAGS_FINAL += -Bstatic
export LDFLAGS_FINAL
#(2) arch/arm/config.mk
LDFLAGS_FINAL += --gc-sections
展開為:
LDFLAGS_FINAL= --gc-sections -Bstatic //指定從-L指定的目錄串列中查找libfoo.a
引數講解見本文末尾參考小節,
10. 參考
[1] -Wall:打開全部編譯告警;
[2] -Wstrict-prototypes:如果在未指定引數型別的情況下宣告或定義函式,則發出警告, (如果前面有一個指定引數型別的宣告,則允許在沒有警告的情況下進行舊式函式定義);
[3] -Wformat、-Wformat=n、-Wformat-security:Wformat、-Wformat=n:檢查對 printf 和 scanf 等的呼叫,以確保提供的引數具有適合指定格式字串的型別,并且格式字串中指定的轉換是有意義的,這包括 printf、scanf、strftime 和 strfmon(X/Open 擴展,不在 C 標準中)系列(或其他特定于目標的系列)中的標準函式和其他由格式屬性(請參閱函式屬性)指定的函式,在沒有指定格式屬性的情況下檢查哪些函式取決于所選的標準版本,并且對沒有指定屬性的函式的這種檢查被 -ffreestanding 或 -fno-builtin 禁用;-Wformat-security:如果指定了“-Wformat”,還會警告使用表示可能的安全問題的格式函式,目前,這會警告呼叫 printf 和 scanf 函式,其中格式字串不是字串文字并且沒有格式引數,如 printf (foo);
[4] -Wformat-nonliteral、-Wno-format-nonliteral :如果指定了 -Wformat,如果格式字串不是字串文字并且因此無法檢查,也會發出警告,除非格式函式將其格式引數作為 va_list;
[5] -fno-builtin、-fno-builtin-function:不識別不以“builtin”作為前綴的內置函式,;
[6] -ffreestanding:編譯輸出(可執行檔案)是運行在一個 freestanding environment 環境下,這個選項 包含 -fno-builtin 選項,等同于 -fno-hosted;
[7] -O -O0 -O1 -O2 -O3 -Os -Ofast -Og -Oz:-Os相當于-O2.5,是使用了所有-O2的優化選項,但又不縮減代碼尺寸的方法;
[8] -fstack-protector、-fno-stack-protector、-fstack-protector-all:-fstack-protector:啟用堆疊保護,不過只為區域變數中含有 char 陣列的函式插入保護代碼;-fstack-protector-all:啟用堆疊保護,為所有函式插入保護代碼;-fno-stack-protector:禁用堆疊保護,GCC中的堆疊保護機制;
[9] -fdelete-null-pointer-checks/-fno-delete-null-pointer-checks:delete-null-pointer-checks是一種優化手段,通過全域的資料流分析來識別和洗掉所有對空指標的檢測操作;編譯器假定對空指標的解參考會造成程式終止,但因為有些環境下,這一結論并不一定成立,而O2,O3和Os時會開啟此優化,因此GCC增加了選項-fno-delete-null-pointer-checks;
[10] -g:告訴gcc生成并嵌入除錯資訊;
[11] -fstack-usage:為每一個函式輸出堆疊使用資訊,每一個原始碼檔案生成一個.su (Stack Usage)檔案, su檔案中有每一個函式的堆疊使用資訊;
[12] -Wstack-usage=byte-size:如果函式的堆疊使用量可能超過位元組大小,則發出警告,;
[13] -Wdate-time:當遇到宏__TIME_、 宏__DATE__ 、 宏__TIMESTAMP__時發出警告;
[14] -Werror=date-time:將指定的警告變成錯誤;
[15] -fpic、-FPIC、-fpie、-fPIE:相同點:都是為了在動態庫中生成位置無關的代碼,通過全域偏移表(GOT)訪問所有常量地址,程式啟動時動態加載程式決議GOT條目,不同點:如果鏈接的可執行檔案的GOT大小超過計算機特定的最大大小,則會從聯結器收到錯誤訊息,指示-fpic不起作用;在這種情況下,請使用-fPIC重新編譯,GOT大小根據作業系統的不同而大小不一樣,SPARC上為8k,在AArch64上為28k,在m68k和RS / 6000上為32k,x86沒有此限制;-fpie、-fPIE這些選項類似于 -fpic 和 -fPIC,但生成的與位置無關的代碼只能鏈接到可執行檔案中, 通常這些選項用于編譯將使用 -pie GCC 選項鏈接的代碼,-fpie 和 -fPIE 都定義了宏 pie 和 PIE, 宏的 -fpie 值為 1,-fPIE 值為 2,-fno-pic :生產位置有關代碼,
[16] -ffixed-reg:生成的代碼不要用暫存器r9,uboot中用來指另做它用;
[17] -ffunction-sections、-fdata-sections:在鏈接生成最終可執行檔案時,如果帶有-Wl,--gc-sections引數,并且之前編譯目標檔案時帶有-ffunction-sections、-fdata-sections引數,則聯結器ld不會鏈接未使用的函式,從而減小可執行檔案大小;
[18] -fshort-wchar:強制將wchar_t指定成兩個位元組,使用這個欄位常常是因為wchar_t型別在Windows和Linux平臺下位元組大小的不同,但這樣做只會改變代碼中實作的部分,而內部庫或者是第三方庫中用到的介面和函式都是沒有變的,仍然采用的是4位元組編碼
[19] --gc-sections ,-gc-sections:同上
[20] -fcommon、-fno-common: 指定編譯器將未初始化的全域變數放在物件檔案的BSS部分,
[21] -mthumb、-marm、-mthumb-interwork、-mno-thumb-interwork:-marm 和-mthumb用來執行生成的代碼在arm模式還是thumb模式執行,-mno-thumb-interwork 是指沒有ARM/Thumb之間的切換
[22] -mword-relocations:由于使用pic時movt / movw指令會硬編碼16bit的地址域,而uboot的relocation并不支持這個, 所以arm平臺使用mword-relocations來生成位置無關代碼
[23] -mabi=name:這些' -m '選項是為ARM埠定義的,為指定的ABI(Application Binary Interface)生成代碼,允許的值是:' apcs-gnu ',' atpcs ', ' aapcs ', ' aapcs-linux '和' iwmmxt ',
[24] -mstrict-align、-mno-strict-align:是否允許非對齊訪問;
[25] -finstrument-functions:生成函式的進入和退出的檢測呼叫;
[26] -pipe:編譯的各個階段之間使用管道而不是臨時檔案進行通信,這在匯編程式無法從管道讀取資料的某些系統上無法作業;但是GNU匯編器沒有問題;
[27] -march=name:指定目標架構的名稱,以及一個或多個可選的特性修飾符;
[28] -mgeneral-regs-only:生成只使用通用暫存器的代碼,這將防止編譯器使用浮點暫存器和高級SIMD暫存器,但不會對匯編程式施加任何限制;
[29] -Bdynamic、-Bstatic:-Bdynamic and -Bstatic這兩個選項是position-dependent選項,影響后面命令列出現的-lname,-Bdynamic (default):在-L指定的目錄串列中查找libfoo.so和libfoo.a;-Bstatic:在-L指定的目錄串列中查找libfoo.a,注意,歷史上-Bstatic和-static同義,編譯器driver的-static是個不同的選項,除了傳遞-static給ld外,還會去除預設的--dynamic-linker,影響libgcc libc等的鏈接;
[30] 下面以uboot的編譯和鏈接程序arm gcc相關的引數,具體內容可以參考:官方檔案;pdf版本下載;
[31] arm gcc 編譯與鏈接引數
[uboot] (番外篇)uboot relocation介紹
[32] 一個問題引出的>/dev/null 2>&1詳解
[33] linuxC編譯引數CPPFLAGS、CFLAGS、LDFLAGS引數的理解
[34] Linux內核移植 part1:arm gcc 編譯與鏈接引數
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/534038.html
標籤:嵌入式
