Linux kernel is one of the worlds largest open source project. So to play with it, We would be first able to customize and then build(compile) it to our will and wish. Because of its sheer volume, The end developers or kernel hackers mandates an automated tool to ease the customization and build process. This is where Linux kernel build system comes into picture and our today’s topic of discussion. The following video will kick start this article by giving excellent perspective with mind boggling numbers about Linux kernel.
What does the Linux build system do?
Linux build system is responsible for compiling the kernel. Entire build process is split into two steps – Configuring and Building. It is completely based on make & makefiles. Linux build system takes make further and uses it for configuring the kernel as well. By the word configure, I mean which parts of the source code should be included/excluded for compilation or how the included parts are built? Whether as part of kernel or as separate modules etc.
From my previous article, We know, make takes a target with in the Makefile and execute the rules under that target. This is also true with kernel build system. So, because of configuring and building steps, The make targets are divided in to two categories(excluding cleaning & documentation related targets)
- Step 1 : Configuration targets
- Step 2 : Build targets
What is meant by configuring the kernel?
Before going further lets answer the above question. Basically as said earlier depending on the will and wish of the developer he/she will have to conditionally exclude or include parts of the source code. So to understand this better, Lets assume we have a source file and we want to add some debugging routines in to it. So as a first step, we surround the debugging routines with some macros as shown below
//Code which is available only if macro is defined #ifdef CONFIG_DEBUGFS //routine 1 //routine 2 #endif //Code which is available only if macro is not defined #ifndef CONFIG_DEBUGFS //routine 3 //routine 4 #endif
Now the next step is to externally define or undefine the CONFIG_DEBUGFS macro before submitting the file for compilation. Lets pause here for a moment and think of the situation of managing these kind of macros for each and every file in the entire kernel code base containing around 50000 files. This is clearly not possible manually, Also to make the configuration more complicated, there exist dependencies among these macros. Example, if macro A is defined macro B should be undefined or when macro B is defined macro C should be defined etc. This process quickly becomes cumbersome. This is where Kconfig comes into picture.
What is Kconfig?
Kconfig is a text file for specifying the above configuration macros and their dependencies. These files are present in almost every directory in the kernel tree. It looks as shown below
Each Kconfig file looks like an exam questionnaire of configuration macros and their dependencies with Y,N choices. These individual Kconfig files are prepared by the respective kernel developer of that particular directory or module. All the Kconfig files from the required directories are read in recursively and presented to the developer via one of the config targets during the configuration step of Linux build.
make menuconfig #calling make to configure the kernel
Once this step is done, The macros for entire kernel will be spit out as a .config, you can think of it as an answer file to all Kconfig files in the entire kernel. It contains every possible macro in the code with the information of whether the macro is enabled(Y) or disabled(N) or sometimes may provide other values for the enabled(Y) options
The generation of .config itself is called as configuring the kernel.
How is kernel built using .config?
Building of kernel image starts by invoking make with vmlinux or all as targets.
make vmlinux # calling make to start building kernel image
Using the .config file the make command will recursively read each Makefile from all the kernel directories. These Makefiles contain source files or directories to be included or excluded during the build process.
Once included, each file can decide which parts of it are to be included or excluded using the same macros as shown in the first code snippet. This recursive inclusion of Makefiles can be seen in the following screenshot.
In the above screenshot at each directory level the build system creates the object files(.o) from C files(.c) and links them into an amalgam(built-in.0) and this amalgam is linked with its parent directory built-in.0. This step repeats to the top of the $(src) directory recursively. In top most directory make creates the vmlinux from all the amalgams. During this process some essential drivers becomes part of the kernel and some of the drivers are compiled separately as also known as modules.
The kernel build system is very robust and generic for configuration tool building and also for kernel building. This article just tries to put bits and pieces together for a beginner to get started. It does not talk about nitty-gritty details. I tried to keep the article as precise as possible and tried not to loose brevity of the content. To appreciate more about kernel build system and make. In the next article I would like to dig deeper into the internals and implementation of kernel build system. Beware its going to be make kung-fu!