How to Compile and Install the Linux Kernel on Ubuntu
In this post I will show you how to compile and install the Linux kernel from source on Ubuntu.
I know that there are tons of tutorials on compiling the Linux kernel. However, while I tried many of them, none of them worked for me. I always either got error messages during compilation or the compilation terminated without error messages but failed at installation. Therefore, I decided to write down how I did it.
The setup I tested this on
I used a freshly installed VirtualBox with Ubuntu Server 22.04. I did not do any modifications to the machine and didn’t install any packages on it beforehand. Additionally, I also tested the steps presented in this post on a real computer with an AMD Ryzen 7 2700X CPU.
Installing dependencies, downloading the kernel source
First we need to install a few packages that are required for the compilation:
$ sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev fakeroot
Additionally we also need to install the dwarves
package. When I tried it without the package, the compilation failed with an error message.
$ sudo apt install dwarves
Next we need to need to download the kernel source from the offical kernel.org website.
Choose the latest longterm
release and copy the link of the tarball
hyperlink.
Then use this link to download and unpack the kernel source to your Ubuntu machine:
$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.89.tar.xz
$ tar -xf linux-5.15.89.tar.gz
Configuring the kernel
Now enter the directory of the Linux source:
$ cd linux-5.15.89
The configuration of the Linux kernel can be specified in a .config
file.
A good starting point is to copy the config file of your currently installed Linux:
$ cp -v /boot/config-$(uname -r) .config
However, this config file includes tons of unnecessary drivers and kernel modules which dramatically increases the build time.
To mitigate this, we can use the localmodconfig
command.
This command looks at the loaded kernel modules of your system and modifies the .config
file such that only these modules are included in the build.
This should work perfectly fine as long as you don’t plan to use the generated build on another machine than the one you compile the source on.
make localmodconfig
If, while running the above command, any requests are promted to you, just hit enter each time (without typing an answer).
Next, you need to make four modifications to the configuration. Otherwise the build will fail.
To do this, you can either directly modify the .config
file or simply run the following commands:
$ scripts/config --disable SYSTEM_TRUSTED_KEYS
$ scripts/config --disable SYSTEM_REVOCATION_KEYS
$ scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEYS ""
$ scripts/config --set-str CONFIG_SYSTEM_REVOCATION_KEYS ""
Compiling
Now it’s time to compile the kernel. For this just run the command
$ fakeroot make
Note that it is very important to run the command with the fakeroot
prefix.
This was something I had to figure out myself because none of the other tutorials I read mention it.
When you don’t run fakeroot make
but only make
the build process will terminate without any error messages which seems good but isn’t.
In reality, the build fails with error code 2 (can be checked by running echo $?
afterwards) after some time.
You can also speed up the build by using multiple CPU cores of your machine. For instance,
$ fakeroot make -j8
will use eight cores of your machine.
The build time heavily depends on your machine and is especially slow on virtual machines. On my VirtualBox with only one CPU core it took around 3 hours. On a physical computer with an AMD Ryzen 7 2700X with 8 cores it took only 6 minutes.
After the build finishes, you can check whether it is successful by running
$ echo $?
This outputs the return code of the previous command. If it returns 0
, the build was sucessful. For any other value than 0
the build was not sucessful.
Installation
The installation is split into two parts: Installing the kernel modules and installing the kernel itself.
First install the kernel modules by running
$ sudo make modules_install
Then install the kernel itself:
$ sudo make install
After that, reboot your machine:
$ sudo reboot
Checking if kernel was installed sucessfully
You can check the version of the installed kernel by running
$ uname -rs
This outputs something like
You know that the installation was sucessfull if the displayed Linux version matches the one of the kernel source you downloaded.
Bonus: Modifying the kernel source
Of course you can also modify the Kernel source before installation to make your own custom version Linux. As a very simple example for such a modification I’ll modify the name of the operating system. Any other modification of the source code works the same.
The default name is of course “Linux”. It is stored in the include/linux/uts.h
header file, which looks like this:
// include/linux/uts.h
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_UTS_H
#define _LINUX_UTS_H
/*
* Defines for what uname() should return
*/
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif
#ifndef UTS_NODENAME
#define UTS_NODENAME CONFIG_DEFAULT_HOSTNAME /* set by sethostname() */
#endif
#ifndef UTS_DOMAINNAME
#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */
#endif
#endif
We can now change the operating system name by changing the UTS_SYSNAME
field. In my case I’ll change it to DavidOS
:
// include/linux/uts.h
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_UTS_H
#define _LINUX_UTS_H
/*
* Defines for what uname() should return
*/
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "DavidOS" // <-- CHANGED
#endif
#ifndef UTS_NODENAME
#define UTS_NODENAME CONFIG_DEFAULT_HOSTNAME /* set by sethostname() */
#endif
#ifndef UTS_DOMAINNAME
#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */
#endif
#endif
After you modified the file, you can simple re-compile the kernel and then install it:
$ fakeroot make
$ sudo make modules_install
$ sudo make install
$ sudo reboot
The compile time should now be significantly shorter than the first time. The reason is that make
re-uses some results from the first compilation run.
When you now run uname -rs
you get the following:
As you can see, it now displays DavidOS
instead of Linux
.
And that’s it
Now you know how to compile the Linux kernel yourself. You can use this knowledge to upgrade to the latest kernel version long before your Linux distribution does. Besides this you can also customize the kernel to adapt it to your needs.