内核/传统编译 - Arch Linux 中文维基

跳转到内容

# 内核/传统编译

来自 Arch Linux 中文维基
< 内核
翻译状态：

- 本文（或部分内容）译自 Kernel/Traditional compilation，最近一次同步于 2026-03-14，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

本文介绍从 kernel.org 的源代码编译自己的内核。这是一种对所有发行版均适用的传统方法。取决于你的背景，这也可能比用 ABS 工具编译内核更复杂。请考虑使用 Arch 构建系统以使重复的编译任务更加有效和安全。

## 准备

准备编译时，不需要也不建议使用 root 账号或用 sudo 等工具获取 root 权限。

### 安装核心软件包

安装 base-devel包 元软件包，这个组包含了 make包 和 gcc包 等我们需要的软件包。参考 Arch 默认内核的 PKGBUILD，同时建议安装以下软件包：xmlto包、kmod包、inetutils包, bc包、libelf包、git包、cpio包、perl包、tar包、xz包。

### 创建内核编译目录

建议创建单独的内核编译目录，本文使用 `home` 下的 `kernelbuild` 目录。

    $ mkdir ~/kernelbuild

### 获取源码

警告： systemd 需要至少 3.12 版本的内核（cgroups 支持需要 4.2 及以上的版本）。参考 `/usr/share/doc/systemd/README`。

从 https://www.kernel.org 下载源码，得到你所选的内核版本对应的 tarball (`tar.xz`) 文件。

可以在浏览器中简单地右键 `tar.xz` 链接并选择 `保存链接为` 下载；也可以通过 HTTP、TFTP、Rsync 或者 Git 的各种图形化或命令行工具下载。

注意：

- 验证下载到的任何内核 tarball 文件的 PGP 签名总是好的做法。这样可以确保它是合法的，并有助于建立信任网络。参见 kernel.org/signature。

- 对于某些版本（例如 `-rc` 版本），下载的存档和生成的目录不会严格遵循本页示例中使用的 `A.B.C` 命名，请根据你的需要进行调整。

下面例子中使用 wget包 下载 A.B.C 内核到 `~/kernelbuild` 目录:

    $ cd ~/kernelbuild
    $ wget https://cdn.kernel.org/pub/linux/kernel/vA.x/linux-A.B.C.tar.xz

在信任下载的压缩包之前，你还得验证下载的正确性。 首先抓取签名，然后用它来抓取签名密钥的指纹，然后使用指纹来获取实际的签名密钥：

    $ wget https://cdn.kernel.org/pub/linux/kernel/vA.x/linux-A.B.C.tar.sign
    $ gpg --list-packets linux-A.B.C.tar.sign | grep -i keyid | awk '{print $NF}' | xargs gpg --recv-keys

注意签名是为 `tar` 存档（即扩展名 `.tar`）生成的，而不是为下载的压缩 `.tar.xz` 文件生成的。 你需要解压后者而不解压它。 检查你是否已安装 `xz`，然后这样继续：

    $ unxz linux-A.B.C.tar.xz
    $ gpg --verify linux-A.B.C.tar.sign linux-A.B.C.tar

如果没看到"Good signature"就别继续。

如果在构建目录中没使用`wget`，就需要手动将压缩包移入其中，例如：

    $ mv /path/to/linux-A.B.C.tar.xz ~/kernelbuild/

#### 半官方内核镜像

一些 kernel.org Git 存储库的半官方镜像由其各自的维护者提供。这些通常比 kernel.org 的版本更新。

- Linus Torvalds 放在 GitHub 上的主线内核

https://github.com/torvalds/linux.git.

- Greg Kroah-Hartman 放在 GitHub 上的稳定分支

https://github.com/gregkh/linux. [1]

### 解压内核代码

- 将其解压后进入源码目录:

    $ tar -xvf linux-A.B.C.tar

为了绝对确保不发生权限错误，需要运行 chown 将文件夹的所有权转移给当前用户。

要将包含其中每个文件的文件夹的所有权转移，运行 `chown` 命令。

    $ chown -R $USER:$USER linux-A.B.C

文件夹中每个文件的所有权转移给你了，所以不会遇到任何与权限相关的错误。

为了完成准备工作，内核树需要绝对干净；不要觉得解压后源代码树是干净的。所以，切换到创建的新内核源目录，然后运行 `make mrproper` 命令：

    $ cd linux-A.B.C
    $ make mrproper

注意：`make mrproper` 的目标依赖于 `make clean` 的目标，所以没必要同时执行两者。参考[2]。

## 配置

这是自定义内核以适应计算机的精确规格的最关键步骤。内核配置在 `.config` 文件中设置，其中包括 Kernel modules 的使用情况。正确设置 `.config` 中的选项，你的计算机会获得最高的运行效率。

注意：现阶段无需使用 root 帐户或 root 权限。

参考使用下面内容可以节省时间：

- 使用 Arch 官方内核的设置(推荐)
- 生成正在运行内核的配置文件和设置（手动，适用于高级用户但不推荐）

### 导出当前内核设置

这个命令将使用默认的 Arch 内核设置为自定义内核创建一个 `.config` 文件。如果正在运行官方 Arch 内核，你可以在内核源码目录中使用以下命令：

    $ zcat /proc/config.gz > .config

也可以在 official Arch Linux kernel 中找到默认配置。

提示：

- 如果你在升级内核，一些选项可能改了或被删掉了。在这种情况下，在 #Compilation 下运行 `make` 时，它会要求你提供版本之间更改的每个配置选项的答案。要使用默认值而不用一直按Enter，请运行 `make olddefconfig`。

- modprobed-db 可用于从默认 Arch `.config` 中删除不需要的模块。获得 properly populated database 后，运行 `make LSMOD=$HOME/.config/modprobed.db localmodconfig` 从 `modprobed.db` 中删除所有不存在的模块。

警告：如果你用当前的 `.config` 文件编译内核，别忘了在新的 `.config` 中的重命名内核版本，就是"CONFIG_LOCALVERSION"这项。或者用#高级配置中列出的用户界面之一中的"General Setup > Local version - append to kernel release"更改。如果跳过这一步，就有把当前内核覆盖的风险。

### 高级配置

提示：如果不想在启动和关闭时看到很多内核输出，可以禁用相关的调试选项。

有多种方式可以协助配置内核：

注意：下面列出的工具提供每个内核功能的三个配置选项：`y` 表示启用，`n` 表示禁用，`m` 表示启用作为内核模块（必要时加载）。

- `make nconfig`: 新的命令行 ncurses 界面，用来代替 `menuconfig`。
- `make xconfig`: 用户友好的图形界面，需要安装 Qt。这是推荐的方法，尤其对于没有经验的用户，因为它更容易导航，并且还会显示每个选项的信息。
- `make gconfig`: 和 xconfig 类似的图形界面，使用 GTK.

在内核源代码目录执行选择的方法，将生成一个全新的`.config`，可选参数默认是选中的，但是如果有老内核的 `.config` 文件，这些参数不一定会被选中。

改变配置文件并保存。建议在源代码目录外备份`.config`,因为你可能需要编译多次，直到所有的选项都配置正确。如果不确定每个选项的影响，每次编译只改变少量选项。如果无法启动新构建的内核，参见这里查看必须的配置项列表。从liveCD运行`$ lspci -k #`以列出使用中的内核模块的名字。最重要的是，你必须保留 systemd 需要的 CGROUPS 支持。

从live media运行 `lspci -k #` 会列出正在使用内核模块的名称。重中之重，你必须保留cgroup支持，这是systemd的依赖。参阅 Gentoo:Kernel/Gentoo Kernel Configuration Guide 和 Gentoo:Intel#Kernel 或 Gentoo:Ryzen#Kernel（适用于 Intel 或 AMD Ryzen CPU）。

## 编译

如果希望 gcc包 根据处理器指令集进行优化， 编辑内核目录下的 `arch/x86/Makefile` (i686) 或 `arch/x86_64/Makefile` (86_64)文件：

- 查找 `Processor type and features > Processor Family` 中设置的处理器系列 `CONFIG_MK8,CONFIG_MPSC,CONFIG_MCORE2,CONFIG_MATOM,CONFIG_GENERIC_CPU`
- 将 cc 调用选项设置为 `-march=native`，例如 `cflags-$(CONFIG_MK8) += $(call cc-option,-march=native)`.

对 32bit 内核，需要编辑 `arch/x86/Makefile_32.cpu` 并设置处理器的 `-march=native`。

编译时间将从15分钟到超过一小时不等。这很大程度依赖于选择了多少选项/模块和处理器性能。详情参考 Makeflags。`.config` 配置好之后，在内核目录运行：

    $ make

提示：为了更快地编译，可以使用 `-jX` 参数运行 make 以并行编译，其中 `X` 是整数。最快的编译通常是通过使用机器中 CPU 核心的数量来实现的； 例如，对于双核处理器，运行 `make -j2`。 参阅 Makepkg#减少编译时间。

## 安装

### 安装模块

内核编译了，它的模块也随之而来。首先构建模块：

    $ make modules

警告：从这里开始，需要 root 权限执行命令，否则会失败.

编译完内核后编译模块:

    # make modules_install

这会将编译后的模块复制到 `/lib/modules/A.B.C/` 中。 这使得单独使用的各个内核的模块保持分离。

提示：如果系统需要正常 Linux 内核外的模块，需要在定制内核安装完成之后重新编译它们。Nvidia 显卡模块可以参考 NVIDIA#Custom kernel。

### 拷贝内核到 /boot 目录

注意：确保已从你的系统架构的目录复制 `bzImage` 内核文件。见下文。

内核编译过程将生成该内核的压缩 `bzImage`，如果没有，运行：

    make bzImage

必须将这个 bzImage 复制到 `/boot` 目录并重命名。只要名称带有 `vmlinuz-` 前缀，你就可以根据需要命名内核。 在下面的示例中，已安装并编译的 A.B.C 内核已被复制并重命名为 `vmlinuz-linuxAB`：

    # cp -v arch/x86/boot/bzImage /boot/vmlinuz-linuxAB

### 制作初始化内存盘

初始化内存盘，是一个在真正的根文件系统可访问之前被挂载的初始化根目录文件系统。初始化内存盘（initrd）被绑定到对应的内核，且作为内核启动过程的一部分被载入。内核将该初始化内存盘（initrd）作为两阶段启动过程的一部分挂载起来，以载入模块使得真正的文件系统可用，然后得到真正的根文件系统。初始化内存盘包含实现以上过程的目录和可执行文件的最小集合，例如用来将内核模块安装到内核的insmod工具。对桌面或服务器Linux系统来说，初始化内存盘(initrd)就是一个临时的文件系统。其生命周期短暂，仅作为到真正的根文件系统的桥梁。在没有可变存储的嵌入式系统中，初始化内存盘就是永久的根文件系统。参考 Initramfs on Wikipedia 和 mkinitcpio。

/boot 中的文件可以取任何名字。然而，为了方便区分，建议采取统一的命名规范，例如使用 `linux<major revision><minor revision>`。

如果你使用了 LILO 引导加载程序且其无法与内核设备映射器驱动连通，你可能需要先运行`modprobe dm-mod`命令。

#### 自动生成

可以复制和修改现有的 mkinitcpio preset，以便可以按照与官方内核相同的方式生成自定义内核 initramfs image。 这在重新编译内核（例如更新时）时会节省很多时间。 在下面的示例中，将为上面安装的内核A.B.C复制并修改库存 Arch 内核的预设文件。

首先，复制现有的预设文件，将其重命名为与复制 `bzImage` 时指定为 `/boot/vmlinuz-` 后缀的自定义内核的名称相匹配：

    # cp /etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linuxAB.preset

其次，编辑文件并针对自定义内核进行修改。注意 `ALL_kver=` 参数也与复制 `bzImage` 时指定的自定义内核的名称匹配：

    /etc/mkinitcpio.d/linuxAB.preset

    ...
    ALL_kver="/boot/vmlinuz-linuxAB"
    ...
    default_image="/boot/initramfs-linuxAB.img"
    ...
    fallback_image="/boot/initramfs-linuxAB-fallback.img"

最后，生成 initramfs 映像：

    # mkinitcpio -p linuxAB

#### 手动方法

不使用 preset 文件，可以用 mkinitcpio 手动生成：

    # mkinitcpio -k <kernelversion> -g /boot/initramfs-<file name>.img

- `-k` (--kernel <kernelversion>): 生成 initramfs image 的内核版本. `<kernelversion>` 需要和内核源代码目录和`/usr/lib/modules/`下的模块目录一致.
- `-g` (--generate <filename>): 要生成的 initramfs 文件。

例如，上面安装的A.B.C自定义内核的命令为：

    # mkinitcpio -k A.B.C -g /boot/initramfs-linuxAB.img

### 拷贝 System.map

`System.map` 文件并非 Linux 启动所必须的。它包含一张该次构建的内核的标识符之列表（例如函数名，变量名等等）和它们相应的地址。该“标识符到地址的映射”是用于：

- 某些进程，像 klogd, ksymoops 等
- OOPS 处理程序，当内核崩溃出错信息释放到屏幕时（例如类似于内核在某个函数中崩溃了的信息）。

提示：UEFI 分区使用 FAT32 文件系统，不支持软链接。

如果 `/boot` 支持软链接（即不是 FAT32），将 `System.map` 复制到 `/boot`, 然后创建 `/boot/System.map` 软链接到 `/boot/System.map-YourKernelName`:

    # cp System.map /boot/System.map-YourKernelName
    # ln -sf /boot/System.map-YourKernelName /boot/System.map

如果 `/boot` 是不支持软链接的 FAT32，则需要将第二条命令换成 cp 来复制文件。

完成以上所有步骤之后，你的/boot目录中应该多出以下三个文件和一个软链接：

- Kernel: `vmlinuz-YourKernelName`
- Initramfs: `Initramfs-YourKernelName.img`
- System Map: `System.map-YourKernelName`
- System.map 软链接（或者复件）

## 引导加载程序设置

在你的引导加载程序（bootloader）配置文件中为你神奇的新内核添加一个入口。范例见GRUB, LILO, GRUB2 或 Syslinux。

提示：内核源码包含一个用于自动化 LILO 安装过程的脚本：如果你正在使用其他引导加载程序，可以安全地忽略它。
分类：​

- 内核

内核/传统编译
添加话题