The Linux kernel config/construct system, also called Kconfig/kbuild, has been round for a very long time, ever because the Linux kernel code migrated to Git. As supporting infrastructure, nevertheless, it’s seldom within the highlight; even kernel builders who use it of their every day work by no means actually give it some thought.
To discover how the Linux kernel is compiled, this text will dive into the Kconfig/kbuild inside course of, clarify how the .config file and the vmlinux/bzImage recordsdata are produced, and introduce a wise trick for dependency monitoring.
Kconfig
The first step in constructing a kernel is all the time configuration. Kconfig helps make the Linux kernel extremely modular and customizable. Kconfig presents the consumer many config targets:
config | Update present config using a line-oriented program |
nconfig | Update present config using a ncurses menu-based program |
menuconfig | Update present config using a menu-based program |
xconfig | Update present config using a Qt-based frontend |
gconfig | Update present config using a GTK+ based mostly frontend |
oldconfig | Update present config using a offered .config as base |
localmodconfig | Update present config disabling modules not loaded |
localyesconfig | Update present config changing native mods to core |
defconfig | New config with default from Arch-supplied defconfig |
savedefconfig | Save present config as ./defconfig (minimal config) |
allnoconfig | New config the place all choices are answered with ‘no’ |
allyesconfig | New config the place all choices are accepted with ‘sure’ |
allmodconfig | New config deciding on modules when potential |
alldefconfig | New config with all symbols set to default |
randconfig | New config with a random reply to all choices |
listnewconfig | List new choices |
olddefconfig | Same as oldconfig however units new symbols to their default worth with out prompting |
kvmconfig | Enable extra choices for KVM visitor kernel help |
xenconfig | Enable extra choices for xen dom0 and visitor kernel help |
tinyconfig | Configure the tiniest potential kernel |
I believe menuconfig is the most well-liked of those targets. The targets are processed by totally different host applications, that are offered by the kernel and constructed throughout kernel constructing. Some targets have a GUI (for the consumer’s comfort) whereas most do not. Kconfig-related instruments and supply code reside primarily beneath scripts/kconfig/ within the kernel supply. As we will see from scripts/kconfig/Makefile, there are a number of host applications, together with conf, mconf, and nconf. Except for conf, every of them is accountable for one of many GUI-based config targets, so, conf offers with most of them.
Logically, Kconfig’s infrastructure has two elements: one implements a new language to outline the configuration gadgets (see the Kconfig recordsdata beneath the kernel supply), and the opposite parses the Kconfig language and offers with configuration actions.
Most of the config targets have roughly the identical inside course of (proven under):
Note that every one configuration gadgets have a default worth.
The first step reads the Kconfig file beneath supply root to assemble an preliminary configuration database; then it updates the preliminary database by studying an present configuration file in line with this precedence:
.config
/lib/modules/$(shell,uname -r)/.config
/and so on/kernel-config
/boot/config-$(shell,uname -r)
ARCH_DEFCONFIG
arch/$(ARCH)/defconfig
If you might be doing GUI-based configuration through menuconfig or command-line-based configuration through oldconfig, the database is up to date in line with your customization. Finally, the configuration database is dumped into the .config file.
But the .config file shouldn’t be the ultimate fodder for kernel constructing; this is the reason the syncconfig goal exists. syncconfig was a config goal known as silentoldconfig, however it would not do what the previous identify says, so it was renamed. Also, as a result of it’s for inside use (not for customers), it was dropped from the checklist.
Here is an illustration of what syncconfig does:
syncconfig takes .config as enter and outputs many different recordsdata, which fall into three classes:
After configuration, we’ll know which recordsdata and code items usually are not compiled.
kbuild
Component-wise constructing, known as recursive make, is a typical manner for GNU make
to handle a big mission. Kbuild is an efficient instance of recursive make. By dividing supply recordsdata into totally different modules/elements, every part is managed by its personal makefile. When you begin constructing, a high makefile invokes every part’s makefile within the correct order, builds the elements, and collects them into the ultimate government.
Kbuild refers to totally different sorts of makefiles:
- Makefile is the highest makefile positioned in supply root.
- .config is the kernel configuration file.
- arch/$(ARCH)/Makefile is the arch makefile, which is the complement to the highest makefile.
- scripts/Makefile.* describes frequent guidelines for all kbuild makefiles.
- Finally, there are about 500 kbuild makefiles.
The high makefile contains the arch makefile, reads the .config file, descends into subdirectories, invokes make on every part’s makefile with the assistance of routines outlined in scripts/Makefile.*, builds up every intermediate object, and hyperlinks all of the intermediate objects into vmlinux. Kernel doc Documentation/kbuild/makefiles.txt describes all features of those makefiles.
As an instance, let’s take a look at how vmlinux is produced on x86-64:
All the .o recordsdata that go into vmlinux first go into their very own built-in.a, which is indicated through variables KBUILD_VMLINUX_INIT, KBUILD_VMLINUX_MAIN, KBUILD_VMLINUX_LIBS, then are collected into the vmlinux file.
Take a take a look at how recursive make is applied within the Linux kernel, with the assistance of simplified makefile code:
# In high Makefile
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps)
+$(name 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.ldsinit-y := init/
drivers-y := drivers/ sound/ firmware/
net-y := web/
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 each time involves this rule, the recipe of vmlinux-dirs
# can be executed. Refer "4.6 Phony Targets" of `data make`
$(type $(vmlinux-deps)): $(vmlinux-dirs) ;# Variable vmlinux-dirs is the listing a part of every 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) $(construct)=$@ need-builtin=1
The recursive make recipe is expanded, for instance:
make -f scripts/Makefile.construct obj=init need-builtin=1
This means make will go into scripts/Makefile.construct to proceed the work of constructing every built-in.a. With the assistance of scripts/link-vmlinux.sh, the vmlinux file is lastly beneath supply root.
Understanding vmlinux vs. bzImage
Many Linux kernel builders will not be clear in regards to the relationship between vmlinux and bzImage. For instance, right here is their relationship in x86-64:
The supply root vmlinux is stripped, compressed, put into piggy.S, then linked with different peer objects into arch/x86/boot/compressed/vmlinux. Meanwhile, a file known as setup.bin is produced beneath arch/x86/boot. There could also be an non-obligatory third file that has relocation data, relying on the configuration of CONFIG_X86_NEED_RELOCS.
A bunch program known as construct, offered by the kernel, builds these two (or three) elements into the ultimate bzImage file.
Dependency monitoring
Kbuild tracks three sorts of dependencies:
- All prerequisite recordsdata (each *.c and *.h)
- CONFIG_ choices utilized in all prerequisite recordsdata
- Command-line dependencies used to compile the goal
The first one is simple to grasp, however what in regards to the second and third? Kernel builders typically see code items like this:
#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif
When CONFIG_SMP adjustments, this piece of code must be recompiled. The command line for compiling a supply file additionally issues, as a result of totally different command traces might end in totally different object recordsdata.
When a .c file makes use of a header file through a #embrace directive, you want write a rule like this:
most important.o: defs.h
recipe...
When managing a big mission, you want plenty of these sorts of guidelines; writing all of them can be tedious and boring. Fortunately, most trendy C compilers can write these guidelines for you by trying on the #embrace traces within the supply file. For the GNU Compiler Collection (GCC), it’s only a matter of including a command-line parameter: -MD depfile
# In scripts/Makefile.lib
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)
-include $(srctree)/embrace/linux/compiler_types.h
$(__c_flags) $(modkern_cflags)
$(basename_flags) $(modname_flags)
This would generate a .d file with content material like:
init_task.o: init/init_task.c embrace/linux/kconfig.h
embrace/generated/autoconf.h embrace/linux/init_task.h
embrace/linux/rcupdate.h embrace/linux/varieties.h
...
Then the host program fixdep takes care of the opposite two dependencies by taking the depfile and command line as enter, then outputting a .<goal>.cmd file in makefile syntax, which data the command line and all of the stipulations (together with the configuration) for a goal. It seems to be like this:
# The command line used to compile the goal
cmd_init/init_task.o := gcc -Wp,-MD,init/.init_task.o.d -nostdinc ...
...
# The dependency recordsdata
deps_init/init_task.o :=
$(wildcard embrace/config/posix/timers.h)
$(wildcard embrace/config/arch/job/struct/on/stack.h)
$(wildcard embrace/config/thread/data/in/job.h)
...
embrace/uapi/linux/varieties.h
arch/x86/embrace/uapi/asm/varieties.h
embrace/uapi/asm-generic/varieties.h
...
A .<goal>.cmd file can be included throughout recursive make, offering all of the dependency data and serving to to resolve whether or not to rebuild a goal or not.
The secret behind that is that fixdep will parse the depfile (.d file), then parse all of the dependency recordsdata inside, search the textual content for all of the CONFIG_ strings, convert them to the corresponding empty header file, and add them to the goal’s stipulations. Every time the configuration adjustments, the corresponding empty header file can be up to date, too, so kbuild can detect that change and rebuild the goal that depends upon it. Because the command line can also be recorded, it’s straightforward to match the final and present compiling parameters.
Looking forward
Kconfig/kbuild remained the identical for a very long time till the brand new maintainer, Masahiro Yamada, joined in early 2017, and now kbuild is beneath lively growth once more. Don’t be shocked should you quickly see one thing totally different from what’s on this article.