Build the Linux kernel from source

Get the Linux kernel source code

The source code for the Linux kernel consists of a set of directories and files, known as the kernel source tree, that will be configured and compiled to create the final kernel image in binary format.

Preparing a working directory

In order to compile the source code, first create a working directory to have a clean environment where to download the Linux source code and work inside.

$ mkdir linux
$ cd linux

Tip

You do not need to be root user or use sudo to compile the kernel. These privileges are only required to install the kernel image, later in the process.

Obtain the Linux kernel source tree

Download the preferred kernel release from https://www.kernel.org. For example, to get the long term stable release 4.19.91, issue:

$ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.91.tar.xz

Any other method to get the compressed tarball into the directory is right provided that, once obtained, you can uncompress the kernel source:

$ tar xvf linux-4.14.91.tar.xz

After uncompressing, enter into the main directory to work with the kernel source:

$ cd linux-4.14.91

Configure the Linux kernel

Before compiling the kernel a few steps are needed to set up everything correctly.

Clean the downloaded source tree

The Linux maintainers recommend to clean up the kernel source tree before any compilation in order to get rid of any spourious files that could be included in the released tarball. Use the make mrproper command provided with the Linux source code:

$ make mrproper

Now you have a clean source tree, also know as the vanilla source.

Tip

Always clean the source tree before any new attempt to build the kernel. The only necessary file to preserve before cleaning the source tree is the .config file, if you have made some modifications that you want to save.

Prepare a .config file

If you compile the kernel source code as provided in the source tree, a set of default options for the kernel will be applied which depend on the choices made by the kernel developers. These options are defined in the .config file but can be modified to customize the kernel image.

Get the right .config file

There are several ways of getting a proper .config file for your system.

From the /boot directory

First, in some distributions a copy of the configuraton file used to build the running kernel is saved in the /boot directory. This file can be copied back into the build directory. The exact name for the .config file varies among distributions. For example, in a Debian system, you could copy the file as:

$ cp /boot/config-4.14.32-2-amd64 .config

or, on a Fedora system:

$ cp /boot/config-4.18.16-300.fc29.x86_64 .config

while in a phyglos system you’ll need:

$ cp /boot/linux-4.14.32-x86_64-pc_generic.config .config
From the /proc/config.gz file

Second, the image of the kernel now running in your system may have been compiled with a copy of the .config file preserved inside that binary image file. This Kconfig file is available through the virtual file /proc/config.gz. You can uncompress and copy these data as the .config file:

$ cat /proc/config.gz | gunzip > .config
Generated with make *config commands

Third, the Linux kernel source tree provides commands like make defconfig or make localmodconfig to help generate a new .config files with some specific configurations.

Tip

See the Linux kernel documentation for all the different commands available.

From the linux-configs collection

And fourth, in the context of the linux-configs collection, a set of preconfigured files are provided in order to choose one of them as a starting point with some expected configuration. You can download the file from the Github repository or download and uncompress the package from the FTP site.

For example, to clone the repository while in the working directory, run:

$ git clone https://github.com/phyglos/linux-configs ../linux-configs

To find a suitable .config file, just browse the collection to find a file to work with. Then copy the desired Kconfig file from the linux-configs collection into the build directory and name it as .config.

$ cp ../linux-configs/linux-4.19.21-x86_64-pc_generic.config .config

Configure the kernel options

In order to compile a kernel suitable for a specific system, the .config file inside the source tree may need to be further customized.

To configure the options for the kernel, using the present configuration file, the kernel source tree provides some configuration tools. To use a text based interface in the console, issue:

$ make menuconfig

Tip

There are other configuration tools available for using a graphical interface to modify the kernel options, like make xconfig. See the Linux documentation for these alternatives.

Now, edit the new kernel configuration, as desired, e.g.:

--> Remove not needed options as:
    -> Unckeck: Profiling Support
    -> Unckeck: OProfile system profiling
    -> Uncheck: Kprobes

--> Optimize for speed:
    -> Check: Optimize very unlikely/likely branches

--> Select Exit to save a new .config file

Backup this configuration file, if a lot of options are changed, in order to preserve it for future use. Copy the .config somewhere outside the build directory:

$ cp .config ~/my-best-config-file.config

Compile the kernel and modules

Once the desired .config file is ready in the build directory, the Linux kernel can be compiled:

$ make

Tip

The compilation time can be quite long, even hours on some old machines. You can use the -j parameter of the make command to control how many cores of the CPU will be used working in parallel:

$ make -j5

When the compilation ends, the binary image bzImage for the new kernel is ready in the arch/x86/boot directory, for both x86 and x86_64 architectures.

Install the kernel image and modules

If any of the options set in the .config file were marked as modules, the kernel compilation process has also created several additional binary files, the kernel modules, that need to be properly installed along with the kernel image.

Note

The following commands install binaries in the system and need to be run as a privileged user. Use the su or sudo command to get these privileges.

Install the kernel modules

In order to install these Linux modules, as a privileged user, issue:

# make modules_install

The modules are installed in the /lib/modules directory, in a subdirectory named after the release number of the kernel being installed.

# tree -L 1 /lib/modules/
/lib/modules/
|-- 4.14.32
`-- 4.19.21

Install the new kernel image

For the new kernel to be available at boot time, the binary image has to be installed in the proper directory, usually in the main /boot directory.

Note

You can install the kernel image using the command make install, but you will not have control on the naming of the image and other details. It is recommend to install the kernel image and other files by following the steps shown bellow.

Install the new Linux kernel image by copying the arch/<arch>/boot/bzImage file into the top /boot directory from the right architecture directory, where <arch> corresponds to the target architecture for this kernel image.

Hint

The images for both 64 bits and 32 bits kernels are placed in the same arch/boot/x86 directory. When compiling for the x86_64 architecture the kernel is built in the x86 directory and a link is created in the arch/x86_64/boot to the arch/x86/boot/bzImage file.

It is a convention that the name of the kernel image in the /boot directory starts with vmlinuz and is followed by the numbers of the release used. The final name depends on the choices of the distribution. For the linux-configs collections, the information about the variant used can also be attached to the name. Hence, as an example, for a 64 bits image for a physical PC compatible system, the full command could be:

# cp arch/x86_64/boot/bzImage /boot/vmlinuz-4.19.21-x86_64-pc_generic

Although not necessary, it can be convenient to save a copy of the .config file in the same /boot directory. For example, using the phyglos naming conventions for the final file:

# cp .config /boot/linux-4.19.21-x86_64-pc_generic.config

Finally, in order to allow debugging the kernel, a file called System.map can be also saved in the /boot directory:

# cp System.map /boot/System.map-4.19.21-x86_64-pc_generic

Tip

This last step is not really necessary if you do not intend to debug the kernel. It can be omitted to simplify and save a few megabytes of space in the boot directory.