1. Overview

In this tutorial, we’ll configure the Linux kernel and learn about its oldconfig Makefile target.

2. Getting the Linux Kernel’s Source Code

As we know, the Linux kernel is completely open-source, and we can grab its source code from https://kernel.org. At the time of writing, the latest version is 5.14.14. Let’s download it with curl:

$ curl -LO "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.14.14.tar.xz"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  115M  100  115M    0     0  2688k      0  0:00:43  0:00:43 --:--:-- 2831k

Now we can extract it with tar by running tar xf linux-5.14.14.tar.xz and cd into it.

3. The Build System

The Linux kernel’s build system mainly revolves around Makefiles used with the make tool. It configures various build options through the top-level .config file. We use the top-level Makefile to configure and build the kernel in a convenient way through make targets.

4. Configuring the Kernel

We can use various configuration frontends to configure the Linux kernel and easily search through configuration options. They use Kconfig files internally for this purpose.

4.1. Menu-Based TUI

We can configure the kernel via an interactive menu-based program by running make menuconfig:

 .config - Linux/x86 5.14.14 Kernel Configuration
  ┌───────────────────────────────────────────────── Linux/x86 5.14.14 Kernel Configuration ─────────────────────────────────────────────────┐
  │  Arrow keys navigate the menu.  <Enter> selects submenus ---> (or empty submenus ----).  Highlighted letters are hotkeys.  Pressing <Y>  │  
  │  includes, <N> excludes, <M> modularizes features.  Press <Esc><Esc> to exit, <?> for Help, </> for Search.  Legend: [*] built-in  [ ]   │  
  │  excluded  <M> module  < > module capable                                                                                                │  
  │                                                                                                                                          │  
  │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │  
  │ │                                    General setup  --->                                                                               │ │  
  │ │                                [*] 64-bit kernel                                                                                     │ │  
  │ │                                    Processor type and features  --->                                                                 │ │  
  │ │                                    Power management and ACPI options  --->                                                           │ │  
  │ │                                    Bus options (PCI etc.)  --->                                                                      │ │  
  │ │                                    Binary Emulations  --->                                                                           │ │  
  │ │                                    Firmware Drivers  --->                                                                            │ │  
  │ │                                [*] Virtualization  --->                                                                              │ │  
  │ │                                    General architecture-dependent options  --->                                                      │ │  
  │ │                                [*] Enable loadable module support  --->                                                              │ │  
  │ │                                -*- Enable the block layer  --->                                                                      │ │  
  │ │                                    IO Schedulers  --->                                                                               │ │  
  │ │                                    Executable file formats  --->                                                                     │ │  
  │ │                                    Memory Management options  --->                                                                   │ │  
  │ │                                [*] Networking support  --->                                                                          │ │  
  │ │                                    Device Drivers  --->                                                                              │ │  
  │ │                                    File systems  --->                                                                                │ │  
  │ │                                    Security options  --->                                                                            │ │  
  │ │                                -*- Cryptographic API  --->                                                                           │ │  
  │ │                                    Library routines  --->                                                                            │ │  
  │ └────────────────────────────────v(+)──────────────────────────────────────────────────────────────────────────────────────────────────┘ │  
  │                                         <Select>    < Exit >    < Help >    < Save >    < Load >                                         │  

We use the legends at the top to identify what various symbols mean and press space to toggle features, using arrow keys to navigate the menu.

Additionally, we can find a similar menu named nconfig, which offers fuzzy-search and has a dark UI.

4.2. Plaintext Menu

We can also use make config to configure the kernel via a basic prompt-based menu. We’ll need to answer various options such as Y to enable a feature, N to disable it, and m to build it as a module if possible:

$ make config
  HOSTCC  scripts/kconfig/conf.o
  HOSTLD  scripts/kconfig/conf
* Linux/x86 5.14.14 Kernel Configuration
* General setup
Compile also drivers which will not load (COMPILE_TEST) [N/y/?] y
Local version - append to kernel release (LOCALVERSION) [] 
Build ID Salt (BUILD_SALT) [] 
Kernel compression mode
> 1. Gzip (KERNEL_GZIP)
  2. Bzip2 (KERNEL_BZIP2)
  6. LZ4 (KERNEL_LZ4)
choice[1-7?]: 5
Default init path (DEFAULT_INIT) [] 
Default hostname (DEFAULT_HOSTNAME) [(none)] 
Support for paging of anonymous memory (swap) (SWAP) [Y/n/?] Y

This can be very cumbersome to go through, so most people prefer the menuconfig approach.

4.3. Auto-Generated Configs

We can automatically generate a config to build upon from various targets:

  • defconfig – Generates a default config for the current architecture from predefined rules, such as arch/x86/configs/x86_64_defconfig for x86_64 systems.
  • localmodconfig – Generates a config based on the current kernel’s configuration and loaded modules to disable unneeded modules.
  • localyesconfig – Similar to localmodconfig but changes all module (m) options to built-in (=y).

5. The oldconfig Target

The oldconfig target updates a pre-existing .config file to work with the new kernel. We could require this if we wanted to use an older kernel’s config file with a newer one. Let’s run make oldconfig on our running kernel’s config file:

$ gzip -dc /proc/config.gz > .config
$ make oldconfig
* Restart config...
* General setup
Compile also drivers which will not load (COMPILE_TEST) [N/y/?] n
Local version - append to kernel release (LOCALVERSION) [] 
uselib syscall (USELIB) [N/y/?] n
Auditing support (AUDIT) [N/y/?] n
Core Scheduling for SMT (SCHED_CORE) [N/y/?] (NEW) 

We extracted the compressed kernel config found at /proc/config.gz with gzip, using the -c flag to write to stdout. Now we can see a menu similar to the one from make config. Here the last option has changed between kernel versions and is marked with (NEW), so we need to set its value. We don’t need to set unchanged options as they keep their original values. Also, we won’t need to answer any prompt if the old config file is completely compatible with our new kernel.

This takes care not only of new/removed options but also dependency changes. For example, it would resolve the case where CONFIG_FOO required CONFIG_BAR on an old kernel, but now it requires CONFIG_BAZ as well.

We can also use make olddefconfig to set new options to default values. We won’t be prompted for them.

6. Missing Config Options

If an option is disabled in the .config file, we’ll find lines such as CONFIG_FOO=n or # CONFIG_FOO is not set. Options whose dependencies are not satisfied are omitted altogether. Say we have a symbol DEBUG_INFO_REDUCED that requires CONFIG_DEBUG_INFODEBUG_INFO_REDUCED won’t appear in the file if it is disabled:

$ grep CONFIG_DEBUG_INFO .config 
# CONFIG_DEBUG_INFO is not set
$ grep DEBUG_INFO_REDUCED .config # No matches

Now, if we set CONFIG_DEBUG_INFO=y and run make oldconfig, we are prompted for the option mentioned above:

Compile the kernel with debug info (DEBUG_INFO) [Y/n/?] y
  Reduce debugging information (DEBUG_INFO_REDUCED) [N/y/?] (NEW) 

7. Conclusion

In this article, we went over configuring the Linux kernel – an overview of its build system and various targets in its Makefile.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.