注意:这篇文章上次更新于636天前,文章内容可能已经过时。
This article was last updated636 days ago, the content may be outdated.
本文记录如何在 Ubuntu 24.04 系统上编译和运行 Linux kernel.
主机配置如下:
1 | ./+o+- wgxls@server |
This article documents how to compile and run the Linux kernel on Ubuntu 24.04.
Host configuration:
1 | ./+o+- wgxls@server |
下载 Linux Kernel 源码
下载 Linux Kernel 源码可以分为两种方式,一种是下载源码包,另一种是使用 Git 下载源码。
- 下载源码包
打开 Linux Kernel 官方网址: https://www.kernel.org/
点击黄色按钮,下载最新版本的源码包。

- 使用 Git 下载源码
使用 Git 下载源码会包括所有的历史版本,所以下载的内容比较大,时间也比较长。
可以从 Linux 的 GitHub 镜像仓库下载代码,地址为: https://github.com/torvalds/linux
1 | git clone https://github.com/torvalds/linux.git |
也可以从 Linux 的官方仓库下载代码,地址为: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/
从以下三个链接 clone 其中一个就可以了。

1 | git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git |
编译 Linux Kernel
安装编译工具和依赖
以下是一个包含了足够冗余的编译工具和依赖的列表,可以根据自己的需求进行调整。
当然,我也不能保证这些依赖对于你的操作系统是有用的,具体问题需要具体问AI分析。
1 | sudo apt update |
配置内核
编译内核需要用到一下常用的命令:
1 | make mrproper # 清理内核源码 |
make mrproper是 Linux 内核源码树中的一个命令,用于清理内核源码树。它的作用是删除所有生成的文件和配置文件,使源码树恢复到一个干净的状态。具体来说,make mrproper会执行以下操作:
- 删除所有编译生成的文件,包括目标文件(.o 文件)、依赖文件(.d 文件)和可执行文件。
- 删除所有配置文件,包括 .config 文件和生成的头文件(如 include/config 目录下的文件)。
- 删除一些其他生成的文件和目录,如 arch/*/boot 目录下的文件。
make clean用于清理编译过程中生成的文件。它的作用是删除所有生成的文件,但不会删除配置文件。具体来说,make clean会执行以下操作:
- 删除所有编译生成的文件,包括目标文件(.o 文件)、依赖文件(.d 文件)和可执行文件。
make menuconfig是 Linux 内核的配置工具,用于配置内核的编译选项。它提供了一个基于文本的菜单界面,可以让用户方便地选择内核的编译选项。具体来说,make menuconfig会打开一个菜单界面,用户可以在这个界面上选择内核的编译选项,然后保存配置文件。
Linux 的内核配置在 Kconfig 文件中,这些文件位于内核源码树的各个目录中。make menuconfig 会读取这些文件,然后生成一个菜单界面,用户可以在这个界面上选择内核的编译选项。用户选择完毕后,make menuconfig 会将用户的选择保存到 .config 文件中。
make xconfig 和 make gconfig 所作的事情和 make menuconfig 是一样的,只是它们提供了不同的界面。make xconfig 使用 Qt 库,make gconfig 使用 GTK 库。
在本文中,我们使用 make menuconfig 来配置内核。
make -j$(nproc)是编译内核的命令。-j选项用于指定并行编译的任务数,$(nproc)是一个 shell 命令,用于获取系统的 CPU 核心数。这样,make -j$(nproc)就会使用系统的所有 CPU 核心来编译内核。
接下来重点介绍一下 make menuconfig 的使用。
make menuconfig 需要终端有足够的 Size, 最小可以接受的尺寸是 19 行 80 列,否则会出现如下错误:
1 | wgxls@server:~/Desktop/kernel/linux$ make menuconfig |
调整好终端的大小后,重新运行 make menuconfig 即可进入配置界面。
操作规则写在了界面的上方,翻译成中文如下:
Enter: 进入子菜单
高亮的字母是快捷键
Y 是选中,N 是不选中,M 是模块化编译 (也可以使用空格键进行切换)
按两次 Esc 键退出
上下左右移动光标
/ 搜索

这里面由 [ ] 指示的选项只有 选中 和 非选中 两种状态,< > 指示的选项有 选中、非选中、模块化编译 三种状态。
首次编译我们先不作任何修改,直接退出即可。
退出时被询问是否保存配置,选择 Yes 即可。

此时,内核的配置文件 .config 就被保存了。
编译内核
直接执行 make -j$(nproc) 即可开始编译内核。
此过程需要一些时间,根据电脑的性能不同,时间也会有所差异,几分钟到几小时不等。
编译成功的内核镜像位于 arch/x86/boot/bzImage
我们可以看一下编译生成的文件大小:
1 | wgxls@server:~/Desktop/kernel/linux$ ls -lh arch/x86/boot/bzImage |
以及查bzImage的版本信息:
1 | wgxls@server:~/Desktop/kernel/linux$ file arch/x86/boot/bzImage |
这个 bzImage 和 Ubuntu /boot 目录下的 vmlinuz 是一样的,只是名字不一样。
1 | wgxls@server:~/Desktop/kernel/linux$ sudo file /boot/vmlinuz-6.8.0-49-generic |
稍后,我们会用 QEMU 来启动这个 bzImage。
踩坑一:
在编译过程中,可能会出现如下错误:
1 | make[3]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。 |
可以通过清空 SYSTEM_TRUSTED_KEYS 来解决:
重新执行 make menuconfig, 定位到如下位置
1 | -> Cryptographic API (CRYPTO [=y]) |


清空后的配置菜单显示如下:

然后保存退出,重新执行 make -j$(nproc) 即可。
踩坑二:
1 | make[3]: *** 没有规则可制作目标“debian/canonical-revoked-certs.pem”,由“certs/x509_revocation_list” 需求。 停止。 |
和上面是同样的道理,把 “debian/canonical-revoked-certs.pem” 清空即可。
位置如下:
-> Cryptographic API -> Certificates for signature checking ->

使用 Busybox 创建 initramfs
编译 Busybox
Busybox 是一个集成了一百多个 Linux 命令和工具的软件包,它可以用来创建一个最小的 Linux 系统。
Busybox 的官方网站是: https://www.busybox.net/
Busybox 的源码可以从官方网站下载,也可以使用 Git 下载。
1 | git clone git://git.busybox.net/busybox |
目前最新的版本是 1.37 , 我们把 clone 的代码切换到 1.37 版本。
1 | git checkout remotes/origin/1_37_stable -b 1_37_stable |
Busybox 的编译过程和 Linux Kernel 类似,首先需要进行配置。
1 | make menuconfig |
把 Build static binary (no shared libs) 选项选中,这样编译出来的 Busybox 就是一个静态链接的二进制文件。
它位于 Settings 下。

然后开始编译。
1 | make -j$(nproc) |
编译错误与解决方案:
1 | CC networking/tc.o |
如果你遇到了上述关于 networking/tc.c 的编译错误,可以尝试通过关闭 CONFIG_TC 来避免:

编译完成输出如下:
1 | LINK busybox_unstripped |
然后执行 make install 安装 Busybox。
1 | make install |
输出如下:
1 | ./_install//usr/sbin/ubiupdatevol -> ../../bin/busybox |
Busybox 的二进制文件位于 _install/bin/busybox。
创建 initramfs
initramfs 是一个临时的根文件系统,用于启动 Linux 内核。
首先我们创建一个目录,用于存放 initramfs 的文件。
把 Busybox 的二进制文件和 bzImage 复制到这个目录下。
1 | mkdir -p ~/Desktop/kernel/workspace/initramfs |
在 initramfs 目录下创建一个 bin 目录,并把 busybox 复制到这个目录下。
1 | mkdir -p initramfs/{bin,sbin,etc,proc,sys} |
在 initramfs 目录下创建一个 init 文件,用于启动 Linux 内核。
并给 init 文件添加可执行权限。
1 | touch initramfs/init |
init 是 Linux 内核启动时的第一个进程,它负责初始化系统,并启动其他进程。
我们将 init 的内容设置为如下:
1 |
|
接下来我们需要把 initramfs 目录打包成一个 cpio 归档文件。
这里我们编写一个 Makefile 来完成这个任务。
1 | vim Makefile |
Makefile 的内容如下:
1 |
|
Makefile 要使用 Tab 键缩进,不能使用空格。
设置完成后,workspace 目录结构如下:
workspace 目录结构:
1 | wgxls@server:~/Desktop/kernel/workspace$ tree |
然后执行 make initramfs 即可生成 initramfs.cpio 和 initramfs.img。
initramfs.cpio 和 initramfs.img 是一样的,只是 initramfs.img 是 initramfs.cpio 的压缩版本。
1 | wgxls@server:~/Desktop/kernel/workspace$ file initramfs.cpio |
使用 QEMU 启动内核
QEMU 是一个开源的虚拟机软件,可以模拟多种硬件平台,包括 x86、ARM、MIPS 等。
我们可以使用 QEMU 来启动 Linux 内核。
首先我们需要安装 QEMU。
1 | sudo apt install qemu-system-x86 |
上一节中我们已经写好了 Makefile,现在我们执行 make run 即可启动内核。
启动日志如下:
1 | [ 0.000000] Linux version 6.12.0 (root@server) (gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0, GNU ld (GNU Binutils for Ubuntu) 2.42) #3 SMP PREEMPT_DYNAMIC Fri Nov 22 12:21:34 CST 2024 |
退出 QEMU 的方法是按下
Ctrl + a然后再按下x。
我们已经看到了 “Hello, Linux Kernel!”,这表示我们的内核已经成功启动了。
并且成功启动了 init 进程。
🎉 实验成功 🎉
你已经成功编译并启动了一个 Linux 内核。开启了你的 Linux 内核之旅。
Downloading the Linux Kernel source
There are two ways to download the Linux kernel source: downloading the source tarball, or cloning it with Git.
- Download the source tarball
Open the official Linux kernel website: https://www.kernel.org/
Click the yellow button to download the latest source tarball.

- Clone the source with Git
Cloning with Git includes all historical versions, so the download is larger and takes longer.
You can clone from Linux’s GitHub mirror at: https://github.com/torvalds/linux
1 | git clone https://github.com/torvalds/linux.git |
You can also clone from the official Linux repository at: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/
Cloning from any one of the three links below is sufficient.

1 | git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git |
Compiling the Linux Kernel
Installing build tools and dependencies
The following is a list of build tools and dependencies with plenty of redundancy; adjust it to your own needs.
Of course, I can’t guarantee these dependencies will be useful for your OS — specific problems need specific AI analysis.
1 | sudo apt update |
Configuring the kernel
Compiling the kernel involves some commonly used commands:
1 | make mrproper # Clean the kernel source |
make mrproperis a command in the Linux kernel source tree used to clean the source tree. It deletes all generated files and configuration files, restoring the source tree to a clean state. Specifically,make mrproperdoes the following:
- Deletes all compilation-generated files, including object files (.o), dependency files (.d), and executables.
- Deletes all configuration files, including .config and generated headers (e.g., files under include/config).
- Deletes other generated files and directories, such as those under arch/*/boot.
make cleanis used to clean files generated during compilation. It deletes all generated files but keeps the configuration files. Specifically,make cleandoes the following:
- Deletes all compilation-generated files, including object files (.o), dependency files (.d), and executables.
make menuconfigis the kernel configuration tool, used to configure kernel build options. It provides a text-based menu interface, letting users conveniently select kernel build options. Specifically,make menuconfigopens a menu interface where users can select kernel build options and then save the configuration file.
Kernel configuration lives in Kconfig files, which are located in various directories of the kernel source tree. make menuconfig reads these files and generates a menu interface where users can select kernel build options. After the user finishes, make menuconfig saves the selections to the .config file.
make xconfig and make gconfig do the same thing as make menuconfig, just with different interfaces. make xconfig uses the Qt library, make gconfig uses the GTK library.
In this article, we use make menuconfig to configure the kernel.
make -j$(nproc)is the command to compile the kernel. The-joption specifies the number of parallel tasks, and$(nproc)is a shell command that gets the number of CPU cores. Thusmake -j$(nproc)uses all CPU cores to compile the kernel.
Next, let’s focus on using make menuconfig.
make menuconfig needs a terminal with enough size — the minimum is 19 lines by 80 columns, otherwise you’ll get the following error:
1 | wgxls@server:~/Desktop/kernel/linux$ make menuconfig |
After resizing the terminal, run make menuconfig again to enter the configuration interface.
The operation rules are written at the top of the interface; translated into Chinese they are:
Enter: enter submenu
Highlighted letters are shortcuts
Y is selected, N is not selected, M is modular compilation (you can also use the space bar to toggle)
Press Esc twice to exit
Arrow keys move the cursor
/ search

Options marked with [ ] have only two states — selected and not selected; options marked with < > have three states — selected, not selected, and modular compilation.
For the first build we won’t change anything; just exit.
When asked whether to save the configuration on exit, choose Yes.

At this point, the kernel configuration file .config is saved.
Compiling the kernel
Just run make -j$(nproc) to start compiling the kernel.
This process takes some time — from a few minutes to a few hours, depending on your machine’s performance.
The compiled kernel image is at arch/x86/boot/bzImage.
Let’s look at the size of the generated file:
1 | wgxls@server:~/Desktop/kernel/linux$ ls -lh arch/x86/boot/bzImage |
And check bzImage’s version info:
1 | wgxls@server:~/Desktop/kernel/linux$ file arch/x86/boot/bzImage |
This bzImage is the same as the vmlinuz in Ubuntu’s /boot directory — only the name differs.
1 | wgxls@server:~/Desktop/kernel/linux$ sudo file /boot/vmlinuz-6.8.0-49-generic |
Later, we’ll use QEMU to boot this bzImage.
Pitfall 1:
During compilation, you may encounter the following error:
1 | make[3]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。 |
You can fix it by clearing SYSTEM_TRUSTED_KEYS:
Run make menuconfig again and navigate to:
1 | -> Cryptographic API (CRYPTO [=y]) |


The config menu after clearing looks like this:

Then save and exit, and run make -j$(nproc) again.
Pitfall 2:
1 | make[3]: *** 没有规则可制作目标“debian/canonical-revoked-certs.pem”,由“certs/x509_revocation_list” 需求。 停止。 |
Same principle as above — clear “debian/canonical-revoked-certs.pem”.
Location:
-> Cryptographic API -> Certificates for signature checking ->

Creating an initramfs with Busybox
Compiling Busybox
Busybox is a package that bundles more than a hundred Linux commands and tools; it can be used to create a minimal Linux system.
Busybox’s official website: https://www.busybox.net/
The Busybox source can be downloaded from the official website or with Git.
1 | git clone git://git.busybox.net/busybox |
The latest version is 1.37; let’s switch our clone to version 1.37.
1 | git checkout remotes/origin/1_37_stable -b 1_37_stable |
Busybox’s build process is similar to the Linux kernel — first, configure it.
1 | make menuconfig |
Select the Build static binary (no shared libs) option, so the compiled Busybox is a statically linked binary.
It’s under Settings.

Then start compiling.
1 | make -j$(nproc) |
Compile errors and solutions:
1 | CC networking/tc.o |
If you hit the networking/tc.c compile error above, try disabling CONFIG_TC to avoid it:

The build output ends like this:
1 | LINK busybox_unstripped |
Then run make install to install Busybox.
1 | make install |
Output:
1 | ./_install//usr/sbin/ubiupdatevol -> ../../bin/busybox |
Busybox’s binary is at _install/bin/busybox.
Creating the initramfs
An initramfs is a temporary root filesystem used to boot the Linux kernel.
First, create a directory to hold the initramfs files.
Copy the Busybox binary and bzImage into this directory.
1 | mkdir -p ~/Desktop/kernel/workspace/initramfs |
Create a bin directory under initramfs and copy busybox into it.
1 | mkdir -p initramfs/{bin,sbin,etc,proc,sys} |
Create an init file under the initramfs directory for booting the Linux kernel.
Make the init file executable.
1 | touch initramfs/init |
init is the first process when the Linux kernel boots; it initializes the system and starts other processes.
Set the contents of init to:
1 |
|
Next we need to package the initramfs directory into a cpio archive.
Here we write a Makefile for this task.
1 | vim Makefile |
Makefile contents:
1 |
|
The Makefile must be indented with Tab characters, not spaces.
Once set up, the workspace directory looks like this:
workspace directory structure:
1 | wgxls@server:~/Desktop/kernel/workspace$ tree |
Then run make initramfs to generate initramfs.cpio and initramfs.img.
initramfs.cpio and initramfs.img are the same; initramfs.img is just the compressed version of initramfs.cpio.
1 | wgxls@server:~/Desktop/kernel/workspace$ file initramfs.cpio |
Booting the kernel with QEMU
QEMU is an open-source virtual machine that can emulate multiple hardware platforms, including x86, ARM, MIPS, etc.
We can use QEMU to boot the Linux kernel.
First, install QEMU.
1 | sudo apt install qemu-system-x86 |
In the previous section we already wrote the Makefile; now just run make run to boot the kernel.
Boot log:
1 | [ 0.000000] Linux version 6.12.0 (root@server) (gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0, GNU ld (GNU Binutils for Ubuntu) 2.42) #3 SMP PREEMPT_DYNAMIC Fri Nov 22 12:21:34 CST 2024 |
To exit QEMU, press
Ctrl + athenx.
We’ve seen “Hello, Linux Kernel!”, which means our kernel booted successfully.
And the init process started successfully.
🎉 Experiment successful 🎉
You have successfully compiled and booted a Linux kernel. Welcome to your Linux kernel journey.


