The kernel is the most important component of an operating system: among the other things, it provides support for different types of hardware and manages resource allocations.
Linux is a monolithic kernel: although its functionalities can be included statically or built and loaded as separate
modules, it always runs as a “single piece” in the same address space. In this tutorial we will see how to download, compile and install a vanilla Linux kernel. The instructions provided should work on all Linux distributions, however this guide is focused on compiling the kernel on a Fedora system.
In this tutorial you will learn:
- How to configure, compile and install a vanilla Linux kernel
- How to package the compiled kernel and its modules
Software Requirements and Conventions Used
|Category||Requirements, Conventions or Software Version Used|
|Other||Root permissions to install needed dependencies and the compiled kernel|
|Conventions||# – requires given linux commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux commands to be executed as a regular non-privileged user
Installing the dependencies
To be able to compile the Linux kernel from source we need to install some packages in our system:
$ sudo dnf install gcc flex make bison openssl-devel elfutils-libelf-devel
The ones above are only the ‘core’ packages we need. To invoke specific configuration targets some extra packages must be installed: the
qt-devel packages, for example, are needed to configure the kernel making use, respectively, of the ncurses-based and the Qt graphical interface, while the
rpm-build package is needed to build an rpm containing the compiled kernel.
Downloading the source tarball
As a first thing, we need to obtain the tarball containing the latest stable Linux kernel sources. We can download and extract the tarball with just one command:
$ curl https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.5.tar.xz|tar -xJ
At the end of the download process, inside our current working directory, we should find a new the folder containing the kernel source code. We need to enter it, in this case:
$ cd linux-5.1.5
At this point we can configure the kernel. In the next paragraph we will take a look at the most common configuration targets used to accomplish the task.
Configuring the kernel
There are various ways we can configure the kernel, and they correspond to different
configuration targets. When a configuration target is invoked, if a file named
.config containing a valid kernel configuration is found in the sources directory, it is used as a starting point for the setup. This makes possibile to update or modify an already existent configuration, perhaps the one that comes with the kernel installed by default in our distribution, (it can be found inside the
/boot directory, named after the kernel in use).
If the file is not found, the configuration will start from scratch and the
.config file will be generated once we save our setup. Let’s see some of the
configuration targets we can use:
If this target is invoked, the user is prompted to configure the kernel by answering a series of questions, in the following fashion:
* * Linux/x86 5.1.5 Kernel Configuration * * * Compiler: gcc (GCC) 9.1.1 20190503 (Red Hat 9.1.1-1) * * * General setup * Compile also drivers which will not load (COMPILE_TEST) [N/y/?]
This target uses a nice and user-friendly
ncurses interface to let us generate or update the kernel configuration. As said before, to be able to use this interface the
ncurses-devel package must be installed in the system.
Using this interface, we can press the
h key when highlighting a specific option to obtain information and suggestions about it:
By invoking this make target it’s possibile to configure the kernel via a graphical interface based on the
Qt toolkit if the
qt-devel package is installed in the system.
This target it’s useful when we want to use an already existing kernel configuration as a starting point. When we invoke this target, we are prompted to configure only the features available in the kernel we are configuring but not included in the original configuration file.
Invoking this target will generate or update a new kernel configuration file on the base of the modules currently loaded on the system. Only them will be included in the configuration, the others will be disabled. This can be used as a quick way to obtain a tailored kernel based on the current state of a machine.
This target works similarly to
localmodconfig with one big difference: the functionalities provided by the modules currently loaded in the system will be statically included into the kernel.
Compiling and installing the kernel
Once we finished configuring the kernel, we can compile the source code. All we have to do is to run:
The operation may take a while, depending on the features we decided to include in the kernel. To speed up the process we can run
make with the
-j option and specify the number of jobs to run simultaneously: a value often used for this option is the number of logical CPU cores + 1. On a machine with 4 logical cores, we would therefore run:
$ make -j5
Once compiled, to install the kernel we can simply run:
$ sudo make install
The kernel core files will be copied inside the
/boot directory. To compile and install the kernel modules, instead, we can run:
$ sudo make modules_install
The kernel modules will be installed in a directory under
/lib/modules named after the kernel version. Finally, for the new kernel to be available and selectable at boot, we must regenerate the grub configuration:
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Packaging the kernel
Instead of installing the compiled kernel directly as we did above, in order to be able to manage its installation and removal via the system package manager, we can create an
rpm package. To accomplish the task we must use one between the
binrpm-pkg targets. The first will build both the source and binary RPM packages, the second only the binary one. For this target to run correctly, the
rpm-build package must be installed. To build only the binary rpm package, we would run:
$ make binrpm-pkg
If the operations are performed without errors, the
rpmbuild directory tree will be created in our home directory. The built rpm package will be available in a subdirectory of
~/rpmbuild/RPMS named after the architecture of the system.
Another option is to package the kernel and its modules inside a compressed tarball, by using one between the
tarxz-pkg targets, depending on the compression we want to use. The tarball will be created inside the kernel source directory.
In this tutorial we learned to know why Linux is called a monolithic kernel, and how its components can be configured statically or as modules. We saw how to download a vanilla kernel and the various methods we can use to configure it. Finally, we saw how to compile it, package it and install it in our system. One last advice: if you decide to re-compile the kernel, it’s always a good idea to invoke one of the
cleaning targets before proceeding:
- clean: Removes most generated files but keep the config and enough build support to build external modules
- mrproper: Removes all generated files + config + various backup files
- distclean: Executes mrproper and also removes editor backup and patch files