讓你快速高效(xiao)的掌握linux內核編譯過程
時間:2018-06-15 來源:未(wei)知
Linux內核編譯
一、linux內(nei)核的配置與編譯:
1.配置內核
1)導入默(mo)認配(pei)置:
make xxxx_defconfig
注1:xxxx表示內核支持(chi)的芯(xin)片(pian)的名稱 比如make exynos_defconfig
注2:內核源碼中對每個支持的芯片都(dou)有(you)默認的配置(zhi),默認配置(zhi)很少只能(neng)保證系統完(wan)成最基本的功能(neng)
注3:可以(yi)通過直接(jie)修改.config文(wen)件來進(jin)行內核的(de)配(pei)(pei)置(麻煩),所有(you)內核配(pei)(pei)置的(de)本質(zhi)都是修改.config文(wen)件
注4:配(pei)置(zhi)文件(jian)中xxxx=y表示添加了(le)該功能,注釋表示不添加該功能(減(jian)小內核體積(ji))
2)修(xiu)改配(pei)置(內核(he)提供了幾種(zhong)簡(jian)單的(de)配(pei)置方法,其本質都是修(xiu)改.config文件中(zhong)的(de)配(pei)置)
make gconfig 依賴(lai)于GTK庫(ku)
make xconfig 依賴于QT庫
make config 麻煩
-> make menuconfig
選(xuan)中的(de)狀態切換:空(kong)格(ge)
搜索一(yi)個選項(xiang):/
[ ] 有兩種狀態(tai)。
輸入Y,顯示(shi)為“*”,表示(shi)內核中該(gai)功(gong)能被選中,相關功(gong)能代碼(ma)將會被編譯進內核。
輸入N,顯(xian)示為空(kong),表示內(nei)核(he)中該(gai)功能沒(mei)有被選中。
< > 有三(san)種狀態(tai)
輸入Y,顯示為“*”,表(biao)示內(nei)核中該功(gong)能被選中
輸入(ru)N,顯(xian)示為空(kong),表(biao)示內核中該(gai)功能沒有被選中
輸入M,則(ze)顯示(shi)為(wei)“M”,表示(shi)內核(he)中該(gai)功能被選為(wei)模塊(編譯后與內核(he)鏡像不在同(tong)一(yi)文件)
2.編譯內(nei)核
make uImage 編譯內(nei)核鏡(jing)像(xiang)(編譯選中為(wei)“*”的(de)選項到內(nei)核)
make modules 編譯內核模塊(編譯選(xuan)中為(wei)“M”的選(xuan)項(xiang))
make dtbs 編譯設備樹文(wen)件(jian)(使(shi)驅動與設備建立(li)關系(xi)的(de)文(wen)件(jian))
make clean 刪除文(wen)件
二、在內(nei)核中添加子菜單:
每一級(ji)目(mu)錄(lu)中(zhong)都(dou)包含一個Kconfig文(wen)件,用于生成選(xuan)配菜(cai)單的(de)。按照Kconfig的(de)語(yu)法修改(gai)對應的(de)Kconfig文(wen)件就(jiu)可以在(zai)(zai)菜(cai)單中(zhong)添加(jia)自(zi)己的(de)選(xuan)項。在(zai)(zai)一個Kconfig文(wen)件中(zhong)menu是(shi)本級(ji)菜(cai)單,如(ru)menu "Character devices",如(ru)果我們想在(zai)(zai)該菜(cai)單下自(zi)己添加(jia)子菜(cai)單按照語(yu)法添加(jia)在(zai)(zai)menu和endmenu之間即可
語法:
config FS4412_LED # 固定(ding)語法(fa),config XXX,XXX用來與MakeFile關聯,即配(pei)置后MakeFile會按照該配(pei)置進行(xing)編(bian)譯
tristate "FS4412LED Device Support"
# tristate “菜單顯示名(ming)稱”;tristate表示該選(xuan)項有三(san)個狀態<>(即可(ke)以選(xuan)擇成N/Y/M),bool表示有兩個選(xuan)項[](N/Y)
default n
# default n 默(mo)(mo)認是'N',即不添加(jia)該功能 default y 默(mo)(mo)認添加(jia)該功能default m 默(mo)(mo)認編譯(yi)成模塊(重新配置(zhi)后生效)
depends on ARCH_EXYNOS4
# depends on 依賴的菜(cai)單 當(dang)有依賴關系的選項沒有被選擇時該選項也不顯(xian)示(shi)
help
support leddevice on FS4412 develop board # 幫助(zhu)文檔 可(ke)有可(ke)無
詳情參考:Documentation/kbuild
將自己的模(mo)塊添(tian)加到菜單的步驟(zou):
1.修改Kconfig添加子菜單
2.添加(jia)對應的.C文(wen)件(驅動文(wen)件)
3.修改(gai)對應的(de)Makefile使菜單與編(bian)譯(yi)關聯(將(jiang)驅動(dong)文件編(bian)譯(yi))
三、linux內核(uImage)的編(bian)譯(yi)過程:
1.在(zai)頂層目錄下(xia)執行make uImage
2.頂(ding)層目錄下的MakeFile
155 srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
# srctree為當前MakeFile所(suo)在(zai)目錄
198 ARCH ?= arm # 自己修改的(de)
203 SRCARCH := $(ARCH)
504 include $(srctree)/arch/$(SRCARCH)/Makefile
-> include arch/arm/MakeFile
-> 執行make uImage后會根據我們(men)設(she)置的CPU架(jia)構,執行對應架(jia)構下的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大目標
# 依賴源碼(ma)頂層目錄(lu)下的vmlinux(編譯過程中(zhong)生成的文(wen)件)
305 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
# Q是對@的封裝 不輸(shu)出編(bian)譯信息(xi)
# MAKE是對make -C的(de)封裝 -C表示切換到指定目(mu)錄下(xia)的(de)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
-> 依賴頂層(ceng)目錄下(xia)的vmlinux,切到arch/arm/boot下(xia)的MakeFile(參數是MACHINE)執行(xing),在(zai)arch/arm/boot/下(xia)生(sheng)成(cheng)目標uImage(uImage就是在(zai)該目錄)
/***************MACHINE變量的(de)來(lai)源******************/
.config/291 CONFIG_ARCH_EXYNOS=y
155 machine-$(CONFIG_ARCH_EXYNOS) += exynos
-> 在最開始導入配(pei)置時(shi)產(chan)生了(le).config文件,.config中(zhong)只對CONFIG_ARCH_EXYNOS進行了(le)賦值(其他都注釋)
-> 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變量(liang)中(zhong)取第一個(ge)單詞
-> MACHINE := arch/arm/mach-exynos
/********************************************************************/
4.arch/arm/boot/Makefile
78 $(obj)/uImage: $(obj)/zImage FORCE
# 依賴于zImage obj表示(shi)當(dang)前MakeFile所在路徑 FORCE強制編譯(yi)不管是否編譯(yi)過
79 @$(check_for_multiple_loadaddr)
80 $(call if_changed,uimage)
81 @$(kecho) ' Image $@ is ready' # 輸出信息
-> 依賴(lai)當前目錄下的(de)zImage生成uImage
-> 追蹤zImage
30 ifeq ($(CONFIG_XIP_KERNEL),y)
# CONFIG_XIP_KERNEL在(zai).config中定義(yi) 沒有賦值(zhi)
41 else
54 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
# 依賴arch/arm/boot/compressed/vmlinux(與之前不是同一(yi)個)
55 $(call if_changed,objcopy)
# 使用gcc編譯出的程序都(dou)是elf格式(shi)的,需要進行二進制格式(shi)的轉換
56 @$(kecho) ' Kernel: $@ is ready' # 顯示(shi)信息
51 $(obj)/compressed/vmlinux: $(obj)/Image FORCE
# vmlinux依(yi)賴于(yu)arch/arm/boot/Image
52 $(Q)$(MAKE) $(build)=$(obj)/compressed $@
# make -C arch/arm/boot/compressed arch/arm/boot/compressed/vmlinux
-> 依賴(lai)arch/arm/boot/Image,切(qie)換到arch/arm/boot/compressed/下(xia)的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
# 內(nei)核的(de)入口地(di)址(運行(xing)起始地(di)址)
2 params_phys-y := 0x40000100
# uboot和內核協商好(hao)的存放(fang)參數的位(wei)置(zhi)
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
# 導出讓(rang)全局可用
/*****************************************************************/
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依賴(lai)很多文(wen)件產生
# 依賴文件的來源
# $(obj)/vmlinux.lds
# arch/arm/boot/compressed/vmlinux.lds 鏈接腳本決定(ding)elf文(wen)件的(de)排版(內核源文(wen)件)
# $(obj)/$(HEAD) = arch/arm/boot/compressed/$(HEAD)
# 25 HEAD = head.o 由 head.S生成(cheng)(內核源文件)
# $(obj)/piggy.$(suffix_y).o
# 86 suffix_$(CONFIG_KERNEL_GZIP) = gzip
# .config/40 CONFIG_KERNEL_GZIP=y 導入默認配置時配置的內核(he)的壓縮格式
# ->suffix_y = gzip
# -> $(obj)/piggy.$(suffix_y).o = arch/arm/boot/compressed/piggy.gzip.o 由 piggy.gzip.S(編(bian)譯中間生成(cheng)(cheng))生成(cheng)(cheng)
# $(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生成(內核(he)源文件)
# 這兩個文(wen)件(jian)用于解(jie)壓(ya)內核(he) 內核(he)當中包含了解(jie)壓(ya)的代碼
# $(lib1funcs)
# 148 lib1funcs = $(obj)/lib1funcs.o -> lib1funcs = arch/arm/boot/compressed/lib1funcs.o(lib1funcs.S生(sheng)成)
# 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(內(nei)核源文件)
/******************************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依賴上層目錄的(de)Image
-> 退回上層目錄(lu)追蹤arch/arm/boot/Image
/*************************************************************************/
6.arch/arm/boot/MakeFile
47 $(obj)/Image: vmlinux FORCE
# 依賴頂層源碼下的(de)vmlinux FORCE強(qiang)制(zhi)執行
48 $(call if_changed,objcopy)
49 @$(kecho) ' Kernel: $@ is ready'
-> 退回頂層(ceng)源碼下追(zhui)蹤vmlinux
7.頂層目(mu)錄(lu)MakeFile
817 vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
# scripts/link-vmlinux.sh 編譯需(xu)要的腳本(ben)
# 809 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
# 追蹤得到一些(xie)路徑(jing)下的源文件
# 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
# 鏈(lian)接腳本(ben)(兩次鏈(lian)接過程)
逆序總結:uImage由zImage通過uboot中的工具為其添加頭(tou)部生成
zImage由arch/arm/boot/compressed/vmlinux(elf格式)文(wen)件經過(guo)二進制格式轉換生(sheng)成
vmlinux由/arch/arm/boot/compressed/piggy.gzip(壓縮后的內(nei)核)和misc.c、decompress.c、(用于解壓內(nei)核的代碼)按照vmlinux.lds鏈接生成(二次鏈接)
piggy.gzip由/arch/arm/boot/Image文件(jian)(不包含解壓(ya)代碼的二進制(zhi)內核文件(jian))壓(ya)縮(suo)得到
Image文(wen)件是(shi)由源碼頂(ding)層(ceng)目錄下的vmlinux(elf格式)經過二進制轉換生成的
vmlinux是由一系列的(de)內核源碼與工具按照鏈(lian)接腳本arch/arm/kernel/vmlinux.lds鏈(lian)接生(sheng)成(cheng)(一次鏈(lian)接)
順(shun)序總結(jie):一系列的(de)(de)源碼(ma)與工(gong)具按(an)照arch/arm/kernel/vmlinux.lds與各(ge)級Makefile的(de)(de)規(gui)則編(bian)譯生成源碼(ma)頂層目錄下的(de)(de)vmlinux(elf格式(shi)內(nei)核)即第一次鏈接
vmlinux經過二進制(zhi)轉換(huan)生(sheng)成arch/arm/boot/Image(二進制(zhi)格式的內核)
Image文件(jian)經過壓縮得(de)到(dao)piggy.gzip文件(jian)(壓縮后的二(er)進制內核)(piggy.gzip文件(jian)的運行需要解壓)
piggy.gzip與解壓該文(wen)件(jian)的(de)代碼misc.c、decompress.c、等按照(zhao)鏈(lian)接(jie)腳本arch/arm/boot/compressed/vmlinux.lds鏈(lian)接(jie)成一個文(wen)件(jian)(第二次鏈(lian)接(jie))vmlinux(elf)
vmlinux文(wen)件經過二進制轉換生成zImage
zImage經過添加頭部(bu)生成uImage

