Ted's Linux Kernel Build HOWTO

By Ted Felix Updated March 20, 2020

Goal

...to get kernel source from kernel.org and build a vanilla kernel.

Get the Source

The latest kernel source can be found at www.kernel.org.

To save bandwidth (both yours and kernel.org's) I recommend downloading the base source and the latest patch. This way for future upgrades, you just need to download the patch, which is much smaller than the complete source. As an example, let's say we want to build version 5.5.10. We would download the following two files:

linux-5.5.tar.xz patch-5.5.10.xz

Download them from kernel.org's kernel file area.

Next we extract the source and apply the patch.

tar -xf linux-5.5.tar.xz cd linux-5.5 xz -dc ../patch-5.5.10.xz | patch -p1

Then give the directory its rightful name.

cd .. mv linux-5.5 linux-5.5.10 cd linux-5.5.10

Build Requirements

You'll need a C compiler and an assembler. In Debian/Ubuntu, build-essential and the build deps for "linux" should get you there:

sudo apt-get install build-essential sudo apt-get build-dep linux

Kernels 4.8 and up require the openssl development libraries.

sudo apt-get install libssl-dev

Configure the Kernel

Configuring the Linux kernel is probably the most difficult task you'll encounter. However, with a few tricks, it isn't really all that bad.

It helps to have an existing kernel config as a starting point. The best config to start with is one that is either for the same kernel version you are building, or one whose version is as close as possible to the version you are building. Check the online repositories for your distro to see if there is a kernel with a closer version number. A while back, using Debian, I was able to find a 2.6.30 kernel in "backports" that was close to the 2.6.31 that I wanted to build, so I went with it. As of March 2020, Ubuntu 18.04 offers linux-generic-hwe-* and linux-lowlatency-hwe-* meta-packages which bring in the latest and greatest kernels.

The easiest approach is to install the kernel you'd like to use as your starting point, then reboot into that kernel. The kernel build tools will use the config for the currently running kernel as its starting point. Use uname to check that you are running the proper kernel:

uname -a

Note: You can also copy a config from /boot to .config in the kernel source directory.

Next we need to update the config to the latest version. The fastest way is to use menuconfig. It will automatically update your config and let you tweak anything you want. Run it like this:

make menuconfig

You can now wander through the numerous kernel configuration settings and see if anything grabs your attention. For many of the settings, the help (press "?") will explain what the typical setting is.

To make a smaller kernel that will build a bit faster, make sure debug info is turned off. You can find it in "Kernel hacking > Compile-time checks and compiler options > Compile the kernel with debug info". Turning this off will reduce the size of the modules by a factor of 10.

Be sure to exit and save your new configuration.

Since making a .config can be a lot of work, be sure to backup your config as it stands.

cp -p .config ~/config.backup

You can also use "make oldconfig" to convert an older config to the new format. If this is a big change, oldconfig will walk you through the new settings. This can take a very long time, but if you're interested in the differences between kernels, this might come in handy.

Build the Kernel

Clean up any leftovers from previous builds.

make clean

Before we build, you might want to configure make to take advantage of all the cores on your processor. The "-j" option tells make how many jobs to run. The following should set this up appropriately:

export MAKEFLAGS="-j`nproc`"

Note: You can add that line to the end of your .bashrc and it will always be in effect.

And build the kernel and the modules.

nice make

I've added nice to prevent the build from dragging the machine down if you want to do other things while the build is in progress. Feel free to omit it if you want it to run a little bit faster.

Install the Kernel

Before you install a kernel, make sure you aren't running the kernel you are about to install. I've not tried it, but I'm betting it won't work. Reboot with one of your distro's standard kernels before proceeding.

Next, install the modules and the kernel itself:

sudo make modules_install install

And that should be it. With older kernels, the process isn't always so simple. See the troubleshooting tips at the end if this isn't working for you.

BACKUP and Reboot

Now would be a good time to backup your machine in case something bad happens with the new kernel.

Reboot and try your new kernel.

To make sure you are running your new kernel, verify the version and build date with the uname command:

uname -a

If the reboot fails, you can select a known working kernel through your bootloader's boot menu. If the menu isn't visible when you boot, hold down the left shift key (legacy) or the Esc key (UEFI) while booting. More in the next section.

GRUB Menu

When you get really deep into building kernels, you'll find pressing left shift or Esc at boot is a pain. Or you might even find that they don't work. To force the menu up, make the following changes to /etc/default/grub.

Once you've made those changes, you'll need to run update-grub.

sudo update-grub

Links

Linux Kernel in a Nutshell - Much more detail on building kernels. It's a bit dated, though, as it was written for 2.6.18.

Troubleshooting Tips

The following are portions that I've pulled out of the main text. At one time I was not seeing the kernel makefiles create the initial ramdisk and update the bootloader. Turns out I was running make install BEFORE make modules_install instead of the other way around. As a result, I had to learn about making initial ramdisks and updating bootloaders. This info might be helpful in the future, so I don't want to lose it.

Installing Older Kernels

With older kernels, sometimes the modules directory wouldn't get cleared out, and the initrd file wouldn't get created properly. Read through these steps if you are having trouble. They might provide some ideas that will help.

If you are building the same version of the kernel again, I've found that it is a good idea to clear out the old modules. You can safely skip this the first time you build a specific kernel version. For this example, we'll clear out the modules for 3.9.10:

cd /lib/modules sudo rm -rf 3.9.10 cd -

"cd" with a hyphen will take us back to where we were previously. That will be our linux-3.9.10 directory.

Install the new modules to /lib/modules.

sudo make modules_install

If you are building the same version of the kernel again, go into the /boot directory and either remove or rename the old initial ramdisk. This step is required or else you will end up with a bad initial ramdisk.

cd /boot sudo rm initrd.img-3.9.10 cd -

Install the new kernel to /boot, create the initial ramdisk, and update the bootloader.

sudo make install

Now take a look at the /boot directory to make sure everything was installed correctly. You should see the following files at a minimum:

initrd.img-3.9.10 vmlinuz-3.9.10

If the initrd file is missing, you'll need to make the initial ramdisk manually. See the next section, "Updating the Initial RAM Disk".

Updating the Initial RAM Disk

Go into the /boot directory and either remove or rename the old initial ramdisk. This step is required or else you will end up with a bad initial ramdisk.

cd /boot sudo rm initrd.img-3.1.9

Build a new initial ramdisk. In a Debian-based distro (e.g. Ubuntu), the update-initramfs script will do the job for you:

sudo update-initramfs -c -k 3.1.9

If update-initramfs is not available in your distro, you can use mkinitramfs directly:

sudo mkinitramfs -o initrd.img-3.1.9 3.1.9

If you had to do this step manually because your distro didn't properly create the initial ramdisk, you should update your bootloader so that it can find the initrd.img file. Continue to the next section.

Bootloader

To boot a new kernel, we need to update our bootloader to point to the new kernel and initial ramdisk. There are a number of different bootloaders, so the instructions vary depending on which one you are using.

GRUB 1

Version 1.x of GRUB is configured through menu.lst. Look for /boot/grub/menu.lst and edit it. Copy the lines for one of the other kernels and modify it to point to your new one.

GRUB 2

If you have built a new kernel (not replaced an old one), run update-grub to get it into the grub menu. grub2 defaults to the newest kernel that you've installed. Press and hold left shift or Esc while booting to get the grub menu and select a different kernel.

LILO

For lilo, take a look at /etc/lilo.conf, and make any changes that are needed. Then you must run the "lilo" command before rebooting, even if you make no changes to the lilo.conf. This is because lilo has to figure out where your new kernel is on the hard drive.

License

Copyright (C) 2009-2020, Ted Felix

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. See the Free Documention License for the full text of this license.

<- Back to my Linux page.