探索Linux內(nèi)核:Kconfig / kbuild的秘密
探索linux內(nèi)核:Kconfig / kbuild的秘密
文章目錄
探索Linux內(nèi)核:Kconfig / kbuild的秘密
深入了解Linux配置/構(gòu)建系統(tǒng)的工作原理
Kconfig
kbuild的
了解vmlinux與bzImage
依賴性跟蹤
展望未來
深入了解Linux配置/構(gòu)建系統(tǒng)的工作原理
自從Linux內(nèi)核代碼遷移到Git以來,Linux內(nèi)核配置/構(gòu)建系統(tǒng)(也稱為Kconfig / kbuild)已存在很長(zhǎng)時(shí)間了。然而,作為支持基礎(chǔ)設(shè)施,它很少成為人們關(guān)注的焦點(diǎn); 甚至在日常工作中使用它的內(nèi)核開發(fā)人員也從未真正考慮過它。
為了探索如何編譯Linux內(nèi)核,本文將深入介紹Kconfig / kbuild內(nèi)部進(jìn)程,解釋如何生成.config文件和vmlinux / bzImage文件,并介紹依賴性跟蹤的智能技巧。
Kconfig
構(gòu)建內(nèi)核的第一步始終是配置。Kconfig有助于使Linux內(nèi)核高度模塊化和可定制。Kconfig為用戶提供了許多配置目標(biāo):
我認(rèn)為menuconfig是這些目標(biāo)中最受歡迎的。目標(biāo)由不同的主程序處理,這些程序由內(nèi)核提供并在內(nèi)核構(gòu)建期間構(gòu)建。一些目標(biāo)有一個(gè)GUI(為了方便用戶),而大多數(shù)沒有。與Kconfig相關(guān)的工具和源代碼主要位于內(nèi)核源代碼中的scripts / kconfig /下。從scripts / kconfig / Makefile可以看出,有幾個(gè)主機(jī)程序,包括conf,mconf和nconf。除了conf之外,它們中的每一個(gè)都負(fù)責(zé)基于GUI的配置目標(biāo)之一,因此,conf處理其中的大多數(shù)。
從邏輯上講,Kconfig的基礎(chǔ)結(jié)構(gòu)有兩部分:一部分實(shí)現(xiàn)一種新語言來定義配置項(xiàng)(參見內(nèi)核源代碼下的Kconfig文件),另一部分解析Kconfig語言并處理配置操作。
大多數(shù)配置目標(biāo)具有大致相同的內(nèi)部過程(如下所示):
請(qǐng)注意,所有配置項(xiàng)都具有默認(rèn)值。
第一步讀取源根目錄下的Kconfig文件,構(gòu)建初始配置數(shù)據(jù)庫(kù); 然后它根據(jù)此優(yōu)先級(jí)讀取現(xiàn)有配置文件來更新初始數(shù)據(jù)庫(kù):
.config
/ lib / modules / $(shell,uname -r)/ .config /
etc / kernel-config
/ boot / config - $(shell,uname -r)
ARCH_DEFCONFIG
arch / $(ARCH)/ defconfig
如果您通過menuconfig進(jìn)行基于GUI的配置或通過oldconfig進(jìn)行基于命令行的配置,則會(huì)根據(jù)您的自定義更新數(shù)據(jù)庫(kù)。最后,配置數(shù)據(jù)庫(kù)被轉(zhuǎn)儲(chǔ)到.config文件中。
但.config文件不是內(nèi)核構(gòu)建的最終素材; 這就是syncconfig目標(biāo)存在的原因。syncconfig曾經(jīng)是一個(gè)名為silentoldconfig的配置目標(biāo),但它不會(huì)執(zhí)行舊名稱所說的內(nèi)容,因此它已重命名。此外,因?yàn)樗枪﹥?nèi)部使用(不適用于用戶),所以它已從列表中刪除。
以下是syncconfig的作用:
syncconfig將.config作為輸入并輸出許多其他文件,這些文件分為三類:
auto.conf和tristate.conf
用于makefile文本處理。例如,您可以在組件的makefile中看到這樣的語句:
obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
1
autoconf.h用于C語言源文件。
**include / config /**下的空頭文件用于kbuild期間的配置依賴性跟蹤,如下所述。
配置完成后,我們將知道哪些文件和代碼片段未編譯。
kbuild的
組件式構(gòu)建(稱為遞歸make)是GNU make管理大型項(xiàng)目的常用方法。Kbuild是遞歸make的一個(gè)很好的例子。通過將源文件劃分為不同的模塊/組件,每個(gè)組件都由其自己的makefile管理。當(dāng)您開始構(gòu)建時(shí),頂級(jí)makefile以正確的順序調(diào)用每個(gè)組件的makefile,構(gòu)建組件,并將它們收集到最終的執(zhí)行程序中。
Kbuild指的是不同類型的makefile:
Makefile是源根目錄中的頂級(jí)makefile。
.config是內(nèi)核配置文件。
arch / $(ARCH)/ Makefile是arch makefile,它是top makefile的補(bǔ)充。
**scripts / Makefile。***描述了所有kbuild makefile的通用規(guī)則。
最后,大約有500個(gè)kbuild makefile。
top makefile包含arch makefile,讀取.config文件,下載到子目錄,在scripts / Makefile。*中定義的例程的幫助下,在每個(gè)組件的makefile上調(diào)用make,構(gòu)建每個(gè)中間對(duì)象,并將所有中間對(duì)象鏈接到vmlinux中。內(nèi)核文檔Documentation / kbuild / makefiles.txt描述了這些makefile的所有方面。
作為一個(gè)例子,讓我們看看如何在x86-64上生成vmlinux:
進(jìn)入vmlinux的所有**.o文件首先進(jìn)入他們自己的內(nèi)置.a**,通過變量 KBUILD_VMLINUX_INIT,KBUILD_VMLINUX_MAIN,KBUILD_VMLINUX_LIBS指示,然后收集到vmlinux文件中。
在簡(jiǎn)化的makefile代碼的幫助下,了解如何在Linux內(nèi)核中實(shí)現(xiàn)遞歸make:
# In top Makefile vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) +$(call if_changed,link-vmlinux) # Variable assignments vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN) $(KBUILD_VMLINUX_LIBS) export KBUILD_VMLINUX_INIT := $(head-y) $(init-y) export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y2) $(drivers-y) $(net-y) $(virt-y) export KBUILD_VMLINUX_LIBS := $(libs-y1) export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds init-y := init/ drivers-y := drivers/ sound/ firmware/ net-y := net/ libs-y := lib/ core-y := usr/ virt-y := virt/ # Transform to corresponding built-in.a init-y := $(patsubst %/, %/built-in.a, $(init-y)) core-y := $(patsubst %/, %/built-in.a, $(core-y)) drivers-y := $(patsubst %/, %/built-in.a, $(drivers-y)) net-y := $(patsubst %/, %/built-in.a, $(net-y)) libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) libs-y2 := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y))) virt-y := $(patsubst %/, %/built-in.a, $(virt-y)) # Setup the dependency. vmlinux-deps are all intermediate objects, vmlinux-dirs # are phony targets, so every time comes to this rule, the recipe of vmlinux-dirs # will be executed. Refer "4.6 Phony Targets" of `info make` $(sort $(vmlinux-deps)): $(vmlinux-dirs) ; # Variable vmlinux-dirs is the directory part of each built-in.a vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y))) # The entry of recursive make $(vmlinux-dirs): $(Q)$(MAKE) $(build)=$@ need-builtin=1
1
遞歸制作配方已擴(kuò)展,例如:
make -f scripts/Makefile.build obj=init need-builtin=1
1
這意味著make將進(jìn)入scripts / Makefile.build繼續(xù)構(gòu)建每個(gè)內(nèi)置的工作.a。在scripts / link-vmlinux.sh的幫助下,vmlinux文件最終位于源根目錄下。
了解vmlinux與bzImage
許多Linux內(nèi)核開發(fā)人員可能不清楚vmlinux和bzImage之間的關(guān)系。例如,這是他們?cè)趚86-64中的關(guān)系:
源根vmlinux被剝離,壓縮,放入piggy.S,然后與其他對(duì)等對(duì)象鏈接到arch / x86 / boot / compressed / vmlinux。同時(shí),在arch / x86 / boot下生成一個(gè)名為setup.bin的文件。可能有一個(gè)可選的第三個(gè)文件具有重定位信息,具體取決于CONFIG_X86_NEED_RELOCS的配置 。
由內(nèi)核提供的稱為build的宿主程序?qū)⑦@兩個(gè)(或三個(gè))部分構(gòu)建到最終的bzImage文件中。
依賴性跟蹤
Kbuild跟蹤三種依賴關(guān)系:
所有必備文件(* .c和* .h)
所有必備文件中使用的**CONFIG_**選項(xiàng)
用于編譯目標(biāo)的命令行依賴項(xiàng)
第一個(gè)很容易理解,但第二個(gè)和第三個(gè)呢??jī)?nèi)核開發(fā)人員經(jīng)常會(huì)看到如下代碼:
#ifdef CONFIG_SMP __boot_cpu_id = cpu; #endif
1
當(dāng)CONFIG_SMP更改時(shí),應(yīng)重新編譯這段代碼。編譯源文件的命令行也很重要,因?yàn)椴煌拿钚锌赡軙?huì)導(dǎo)致不同的目標(biāo)文件。
當(dāng)**.c文件通過#include**指令使用頭文件時(shí),您需要編寫如下規(guī)則:
main.o: defs.h recipe...
1
管理大型項(xiàng)目時(shí),需要大量的這些規(guī)則; 把它們?nèi)繉懴聛頃?huì)很乏味和乏味。幸運(yùn)的是,大多數(shù)現(xiàn)代C編譯器都可以通過查看源文件中的**#include行來為您編寫這些規(guī)則。對(duì)于GNU編譯器集合(GCC),只需添加命令行參數(shù):-MD depfile**
# In scripts/Makefile.lib c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ -include $(srctree)/include/linux/compiler_types.h \ $(__c_flags) $(modkern_cflags) \ $(basename_flags) $(modname_flags)
1
這將生成一個(gè)**.d**文件,內(nèi)容如下:
init_task.o: init/init_task.c include/linux/kconfig.h \ include/generated/autoconf.h include/linux/init_task.h \ include/linux/rcupdate.h include/linux/types.h \ ...
1
然后主機(jī)程序fixdep通過將depfile和命令行作為輸入來處理其他兩個(gè)依賴項(xiàng),然后以makefile語法輸出**。 .cmd**文件,該文件記錄命令行和所有先決條件(包括配置)為目標(biāo)。它看起來像這樣:
# The command line used to compile the target cmd_init/init_task.o := gcc -Wp,-MD,init/.init_task.o.d -nostdinc ... ... # The dependency files deps_init/init_task.o := \ $(wildcard include/config/posix/timers.h) \ $(wildcard include/config/arch/task/struct/on/stack.h) \ $(wildcard include/config/thread/info/in/task.h) \ ... include/uapi/linux/types.h \ arch/x86/include/uapi/asm/types.h \ include/uapi/asm-generic/types.h \ ...
1
在遞歸make期間將包含一個(gè)**。 .cmd**文件,提供所有依賴關(guān)系信息并幫助決定是否重建目標(biāo)。
這背后的秘密是fixdep將解析depfile(.d文件),然后解析內(nèi)部的所有依賴文件,搜索所有CONFIG_字符串的文本,將它們轉(zhuǎn)換為相應(yīng)的空頭文件,并將它們添加到目標(biāo)的先決條件。每次配置更改時(shí),相應(yīng)的空頭文件也將更新,因此kbuild可以檢測(cè)到該更改并重建依賴于它的目標(biāo)。因?yàn)檫€記錄了命令行,所以很容易比較最后和當(dāng)前的編譯參數(shù)。
展望未來
Kconfig / kbuild在很長(zhǎng)一段時(shí)間內(nèi)保持不變,直到新的維護(hù)者M(jìn)asahiro Yamada于2017年初加入,現(xiàn)在kbuild再次正在積極開發(fā)。如果您很快就會(huì)看到與本文中的內(nèi)容不同的內(nèi)容,請(qǐng)不要感到驚訝。
轉(zhuǎn)自:https://opensource.com/article/18/10/kbuild-and-kconfig
Linux 數(shù)據(jù)庫(kù)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。