How to build the Linux Kernel

The following instructions are based on CentOS 7, these should work for most other distributions, however, the initial dependencies will need to be reviewed.

Unless prefixed with sudo, all commands can be executed as a non-root user.

Why

There’s a few reasons why you’d want to build your own kernel, however, most of the point below aren’t significant.

  • Access recent enhancements not yet available in Linux distributions, in my case, I wanted to continue to run CentOS on my server, but build my kernel myself to access modern features (prebuilt unsupported Kernels are available).
  • Learning exercise - this was my secondary reason.
  • Creating a slimmer Kernel for performance (with many modules only being loaded when needed, I’m not sure on this)
  • Security’s sake (this requires you to be vigilant to always update the Kernel yourself)

Install Dependencies

In this case, we want tools like gcc (for compiling) and ncurses (for menuconfig):

$ sudo yum groupinstall "Development Tools"
$ sudo yum install ncurses-devel -y

Fetch the Kernel source

Go to kernel.org to fetch the kernel version that you’d like, most likely, you’ll just want the latest stable.

$ mkdir linux
$ cd linux/
$ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.1.tar.xz
$ tar xfJ linux-3.18.1.tar.xz
$ cd linux-3.18.1/

Configure the Kernel

To preconfigure my kernel, I’m using the existing configuration options based on CentOS’s current running Kernel. This’ll help me compile everything I need, and just look for the specific options I want or don’t want.

The Kernel also comes with options to build a default config (make defconfig), but I don’t know exactly how this configuration is built. Some options are set in arch/x86/configs/x86_64_defconfig, but not all.

But for the moment, I’ll reuse CentOS’s but you could use the default by running make defconfig instead of the following:

$ cp /boot/config-`uname -r ` .config

If you’re using CentOS’s default from an older Kernel, you’ll want to upgrade the .config file to incorporate the new options. The command make olddefconfig will upgrade the .config file, setting the default values without prompting. Alternatively, you can run make oldconfig which prompts for answers to each configuration option. Only run this if you’re upgrading the .config file (not using a .config file build from make defconfig).

$ make olddefconfig

From here, I use menuconfig, a ncurses based interface to choose Kernel configuration options. There’s also GTK+ (make gconfig), QT (make xconfig), a purely text based option (make config).

$ make menuconfig

Compile the Kernel

This process takes a while, depending on options and CPU age and number of CPUs, less so disk IO speed. Optionally, and likely recommended, is to supply the -j [jobs] flag, this specifies the number of jobs running concurrently - you’ll want to set this number to the number of CPUs in your system.

In my case, because I have 2 CPUs, I would run:

$ make -j 2

Because I wanted to time the events, and run at a higher concurrency rate (long story short, it didn’t perform any better), I used the following command to also include timing information:

$ START_DATE=`date`; time make -j4; echo "Start date: $START_DATE"; echo -n "End date: "; date
real    350m30.902s
user    440m34.103s
sys     224m7.598s
Start date: Wed Dec 24 09:42:43 ACDT 2014
End date:   Wed Dec 24 15:33:14 ACDT 2014

Grab a tea, this’ll take a while if you’re running older hardware (in my case, a Virtual Box guest on a 2008 2.4GHz Core 2 duo).

Install the Kernel

This process is far quicker, but may still take a few minutes depending on your disks. Note, only now do we need to run as a root user.

$ sudo make modules_install
$ sudo make install

Finishing Touches

Your Kernel is not built and installed, it should have also updated GRUB configuration. But in some cases, you may need to run mkinitrd, but it appears make install did more work than I expected.

In my final case, I wanted this new Kernel to be my default, so I set it like so:

$ sudo grub2-set-default 0

Additional Reading

See Linux Kernel in a Nutshell.