Linux 内核编译
Linux版本说明
- linux-next 树: 所有准备合并到 Linux 代码库的代码首先被合并到 linux-next 树。它代表的是 Linux 内核最新也是“最不稳定”的状态。大多数 Linux 内核开发者和测试人员使用这个来提高代码质量,为 Linus Torvalds 的后续提取做准备。请谨慎使用!
- 发布候选版(RC) / 主线版: Linus 从 linux-next 树抽取代码并创建一个初始发布版本。这个初始发布版本的测试版称为 RC(发布候选Release Candidate)版本。一旦 RC 版本发布,Linus 只会接受对它的错误修复和性能退化相关的补丁。基础这些反馈,Linus 会每周发布一个 RC 内核,直到他对代码感到满意。RC 发行版本的标识是
-rc后缀,后面跟一个数字。 - 稳定版: 当 Linus 觉得最新的 RC 版本已稳定时,他会发布最终的“公开”版本。稳定发布版将会维护几周时间。像 Arch Linux 和 Fedora Linux 这样的前沿 Linux 发行版会使用此类版本。我建议你在试用 linux-next 或任何 RC 版本之前,先试一试此版本。
- LTS 版本: 每年最后一个稳定版将会再维护 几年。这通常是一个较旧的版本,但它会 会积极地维护并提供安全修复。Debian 的稳定版本会使用 Linux 内核的 LTS 版版本。
对于 Arch Linux 以及其衍生版本的用户,安装命令如下:
1 | sudo pacman -S base-devel bc coreutils cpio gettext initramfs kmod libelf ncurses pahole perl python rsync tar xz |
对于 Debian 以及其衍生版本的用户,安装命令如下:
1 | sudo apt install bc binutils bison dwarves flex gcc git gnupg2 gzip libelf-dev libncurses5-dev libssl-dev make openssl pahole perl-base rsync tar xz-utils |
对于 Fedora 以及其衍生版本的用户,安装命令如下:
1 | sudo dnf install binutils ncurses-devel \ /usr/include/{libelf.h,openssl/pkcs7.h} \ /usr/bin/{bc,bison,flex,gcc,git,gpg2,gzip,make,openssl,pahole,perl,rsync,tar,xz,zstd} |
[Linux Kernel Archives](The Linux Kernel Archives)
为了验证 Tar 文件的完整性,需要先解压它。目前,它是使用 XZ 压缩算法压缩的。使用 unxz 工具(其实就是 xz --decompress 的别名)来解压 .tar.xz 格式的压缩文件。
1 | unxz --keep linux-*.tar.xz |
指定内核配置
1 cp /boot/config-6.1.0-28-amd64 ~/kernel/linux-source-6.12.8/.config若当前内核配置文件没有在
/boot文件夹内或者/boot文件夹内未找到内核配置文件,可使用如下命令:
1 sudo zcat /proc/config.gz > /path/to/.config说明:
其中的/path/to/为下载的内核源码所在的文件夹;
若已进入下载的内核源码所在的文件夹仅输入.config即可,即:sudo cp /boot/config-$(uname -r) .config
1 sudo zcat /proc/config.gz > .config学习内核开发的目的学习如何构建 Linux 内核,那你应该这样做。
请注意,偏离你的 Linux 发行版的配置可能无法在实体硬件上“正常”工作。问题可能是特定硬件无法工作、Linux 内核无法启动等。
因此,只建议在虚拟机中使用。
可以通过查看 make help 的输出 来查看 所有 可用的选项,但我们主要关注三个 make 目标:
defconfig: 默认配置。
allmodconfig: 根据当前系统状态,尽可能地把项目构建为可加载模块(而非内建)。
tinyconfig: 极简的 Linux 内核。
由于 tinyconfig 目标只会构建少数项目,构建时间将会缩短。我个人选择它的原因主要有:检查我在代码/工具链中做的修改是否正确,以及代码是否可以编译。
在虚拟机中只进行少数选项的测试。
在为 ARM 或 RISC-V 机器构建 Linux 内核时,你可能需要 DTB(设备树的二进制文件)。使用 tinyconfig 目标将不会启用构建 DTB 的选项,你的内核很可能无法启动。可以用 QEMU 在没有任何 DTB 的情况下启动 Linux 内核。
除非你确切地知道自己在做什么,否则你应当使用 defconfig 目标。
修改配置
1 | make menuconfig # 文本界面配置工具 需要libncurses |
目标架构默认(X86_64) 启动menuconfig
1
2 make ACH=目标架构 CROSS_COMPILE=工具链前缀 defconfig
make ARCH=目标架构 menuconfig处理器类型与功能设置
1 Processor typer and features # X86 AMD Intel ARM SoC Cortex-A平台设备支持
1 Device Drivers # ARm 可能需要GPIO、SPI、I2C设备树支持(嵌入式系统)
1 Boot options --> Use a device tree to describe hardware虚拟化和模拟支持
1 Virtualization # QEMu模拟ARM64生成设备树文件(ARM和ARM64特有)
1 Device Drivers ---> OF(Open Firmware) device tree support检查配置架构
1 cat .config | grep CONFIG_ARCHX86_64
1 cat .config | grep CONFIG_X86_64ARM
1 cat .config | grep CONFIG_ARM
添加自定义内核构建标签
1 | ./scripts/config --file .config --set-str LOCALVERSION "-custom" |
修改内核显示CC version ,定位Makefile文件中CC_VERSION_TEXT
1 | CC_VERSION_TEXT = $(subst $(pound),,$(shell LC_ALL=C $(CC) --version 2>/dev/null | head -n 1)) |
编译
编译内核
1 | make -j$(nproc) |
其中的 -j 选项用于指定并行编译任务的数量。而 nproc 命令用于返回可用处理单位(包括线程)的数量。因此,-j$(nproc) 其实意味着“使用我拥有的 CPU 线程数相同数量的并行编译任务”。
2>&1 会将 STDOUT 和 STDIN 重定向到相同的文件描述符,并通过管道传输给 tee 命令,这会将输出存储在一个名为 log 的文件,并且在控制台打印出完全相同的文本。如果你在构建时遇到错误,并希望回顾日志来检查出了什么问题,这将会十分有用。遇到那种情况,你只需要简单执行 grep Error log 命令就能找到线索。
1 make -j$(nproc) 2>&1 | tee log这对大部分(99%)用户来说已经足够了。
其中的 -j 选项用于指定并行编译任务的数量。而 nproc 命令用于返回可用处理单位(包括线程)的数量。因此,-j$(nproc) 其实意味着“使用我拥有的 CPU 线程数相同数量的并行编译任务”。
2>&1 会将 STDOUT 和 STDIN 重定向到相同的文件描述符,并通过管道传输给 tee 命令,这会将输出存储在一个名为 log 的文件,并且在控制台打印出完全相同的文本。如果你在构建时遇到错误,并希望回顾日志来检查出了什么问题,这将会十分有用。遇到那种情况,你只需要简单执行 grep Error log 命令就能找到线索。
自定义 make 目标
构建 Linux 内核,或者只想构建模块,或者只想构建设备树二进制(DTB)。在这种情况下,你可以指定一个构建目标,然后
make命令只会构建指定的项目,而不会构建其他的。以下是一些构建目标:
vmlinux:纯粹的 Linux 内核。modules:可加载模块。dtbs:设备树二进制文件(主要用于 ARM 和 RISC-V 架构)。all:构建所有被标记了星号*的项目(从make help的输出中可以查看)。通常情况下,你并不需要指定构建目标,因为它们都已经在构建列表中。所列出的目标是在你只想要测试某一个构建目标,而不是其他目标时的情况。
依据你的 计算机架构,构建完成的 Linux 内核镜像(存放在
/boot目录)的名称会有所不同。对于
x86_64,Linux 内核的默认镜像名称是bzImage。因此,如果你只需要构建引导所需的 Linux 内核,你可以像下面这样设定bzImage为目标:
1
2 # 对于 x86_64
make bzImage“那么如何在我的架构上找到用来调用
make的目标名称呢?”有两种方法。要么你可以执行
make help之后查找在Architecture specific targets下,第一个前面带有星号*的选项。或者,如果你希望自动完成,你可以利用
image_name目标得到镜像的完全路径(相对路径),选择性地添加-s标志来获得有用的输出。以下是我拥有的三台电脑的输出,一台是
x86_64,另一台是AArch64,还有一台是riscv:
1
2
3
4 # x86_64
make -s image_namearch/x86/boot/bzImage### AArch64$ make -s image_namearch/arm64/boot/Image.gz
# RISC-V
make -s image_namearch/riscv/boot/Image.gz现在,要只构建 Linux 内核镜像,你可以这样进行:
1 make $(make -s image_name | awk -F '/' '{print $4}')
编译模块
1 | make modules -j$(nproc) |
安装
1 | # 安装模块 |
通过设定
INSTALL_HDR_PATH变量,你可以修改 Linux 内核头文件的安装路径。
Arch-linux
如果你尝试执行了
make install命令,可能已经注意到产生了错误。错误如下:
1 $ sudo make install INSTALL /bootCannot find LILO.要在 Arch Linux 上实际完成 Linux 内核的安装,我们需要手动复制 Linux 内核镜像文件。别担心,如果你使用的是 Arch Linux,手动操作应该是家常便饭了。
可以使用以下命令完成这个步骤:
1 sudo install -Dm644 "$(make -s image_name)" /boot/vmlinuz-<kernel_release>-<localversion>因为我编译的是 6.5.5 版本的内核,所以我将会执行下面这条命令,你可以根据你的实际情况进行适当调整:
1 sudo install -Dm644 "$(make -s image_name)" /boot/vmlinuz-6.5.5-pratham虽然不是必须的,但最好复制一份名为
System.map和.config
1 sudo cp -vf System.map /boot/System.map-<kernel_release>-<localversion>sudo cp -vf .config /boot/config-<kernel_release>-<localversion>ARM架构
安装 DTB(只针对 ARM 和 RISC-V)如果你使用的是 x86_64 架构,那么你可以跳过此步骤!
如果你针对 ARM 或者 RISC-V 构建了内核,那么在运行
make的过程中,设备树的二进制文件可能已经被编译出来了。你可以通过在arch/<machine_architecture>/boot/dts目录查找.dtb文件来确认这一点。这里提供了一个快速检查的技巧:
1
2
3
4
5
6 ### 对于 AArch32
$ find arch/arm/boot/dts -name "*.dtb" -type f | head -n 1 > /dev/null && echo "DTBs for ARM32 were built"
### 对于 AArch64
$ find arch/arm64/boot/dts -name "*.dtb" -type f | head -n 1 > /dev/null && echo "DTBs for ARM64 were built"
### 对于 RISC-V
$ find arch/riscv/boot/dts -name "*.dtb" -type f | head -n 1 > /dev/null && echo "DTBs for RISC-V were built"如果你看到出现
DTBs for <arch> were built的消息,那么你可以开始安装 DTB。这可以通过dtbs_install目标来实现。需要使用
sudo,因为它们会被安装在/boot/dtb-<kernel_release>-<localversion>中,而这个目录是由root所拥有的。
1 sudo make dtbs_install给开发者的提示: 就像安装模块一样,你可以使用
INSTALL_DTBS_PATH变量指定一个自定义的路径来安装设备树二进制文件。
内核文件编译保存
内核映像文件:bzImage或zImage
符号表文件:System.map
配置文件:.config
模块文件:/lib/modules/<kernel-version>
1 | # 打包关键文件 |
更新引导
1 | sudo update-grub # 没有update-grub 可以 |
生成初始化RAM磁盘
当你安装 Arch Linux 时,可能已经了解过
mkinitcpio这个工具。创建初始的 RAM 磁盘。首先,创建一个预设文件。向
/etc/mkinitcpio.d/linux-<localversion>.preset文件中添加以下内容,根据实际需要来替换<kernel_release>和<localversion>。
1 ALL_config="/etc/mkinitcpio.conf"ALL_kver="/boot/vmlinuz-<kernel_release>-<localversion>"PRESETS=('default' 'fallback')default_image="/boot/initramfs-<kernel_release>-<localversion>.img"fallback_options="-S autodetect"配置完成后,执行下面的命令来生成初始 RAM 磁盘:
arch
1 sudo mkinitcpio -p linux-<localversion>
debian fedora
1
2 sudo dracut
# sudo dracut --force
查看模块和内核
1 | # 内核 |
清除编译文件
1 | make clean # 清除编译产生文件,保留.config配置 |
clean:除了.config文件外,删除几乎所有其他内容。mrproper:执行了make clean的所有操作外,还会删除.config文件。distclean:除了执行make mrproper的所有操作外,还会清理任何补丁文件。
卸载
1 | # 删除内核模块 |




