Building the Kernel - Linux Embedded systems

Building the kernel is frequently viewed as a difficult proposition. There’s also the view that building the kernel is risky because the newly build kernel won’t work properly even if it does compile. These assumptions are simply false. Building a kernel from source is easy, and the risks of the software not working are minimal the kernel is tested by thousands of software engineers on a daily basis. Because the project is complex, building the kernel requires a few steps not necessary for other project. The basic steps are as follows:

  1. Configuration: During the configuration step, you set the parameters and options that control how the kernel is built. There are several different ways of configuring the kernel, but it doesn’t matter which one you select because all of them perform the same underlying activities. Configuration is frequently aided by default configuration settings supplied with the kernel for most boards and processors; for many boards, you can use this default configuration as is to build a kernel that will boot on the board.
  2. Building the kernel: After it’s configured, the kernel can be compiled and linked. This process works much like any other project using GNU Make as the build tool. The result of the kernel build is a binary that can be put on the board and booted as well as file suitable for debugging.
  3. Building the modules: The Linux kernel supports linking code into the image at runtime, similar to the way a program uses a shared library. Kernel modules support hardware components that may not be present when the kernel is started, so having the code in memory is a waste of resources. The code that can be linked into the kernel, in a process called loading, is called a module; these modules can be built separately from the kernel. Modules can be loaded and unloaded on demand.

The Linux kernel build process involves first priming the kernel source tree so that it’s in the right state to be compiled; this process is called configuration or configuring the kernel. The kernel configuration process grew out of environment variables that were set in the shell, which were then used by the make file to compile certain code or change the compilation method. As the complexity of thekernel project grew, the configuration process advanced similarly and gained a text-based menu interface that is essentially unchanged in the current distribution of Linux.

To start the kernel configuration process using the text-based menu-oriented configuration program (other methods are discussed later), do the following from the command prompt while in the kernel’s top-level directory:
$ make menuconfig ARCH=<your architecture>

If the kernel has never been configured before (or has been cleaned more on that later), the programs used to configure the kernel and display the text-based menu are compiled, after which the screen shown in Figure below appears on your console.


The value for ARCH is one of the entries in the kernel’s arch directory and is always in lowercase. To see a list of the supported processor architectures, do the following from the top of kernel’s source tree:

If you’re uncertain what to pick for the architecture, run uname -m on the target machine. If you’re still uncertain, get in touch with the technical support department or FAE for the board. The most popular targets for embedded (in alphabetical order) are arm, mips, powerpc, sh, and x86. Many people prefer to use GUI tools that can work with a mouse, as opposed to the text-oriented configuration program. For the kernel, there are two different graphical kernel configuration systems: one that uses the QT graphics library and the other that uses GTK libraries. Table below describes the configuration programs, the packages you need to install in order to build them, and why you would want to use one over another. GTK and QT use different GUI widget sets, where a widget is a check box or button. Because many systems don’t have the proper libraries in place for compiling applications using either of these widget sets, the table also says what extra packages you need to install in order for the configuration build to work.

KCP configuartion programs

No matter what configuration program you use, the program does the same thing, so feel free to experiment with each and pick the one you prefer. Many kernel developers have a preference for the console-based menu configuration tool, so if you’re working with a kernel developer, learning and using this tool is a good idea.

The options selected by the kernel configuration program are stored in a .config file. Because this file starts with a. it doesn’t appear when you list a directory’s contents in Linux and use the default parameters for ls (hint: use the -a argument to ls to see files starting with a dot); that confuses users who look for the file containing their configuration information. After you run the configuration program, take a peek at the contents of the file using the head command or by opening the file in an editor:

Notice that some of the comment lines show variables that aren’t set to a value. This is a vestige of when this file set environment variables; having the line commented out was a trick to show that the variable wasn’t being set while keeping a record of the variables that weren’t being set. The configuration system now relies on the pattern

to determine if a variable is not set, even though this line appears to be a comment. Don’t change lines that follow this pattern, because doing so will confuse the kernel configuration program.

How Kernel Configuration Works
The kernel configuration process works when the kernel configuration program reads a kernel configuration specification file, called the kconfig file. This file resides in the arch directory, as specified with the ARCH=<your architecture> parameter when you run menuconfig. The kconfig file for the architecture contains the settings specific to the architecture and then includes configuration files for the rest of the kernel. For example, the MIPS kconfig file contains the following:

The kernel configuration program reads in the .config file for the kernel, applies the settings to the kconfig that was just read into the system, and renders the menu. After you select options, the changes are written back out to the .config file. Early in the build process, the file include/linux/autoconf.h is generated: it contains all the settings in the .config file as C preprocessor macros. The autoconf.h file is included in all the files in the Linux kernel; that is how the options you select in the configuration program are made available to the kernel. To see the process in terms of actions and configuration files, have a look at Figure BELOW.

How-the-Linux-Kernal configuration works

Default Configurations
The settings for the current configuration session are kept in the .config file in the top level of the kernel sources. Default configuration files (called defconfig files) for boards are stored under their respective arch directories. To get a listing of the defconfig files for a given architecture, do the following from the top-level kernel directory:

Some generic help for building the kernel appears, followed by a listing of the defconfig files for <your architecture>. In this case, the value was mips:

pnx8335-stb225_defconfig Build for pnx8335-stb225
pnx8550-jbs_defconfig Build for pnx8550-jbs
pnx8550-stb810_defconfig Build for pnx8550-stb810
rb532_defconfig Build for rb532

These defconfig files are nothing more than .config files that has been copied to a different directory and renamed. The kernel build system expects these files to be in the configs directory under the selected architecture; when the make target matches a file in the defconfig directory, it copies the file to .config.

If you’re not interested in running make to see the default configurations available, or if you want more information than make provides (such as a date, or if you’d like to sort the list), you can locate these files with the find utility:

Using mips for the architecture, the following appears:


To use one of these files to configure the kernel, use it as a target for make. For example, to configure the kernel to build for the yosemite board, you issue the following command from the top level of the kernel directory:

The kernel will be ready to compile, targeting this processor. Because a defconfig file is just a renamed and relocated .config file, you can also store the .config file used in your project in the configs directory.

Editing .config By Hand
Because the .config file is a plain-text file with an uncomplicated format, editing it directly is a temptation and is sometimes the fastest way to change a value that’s buried in the configuration’s menu system. There is nothing wrong with editing this file by hand, and doing so is common among developers who know exactly what change they want to make. As an example, developers frequently change the value of CONFIG_CMDLINE, the kernel command line; opening the file in an editor and changing the line is much faster than using the existing kernel configuration tools.

After you make a change to the .config file, the best practice is to use the oldconfig target to test the selected options against the current configuration settings. For example,
$ make ARCH=arm oldconfig
results in the current .config file being processed. Any problems are reported on the command line.

For example, some changes to the file result in other dependent options no longer being valid. Another practical use for oldconfig is when you use the contents of a kernel’s /proc/config.gz file. Recall from Chapter 4 that when examining a board, you can get a copy of the configuration used to build the kernel from the kernel itself. If you want to build the kernel with that file, the steps are e as follows:

  1. Get the file. On the board is a file /proc/config.gz that is a compressed version of the .config file used to build the kernel. Uncompress it into a regular file by doing the following command on the target:
    $ gunzip -c /proc/config.gz /tmp/kernel.config
    This decompresses the file /proc/config.gz and makes a copy in
  2. Copy to the kernel’s source tree. Copy the file from the board using the method you’ve already established. This could mean using SCP, FTP, or a USB thumb drive. Copy the file to the root of the kernel source tree, naming it
  3. Use make oldconfig. This step loads the existing configuration options, checks them against the current .config file, and reports any problems:
    $ make ARCH=<your arch> oldconfig

Building the Kernel
After the kernel is configured, it’s ready to be built. The output, or target, of a kernel build is a binary suitable for the boot loader on the target board, because the boot loader is the program responsible for getting the kernel code in memory and ready to be executed. The build also produces some of the tools used to build the kernel itself; unlike other projects, the build does the right thing when compiling programs for the host (such as those supporting programs) and object code for the target, such as the kernel and modules.

Many different targets are available for building a kernel, and the right one depends on the boot loader for the board. The differences between the targets in terms of the overall Linux build is quite small, because the build targets determine what happens in the last few steps of the build to format the object code so that it can be used with the boot loader on the board. Table below outlines the targets available and their applicability.


In addition to picking the appropriate target, you also need to tell the make file what compiler to use. The kernel’s make file cross-compiles well, and the make file uses the host system’s compiler when building tools for building the kernel and the cross-compiler when building code. The general case command line looks something like this:

To build a kernel for a PowerPC board using a U-Boot boot loader, use the following command:

This command line specifies the cross-compiler; it begins with powerpc-405-linux-gnuabi-. The value for CROSS_COMPILER can include a fully qualified directory path if you don’t want to put the crosscompiler on the path. Some users who build several different kernels regularly opt for the fully qualified name route; however, putting the cross-compiler on the path is just as effective.

If you skipped ahead to this section and didn’t configure the kernel, the following message appears:

After the compilation process finishes, the following appears, to show what was produced (this output will vary slight depending on your kernel):

The output of the kernel build is located under the arch/<ARCH>/boot directory. The actual location varies, so double-check what the output of the build says. In this example, the line
WRAP arch/powerpc/boot/uImage
shows that the output of the build is arch/powerpc/boot/uImage. If you’re new to the kernel, this process is a bit mysterious, because no message says “Your Kernel is Here!” The rule of thumb is to look for the line that has a file name the same as the target under the arch/<ARCH>/boot directory. In this case, the uImage file produced by the build is ready for download to a target board.

Building Modules
A kernel module is code that is linked into the kernel while the kernel is running. When you’re buildingthe kernel, you can either link drivers directly into the kernel or build them as modules that can beloaded into the kernel at some other time. Most embedded systems don’t use kernel modules becausethe hardware on the board is fixed and doesn’t change over the life of the system. That is, the kernel thatis built for an embedded system is for that system and no other. Compare this to your desktop system,where the kernel is intended to run on an arbitrary x86 host and must adapt by loading modules. Yourdesktop system probably has dozens of kernel modules loaded. On your host machine, do the followingto see a list of the installed modules:

$ lsmod
Module Size Used by
usbhid 42336 0
nls_iso8859_1 12032 0
nls_cp437 13696 0
vfat 18816 0
fat 58272 1 vfat
mmc_block 17668 0
aes_i586 15744 0
aes_generic 35880 1 aes_i586
ftdi_sio 56968 0
i915 65540 2

Remember, a general-purpose Linux distribution doesn’t know what devices will be on the machine, so the kernel has a minimal set of drivers statically linked and then uses modules, which are dynamically linked, to get the remaining drivers. This minimal set of drivers is enough to drive a display and mount a few file systems likely to be available on most hardware platforms.

The work involved in looking at the current hardware configuration and loading the drivers also takes time during the boot process. Many embedded devices don’t have much time before they’re up and running, so the time overhead alone may disqualify the use of kernel modules.

For devices that do use kernel modules, building the modules is a straightforward task. The prior section showed how to build a kernel for a PowerPC 405-based board; using that same kernel directory, you build the modules with the following command:

The output shows that the process is busy building modules (by way of the [M]). The output of a kernel module build is some number of files ending in .ko that are scattered across the kernel’s source tree.

After they’re compiled, the modules can be gathered into one location via an installation target in the kernel’s make file. Installing the modules for an embedded system means gathering the .ko files in the kernel source tree and putting them in a directory. That directory’s contents are then moved to the target device. You do this by using the modules_install target as follows:

If space is a concern, you can remove the kernel modules that won’t be used on the target device before this directory is included in the board’s root file system.

Kernel modules aren’t atomic, which means a kernel module may need another in order to work correctly. This data is stored in the modules.dep file under the
$INSTALL_MOD_PATH/lib/modules/<kernel version> directory. A typical entry looks like the
kernel/drivers/mtd/mtdblock.ko: kernel/drivers/mtd/mtd_blkdevs.ko

This line says that the mkdblock.ko module depends on the mtd_blkdevs.ko module. Looking at the mtd_blkdevs.ko file shows that no further dependencies exist. Dependency information is close in format to what you find in a make file, so it’s easy for a human to read. This information tells you that you need both of these files on the target system if you want to use the features offered by the mtdblock.ko module. This is very helpful when you’re removing kernel modules that aren’t necessary in order to conserve space.

It’s important to note that only the kernel module file (.ko) is necessary to load a module. The additional files, like modules.deps, are a convenience. All you need to load a module on a system is the insmod program, which loads the module into the kernel, and the module itself. However, if your system will be loading arbitrary modules or storage space isn’t a concern, you can include all the module files in the target’s file system.

Cleaning Up
Cleaning a kernel build is much like cleaning a regular project: it involves removing the output from prior builds. In the case of Linux, there are several different types of “clean,” listed here in order of increasing cleanliness:

  1. clean: Removes all the object files but keeps .config. Use this configuration option when you’re testing whether the kernel rebuilds after you change to the configuration.
  2. mrproper: Does everything that clean does and deletes .config and some of the architecture-related files and symlinks created as part of the configuration and build process. Use this when you want to restore the kernel source tree to the approximate state it was in before it was configured.
  3. distclean: Does everything that clean and mrproper do, plus deletes what appear to be editor backup, patch, and other files. Use distclean before you create or apply a patch file, because this target leaves the source tree in the most pristine state possible.

All rights reserved © 2020 Wisdom IT Services India Pvt. Ltd Protection Status

Linux Embedded systems Topics