How to build an Ubuntu Linux kernel

If you have patches you need to apply to the Ubuntu Linux kernel, or you want to change some kernel configs, you may need to build your kernel from source. Follow these steps to customize and build the Ubuntu Linux kernel.

Important

Kernels built using this method are not intended for use in production.

Prerequisites

  • This guide supports Xenial Xerus and newer.

  • It is recommended to have at least 8GB of RAM and 40GB free disk space on the build machine.

If this is the first time you are building a kernel on your system, you will need to Set up build environment and Install required packages.

Otherwise, skip ahead to Obtain the source for an Ubuntu release.

Set up build environment

To build an Ubuntu kernel, you will need to enable the necessary source repositories in the sources.list or ubuntu.sources file.

See How to enable kernel source package repositories for details.

Install required packages

To install the required packages and build dependencies, run:

sudo apt update && \
    sudo apt build-dep -y linux linux-image-unsigned-$(uname -r) && \
    sudo apt install -y fakeroot llvm libncurses-dev dwarves

Obtain the source for an Ubuntu release

There are different ways to get the kernel sources, depending on the kernel version you want to make changes to.

Get the latest kernel source for your Ubuntu release

Use the apt source command to get the latest kernel source for your Ubuntu release. This is the version in the archive, which may be newer than the kernel you are running.

In this guide we will assume you are using the generic kernel:

apt source linux-image-unsigned-$(uname -r)

Otherwise, append your flavour name onto the end (like -realtime for the real-time kernel). Keep in mind some folder names will be different in this case.

This will download and unpack the kernel source files to your current working directory.

<working_directory>
├── linux-X.Y.Z/
│   └── *
├── linux_X.Y.Z-*.diff.gz
├── linux_X.Y.Z-*.dsc
└── linux_X.Y.Z.orig.tar.gz

Get kernel source for a specific version

To build a particular kernel version, including the one you are currently running, use Git. Released versions are available as Ubuntu-* tags. See How to obtain kernel source for an Ubuntu release using Git for detailed instructions.

Prepare the kernel source

Once you have the kernel source, go to the kernel source working directory (e.g. “linux-6.8.0”) and run the following commands to ensure you have a clean build environment and the necessary scripts have execute permissions:

cd <kernel_source_working_directory>

chmod a+x debian/scripts/* && \
    chmod a+x debian/scripts/misc/* && \
    fakeroot debian/rules clean

Modify ABI number

You should modify the kernel version number to avoid conflicts and to differentiate the development kernel from the kernel released by Canonical.

To do so, modify the ABI number (the number after the dash following the kernel version) to “999” in the first line of the changelog file. For the generic kernel this file is at debian.master/changelog.

For example, modify the ABI number to “999” for Noble Numbat:

linux (6.8.0-999.48) noble; urgency=medium

If you are building something other than the generic Ubuntu Linux kernel, modify the ABI number in debian.<flavour>/changelog instead.

Modify kernel configuration

(Optional) To enable or disable any features using the kernel configuration, run:

fakeroot debian/rules editconfigs

This will invoke the menuconfig interface for you to edit specific configuration files related to the Ubuntu kernel package. You will need to explicitly respond with Y or N when making any config changes to avoid getting errors later in the build process.

Note

If you do not have the compiler toolchain installed for each architecture supported by the kernel being configured, you’ll see errors that the configs for these uninstalled architectures are missing. These can be ignored as long as you don’t intend to build binaries for those architectures.

Customize the kernel

(Optional) Add any firmware, binary blobs, or patches as needed.

Build the kernel

To simplify the build process for development, export this config option:

export do_linux_main_modules_depends=false

Important

zfs and v4l2loopback modules are not included in this mode. If you need these modules during development we recommend installing their dkms packages.

No action needed.

You are now ready to build the kernel.

fakeroot debian/rules clean && \
    fakeroot debian/rules binary

Note

Run fakeroot debian/rules clean to clean the build environment each time before you recompile the kernel after making any changes to the kernel source or configuration.

If the build is successful, several .deb binary package files will be produced in the directory one level above the kernel source working directory.

For example, building a kernel with version “6.8.0-999.48” on an x86-64 system will produce the following .deb packages (and more):

  • linux-headers-6.8.0-999_6.8.0-999.48_all.deb

  • linux-headers-6.8.0-999-generic_6.8.0-999.48_amd64.deb

  • linux-image-unsigned-6.8.0-999-generic_6.8.0-999.48_amd64.deb

  • linux-modules-6.8.0-999-generic_6.8.0-999.48_amd64.deb

Install the new kernel

Important

The packages produced by this build are unsigned. On a system with Secure Boot enabled, the new kernel will not boot. Either test on a system with Secure Boot disabled, such as a virtual machine, or sign the kernel image with an enrolled Machine Owner Key (MOK) first before installing.

Install all the debian packages generated from the previous step (on your build system or a different target system with the same architecture) with dpkg -i and reboot:

cd ..
sudo dpkg -i linux-headers-<kernel version>*_all.deb \
    linux-headers-<kernel version>-<flavour>*.deb \
    linux-image-unsigned-<kernel version>-<flavour>*.deb \
    linux-modules-<kernel version>-<flavour>*.deb
sudo reboot

Test the new kernel

Run any necessary testing to confirm that your changes and customizations have taken effect. You should also confirm that the newly installed kernel version matches the value in the <kernel_source_working_directory>/debian.master/changelog file by running:

uname -r