Linux核心編譯
一、linux核心的配置與編譯:
1.配置核心
1)導入預設配置:
make xxxx_defconfig
注1:xxxx表示核心支援的晶片的名稱 比如make exynos_defconfig
注2:核心源碼中對每個支援的晶片都有預設的配置,預設配置很少隻能保證系統完成最基本的功能
注3:可以通過直接修改.config檔案來進行核心的配置(麻煩),所有核心配置的本質都是修改.config檔案
注4:配置檔案中xxxx=y表示添加了該功能,注釋表示不添加該功能(減小核心體積)
2)修改配置(核心提供了幾種簡單的配置方法,其本質都是修改.config檔案中的配置)
make gconfig 依賴于GTK庫
make xconfig 依賴于QT庫
make config 麻煩
-> make menuconfig
選中的狀态切換:空格
搜尋一個選項:/
[ ] 有兩種狀态。
輸入Y,顯示為“*”,表示核心中該功能被選中,相關功能代碼将會被編譯進核心。
輸入N,顯示為空,表示核心中該功能沒有被選中。
< > 有三種狀态
輸入Y,顯示為“*”,表示核心中該功能被選中
輸入N,顯示為空,表示核心中該功能沒有被選中
輸入M,則顯示為“M”,表示核心中該功能被選為子產品(編譯後與核心鏡像不在同一檔案)
2.編譯核心
make uImage 編譯核心鏡像(編譯選中為“*”的選項到核心)
make modules 編譯核心子產品(編譯選中為“M”的選項)
make dtbs 編譯裝置樹檔案(使驅動與裝置建立關系的檔案)
make clean 删除檔案
二、在核心中添加子菜單:
每一級目錄中都包含一個Kconfig檔案,用于生成選配菜單的。按照Kconfig的文法修改對應的Kconfig檔案就可以在菜單中添加自己的選項。在一個Kconfig檔案中menu是本級菜單,如menu "Character devices",如果我們想在該菜單下自己添加子菜單按照文法添加在menu和endmenu之間即可
文法:
config FS4412_LED # 固定文法,config XXX,XXX用來與MakeFile關聯,即配置後MakeFile會按照該配置進行編譯
tristate "FS4412LED Device Support"
# tristate “菜單顯示名稱”;tristate表示該選項有三個狀态<>(即可以選擇成N/Y/M),bool表示有兩個選項[](N/Y)
default n
# default n 預設是'N',即不添加該功能 default y 預設添加該功能default m 預設編譯成子產品(重新配置後生效)
depends on ARCH_EXYNOS4
# depends on 依賴的菜單 當有依賴關系的選項沒有被選擇時該選項也不顯示
help
support leddevice on FS4412 develop board # 幫助文檔 可有可無
詳情參考:Documentation/kbuild
将自己的子產品添加到菜單的步驟:
1.修改Kconfig添加子菜單
2.添加對應的.C檔案(驅動檔案)
3.修改對應的Makefile使菜單與編譯關聯(将驅動檔案編譯)
三、linux核心(uImage)的編譯過程:
1.在頂層目錄下執行make uImage
2.頂層目錄下的MakeFile
155 srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
# srctree為目前MakeFile所在目錄
198 ARCH ?= arm # 自己修改的
203 SRCARCH := $(ARCH)
504 include $(srctree)/arch/$(SRCARCH)/Makefile
-> include arch/arm/MakeFile
-> 執行make uImage後會根據我們設定的CPU架構,執行對應架構下的MakeFile
3.arch/arm/MakeFile
291 boot := arch/arm/boot
299 BOOT_TARGETS = zImage Image xipImage bootpImage uImage
# uImage屬于BOOT_TARGETS中的一個成員
304 $(BOOT_TARGETS): vmlinux
# 生成uImage就要生成BOOT_TARGETS大目标
# 依賴源碼頂層目錄下的vmlinux(編譯過程中生成的檔案)
305 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
# Q是對@的封裝 不輸出編譯資訊
# MAKE是對make -C的封裝 -C表示切換到指定目錄下的MakeFile
# $(build)=$(boot) -> build = arch/arm/boot
# MACHINE=$(MACHINE) -> MACHINE := arch/arm/mach-exynos
# $(boot)/$@ -> arch/arm/boot/uImage
-> make -C arch/arm/boot MACHINE=arch/arm/mach-exynos arch/arm/boot/uImage
-> 依賴頂層目錄下的vmlinux,切到arch/arm/boot下的MakeFile(參數是MACHINE)執行,在arch/arm/boot/下生成目标uImage(uImage就是在該目錄)
/***************MACHINE變量的來源******************/
.config/291 CONFIG_ARCH_EXYNOS=y
155 machine-$(CONFIG_ARCH_EXYNOS) += exynos
-> 在最開始導入配置時産生了.config檔案,.config中隻對CONFIG_ARCH_EXYNOS進行了指派(其他都注釋)
-> machine-y += exynos 即 machine-y = exynos
232 ifneq ($(machine-y),)
# 比較machine-y與空的值(machine-y = exynos),不相等
233 MACHINE := arch/arm/mach-$(word 1,$(machine-y))/ # word 1,$(machine-y) word為函數 表示從machine-y變量中取第一個單詞
-> MACHINE := arch/arm/mach-exynos
/********************************************************************/
4.arch/arm/boot/Makefile
78 $(obj)/uImage: $(obj)/zImage FORCE
# 依賴于zImage obj表示目前MakeFile所在路徑 FORCE強制編譯不管是否編譯過
79 @$(check_for_multiple_loadaddr)
80 $(call if_changed,uimage)
81 @$(kecho) ' Image $@ is ready' # 輸出資訊
-> 依賴目前目錄下的zImage生成uImage
-> 追蹤zImage
30 ifeq ($(CONFIG_XIP_KERNEL),y)
# CONFIG_XIP_KERNEL在.config中定義 沒有指派
41 else
54 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
# 依賴arch/arm/boot/compressed/vmlinux(與之前不是同一個)
55 $(call if_changed,objcopy)
# 使用gcc編譯出的程式都是elf格式的,需要進行二進制格式的轉換
56 @$(kecho) ' Kernel: $@ is ready' # 顯示資訊
51 $(obj)/compressed/vmlinux: $(obj)/Image FORCE
# vmlinux依賴于arch/arm/boot/Image
52 $(Q)$(MAKE) $(build)=$(obj)/compressed $@
# make -C arch/arm/boot/compressed arch/arm/boot/compressed/vmlinux
-> 依賴arch/arm/boot/Image,切換到arch/arm/boot/compressed/下的MakeFile生成vmlinux
/***********MACHINE參數的引用*******************/
arch/arm/boot/Makefile
14 ifneq ($(MACHINE),)
# arch/arm/MakeFile中傳參進來MACHINE=arch/arm/mach-exynos
15 include $(srctree)/$(MACHINE)/Makefile.boot
# include arch/arm/mach-exynos/Makefile.boot
16 endif
arch/arm/mach-exynos/Makefile.boot
1 zreladdr-y += 0x40008000
# 核心的入口位址(運作起始位址)
2 params_phys-y := 0x40000100
# uboot和核心協商好的存放參數的位置
arch/arm/boot/Makefile
22 ZRELADDR := $(zreladdr-y)
# ZRELADDR = 0x40008000
23 PARAMS_PHYS := $(params_phys-y)
# PARAMS_PHYS = 0x40000100
24 INITRD_PHYS := $(initrd_phys-y)
25
26 export ZRELADDR INITRD_PHYS PARAMS_PHYS
# 導出讓全局可用
/*****************************************************************/
5.arch/arm/boot/compressed/MakeFile
185 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
186 $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
187 $(bswapsdi2) FORCE
# vmlinux依賴很多檔案産生
# 依賴檔案的來源
# $(obj)/vmlinux.lds
# arch/arm/boot/compressed/vmlinux.lds 連結腳本決定elf檔案的排版(核心源檔案)
# $(obj)/$(HEAD) = arch/arm/boot/compressed/$(HEAD)
# 25 HEAD = head.o 由 head.S生成(核心源檔案)
# $(obj)/piggy.$(suffix_y).o
# 86 suffix_$(CONFIG_KERNEL_GZIP) = gzip
# .config/40 CONFIG_KERNEL_GZIP=y 導入預設配置時配置的核心的壓縮格式
# ->suffix_y = gzip
# -> $(obj)/piggy.$(suffix_y).o = arch/arm/boot/compressed/piggy.gzip.o 由 piggy.gzip.S(編譯中間生成)生成
# $(addprefix $(obj)/, $(OBJS)) # 給變量$(OBJS))添加字首$(addprefix $(obj)/
# 26 OBJS += misc.o decompress.o -> OBJS = misc.o decompress.o
# -> $(addprefix $(obj)/, $(OBJS)) = arch/arm/boot/compressed/misc.o decompress.o 由 misc.c decompress.c生成(核心源檔案)
# 這兩個檔案用于解壓核心 核心當中包含了解壓的代碼
# $(lib1funcs)
# 148 lib1funcs = $(obj)/lib1funcs.o -> lib1funcs = arch/arm/boot/compressed/lib1funcs.o(lib1funcs.S生成)
# 150 $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S(核心源檔案)
# $(ashldi3)
# 154 ashldi3 = $(obj)/ashldi3.o -> ashldi3 = arch/arm/boot/compressed/ashldi3.o(ashldi3.S生成)
# 156 $(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S(核心源檔案)
# $(bswapsdi2)
# 160 bswapsdi2 = $(obj)/bswapsdi2.o -> bswapsdi2 = arch/arm/boot/compressed/bswapsdi2.o(bswapsdi2.S生成)
# 162 $(obj)/bswapsdi2.S: $(srctree)/arch/$(SRCARCH)/lib/bswapsdi2.S(核心源檔案)
/******************************piggy.gzip.o********************************/
# 195 $(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE -> piggy.gzip.o:piggy.gzip -> piggy.gzip.o依賴piggy.gzip
# 192 $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE -> piggy.gzip:arch/arm/boot/Image FORCE -> piggy.gzip依賴上層目錄的Image
-> 退回上層目錄追蹤arch/arm/boot/Image
/*************************************************************************/
6.arch/arm/boot/MakeFile
47 $(obj)/Image: vmlinux FORCE
# 依賴頂層源碼下的vmlinux FORCE強制執行
48 $(call if_changed,objcopy)
49 @$(kecho) ' Kernel: $@ is ready'
-> 退回頂層源碼下追蹤vmlinux
7.頂層目錄MakeFile
817 vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
# scripts/link-vmlinux.sh 編譯需要的腳本
# 809 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
# 追蹤得到一些路徑下的源檔案
# 802 export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
# 803 export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y)
# 804 export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
# 連結腳本(兩次連結過程)
逆序總結:uImage由zImage通過uboot中的工具為其添加頭部生成
zImage由arch/arm/boot/compressed/vmlinux(elf格式)檔案經過二進制格式轉換生成
vmlinux由/arch/arm/boot/compressed/piggy.gzip(壓縮後的核心)和misc.c、decompress.c、(用于解壓核心的代碼)按照vmlinux.lds連結生成(二次連結)
piggy.gzip由/arch/arm/boot/Image檔案(不包含解壓代碼的二進制核心檔案)壓縮得到
Image檔案是由源碼頂層目錄下的vmlinux(elf格式)經過二進制轉換生成的
vmlinux是由一系列的核心源碼與工具按照連結腳本arch/arm/kernel/vmlinux.lds連結生成(一次連結)
順序總結:一系列的源碼與工具按照arch/arm/kernel/vmlinux.lds與各級Makefile的規則編譯生成源碼頂層目錄下的vmlinux(elf格式核心)即第一次連結
vmlinux經過二進制轉換生成arch/arm/boot/Image(二進制格式的核心)
Image檔案經過壓縮得到piggy.gzip檔案(壓縮後的二進制核心)(piggy.gzip檔案的運作需要解壓)
piggy.gzip與解壓該檔案的代碼misc.c、decompress.c、等按照連結腳本arch/arm/boot/compressed/vmlinux.lds連結成一個檔案(第二次連結)vmlinux(elf)
vmlinux檔案經過二進制轉換生成zImage
zImage經過添加頭部生成uImage
嵌入式物聯網需要學的東西真的非常多,千萬不要學錯了路線和内容,導緻工資要不上去!
無償分享大家一個資料包,差不多150多G。裡面學習内容、面經、項目都比較新也比較全!某魚上買估計至少要好幾十。加微信領取資料