Linux kernel code tree

Code related to this blog is on Githubclick here. Please make suggestions and critiques in the comments section below.

Introduction

Linux is the most widely used Open Source operating system in the world today. The Linux Kernel is the core around which all Linux operating systems are built. This blog is partly about curiosity regarding the actual code in the Linux Kernel and how difficult (or easy??) it would be to create one’s own operating system from the Linux Kernel.

Of course, many books and blogs exist on the Linux Kernel. However Linux Kernel development is a dynamic ever-changing project. And with thousands of contributors making hundreds of thousands of code changes every single day, the likelihood of a ‘how-to‘ recipe getting dated is quite high. Perhaps a better approach is to study the development process and engage with it instead. Luckily the project is very well documented on The Linux Kernel Documentation website, so that will be our main source of information.

Why?

So why should one be interested in compiling the Linux Kernel? (This list below is by no means exhaustive)

  • Device Drivers – most of the code in the Linux Kernel comes in the form of device drivers from businesses creating IT components. Of course to design, create and test these drivers, you must be able to integrate the code with the Linux Kernel code, compile, test and debug it.
  • Linux Distributions – Most Linux distros use pre-compiled kernels, however customisations in some distros may necessitate compiling the Linux kernel from source. For example, Canonical provides a number of Ubuntu Kernels.
  • DIY OS – want to create your own operating system? Why not? You probably know someone with an Android smart phone. And Android is built on top of the Linux kernel. Check out the Android Open Source Project (AOSP) architecture overview here.
  • Follow the French? – the issue of digital sovereignty is trending, with the French government announcing in April 2026 plans to install Linux on around 2.5 million devices in its civil service. Well, any serious effort at digital sovereignty based on Linux and Open Source would include engaging with Linux at the kernel level. Nadia Dubois has written a great article about this announcement in Tech Insider.
  • Students of OS Design – there are many Open Source operating system candidates for study, not least, MINIX. However, for a widely used kernel, Linux will make a very good choice.
  • Geeks et al – for hackers, tinkerers and the eternally curious, the Linux Kernel comes highly recommended given its popularity, copious documentation and a large ever growing community.

For beginners, the Linux Foundation offers a free course A Beginner’s Guide to Linux Kernel Development (LFD103) which I highly recommend.

This blog is a hands-on collaborative Learning Together effort. We may also develop scripts to automate certain tasks in the process.

Requirements

Any regular computer or laptop with a reasonable 64 bit CPU will do. A 30-40 GB disk and at least 8GB of RAM is recommended. A higher specification is obviously better for speed of compilation. For Windows users, you can use a VM (virtual machine) for which you’ll need a hypervisor like VirtualBox or VMWare Workstation.

Familiarity with any programming language is required if you wish to follow (and contribute to) the scripts being developed.

Although Linux works on many architectures, we will be dealing with the x86 instruction set architecture, which primarily refers to CPUs from Intel and AMD. Of course contributions from people working on other architecture is welcome.

First things first – Caution

After compiling and installing the kernel, the boot process may be adjusted to try and boot the newly compiled kernel in the first instance on the next reboot. What if that kernel fails to boot?

Make sure to take a fresh backup of your system – just in case.

Many modern systems will only boot ‘trusted’ kernels and your recently compiled kernel is not trusted. One way to avoid this issue is to temporarily disable secure boot in the BIOS. In an x86 Linux environment, you can use the mokutil program to disable secure boot restrictions. Start by just running the command. If you get a response like ‘This system doesn’t support Secure Boot‘ then there is nothing more to do. Otherwise you can run mokutil –disable-validation then enter a temporal password, which you will need when rebooting. To re-enable validations run mokutil –enable-validation.

Development System Setup

At this point, we have a Linux system installed either on bare metal or in a VM. Next we need to ensure that our Linux system has the libraries needed to compile the Linux kernel.

For this, we will follow the minimum requirements to compile the kernel recommended in the Linux kernel docs here. There are a lot of libraries listed. This might be a good place to start thinking about some automation. How about a script that checks and installs and/or updates the libraries?

Code related to this blog is on Githubclick here. Please make suggestions and critiques in the comments section below.

The plan is to put all the requirements into a configuration file. And a script would then process this file to install and/or update the libraries. There are two main advantages to this approach, namely:

  • customisable – you can customise the config file for your own needs (e.g for different architectures)
  • future proofing – if (when) requirements change in future, the only thing likely to need modification is the config file

The idea is to place this and other scripts into a library, whose structure is shown in the graphic on the left. At the root are the executable utilities, and their code will be placed in the utilities.d directory, along with common routines in the common.d directory. The config.d and template.d directories are self explanatory – for configurations and templates respectively.

In general running a utility will take the following form: <utility> <command> <options> for example:

kernel check-requirements

The above call will only work once a proper PATH has been specified to the installed location – that is for the future. For now, run it from the lib directory like this:

./kernel check-requirements

The ‘kernel’ Utility

The ambition for the kernel utility is a set of routines to help with setting up an environment, obtaining kernel code, compiling and installing the new kernel.

Minimum requirements checker

The first routine checks for minimum requirements as listed in the kernel documentation. In theory this should be fairly straight forward, and the logic should run something like this:

i) pick a requirement
ii) if the library / program is NOT installed, then install it
iii) if the version is LESS THAN the required version, then update it

However, we immediately run into an issue, namely, there is no uniformity in the way these programs maintain and report their version numbers. We address this and other issues in the config file by, for example, requiring each dependency to specify how to get its version information. So an entry in the config file is structured as follows:

progam / dependency, minimum version, command to get version, regular expression to get version, command to install, required (yes/no)

Testing 01 – Ubuntu Server 24.04 (Debian based)

Errors are currently displayed on screen for debugging purposes.

The script is processing each requirement in the config file and installing or updating dependencies as needed.

When it finishes, errors are reported for the following requirements:

  • make
  • jfsutils
  • kmod
  • udev

Four error reports out of 29 requirements processed. Not a bad start.

Now, we’ll look at each error report separately.

i) make

The issue here was found to be in the way make reported its version in Debian 13.10 vs Ubuntu Server 24.04. The GNU make utility reports its version in the following format:

<major>.<minor>.<patch>

This convention is maintained in Debian 13.10 as well as in other distros (eg CachyOS which is Arch based maintains that convention), but (for some reason) the same utility in Ubuntu Server 24.04 has removed the <patch> number and only reports <major>.<minor>

The config file has been modified to account for this variation, though it’ll be interesting to find out why Canonical (Ubuntu) broke with this convention.

Comments

Leave a Reply