我需要创建一个自设的内核

英文版本由 RalphAngenendt 创建。现在由 AlanBartlettAkemiYagi 维护。

为 CentOS 创建自设的内核有两个方法:第一个是利用加了自设选项的 CentOS 源代码;另一个是利用来自 Linux Kernel Archive的主流内核源代码。

这份教学文档教授如何利用你自己的选项或改动,配合 CentOS 的源代码来创建一个内核。它主要是针对 CentOS-7 而写成。

(如果你希望创建一个主流的内核,切勿依照 How To Compile A Kernel 内的指引。这个网站不被认可,因为它不安全地教导以 root 创建内核,方法本身就有毛病。详细理由请参阅 Building Source RPM as non-root under CentOS。创建主流内核的一个良好参考指南是 Linux Kernel in a Nutshell 这本书。)

这些行动都只供你个人使用。开发小组并不支持自设的内核,因为他们不能控制你的编译环境、选择项目等。如果你选择创建自设的内核,当有安全性更新、新发行、或任何须要进行维护的情况出现,你要独力肩负起这个责任。


注:如果想看一个自设内核的实例,请下载 centosplus 内核的 srpm 组件。譬如说,你可在 这里 找到属于 CentOS-7 及在 这里 找到属于 CentOS-6 的组件 。

1. 编译前的准备

要成功地创建一个内核,你须要安装下列组件:

当上述 yum 指令执行时,请留意有否组件被排除。假若 yum 配置文件内存有任何内核及相关组件的 exclude 项目,它们亦必须被删除。纵使 CentOS 计划普遍不鼓励采用这类 exclude 规限,某些发行商不允许用户自行修改的内核在他们的环境上运行。有关这个主题的详尽数据,请参阅 不健全的虚拟服务器这篇 CentOS wiki 文章的第三节。请注意,为不想损失的内容创建最新及已测试的备份永远是个明智的做法。

如果你想加入任何内核的修正,请于现在复制它们到你的 ~/rpmbuild/SOURCES/ 目录内。

2. 设置内核

如果你不打算修改发行内核的配置文件,你可以忽略这部份(CentOS-7),又或许你只需进行最后一步(CentOS-6):

][user@host] $ cp ~/rpmbuild/BUILD/kernel-*/linux-*/configs/* ~/rpmbuild/SOURCES/

请进到 ~/rpmbuild/BUILD/kernel-*/linux-*/ 目录,然后选择复制 configs/ 目录内的配置文件或 /boot/ 目录内的现有内核配置文件,并命名为 .config

请参考下面的样例:

[user@host]$ cd ~/rpmbuild/BUILD/kernel-*/linux-*/

你可选用 —

[user@host]$ cp configs/kernel-3.10.0-`uname -m`.config .config

(在 CentOS-6 以 3.10.0 替换 2.6.32。) — 或 —

[user@host]$ cp /boot/config-`uname -r` .config

注:包围 uname-muname-r 的字符是反引号,不是引号。

首先执行 make oldconfig。现在你应该执行 make menuconfigmake gconfigmake xconfig 来自定内核的设置。当你完成后,请记得存储你的改动。

如果你安装了整个内核的源代码来创建一个内核模块,你应该在这里停手。请你现在便参考「创建你自己的内核模块」教学文档。

接著,在你将设定档复制回 configs/ 目录前,请先将注释了的硬件平台(相等于 uname -i 指令的输出)的一行加在设定档的顶部。在 64 位元架构上这是 x86_64(在 CentOS-6 的 32 位元架构上这会是 i386)。这个字串必须以 # 符号来注释,而且必需是档案的头一行。请留意 # 符号与硬件平台的描述中间必须有一个空格。

请在 .config 文件的顶部加入以下一行:

# x86_64

在 CentOS-6 上亦可以是:

# i386

现在将 .config 档复制回 configs/ 目录内。这基本上与先前的复制指令刚刚相反:

[user@host]$ cp .config configs/kernel-3.10.0-`uname -m`.config

注:包围 uname-m 的字符是反引号,不是引号。

最后一步就是将 configs/ 目录内的所有内容复制到 ~/rpmbuild/SOURCES/ 目录内。

[user@host]$ cp configs/* ~/rpmbuild/SOURCES

3. 内核的 ABI

CentOS 内核的其中一个特色就是它的应用程序二进制界面(ABI)会在整个产品生效期内保持一样。ABI 维持不变的好处,就是外置的内核模块在创建时不必与内核版本挂钩 —— 因此它们不必在新内核发行时被重新创建。这是追踪 ABI 内核模块组件的基础 —— 它们可以提供更新的驱动程序及其它文件系统等支持。

为了维系 ABI 的一致性,原先的内核的 ABI 会被记录及存储在一个文件内。这个文件会在创建每个新内核时用来检查 kABI。如果新的内核被设置或修改至一个地步令它的 ABI 与先前的有差别,编译将会失败,并且会有信息表示 kABI 的一致性已被破坏。这时,内核创建者有两个选择:(一)重新设置新的内核,让它的 ABI 与原有的能互相吻合,因而可继续享受一致 ABI 所提供的好处;(二)在创建的过程中停止检查 kABI。在这两个选择之间,前者较为可取,但有时后者是唯一可行的方法。

要停止检查内核的 ABI,你只须在 rpmbuild 命令行上加入一个选项及它的参数:

--without kabichk

4. 更改内核的 spec 文件

这个部份所提及的行数只对应现有 CentOS 内核的 spec 文件。

现在请更改内核的 spec 文件。

[user@host]$ cd ~/rpmbuild/SPECS
[user@host SPECS]$ cp kernel.spec kernel.spec.distro
[user@host SPECS]$ vi kernel.spec

在第 8 行,buildid 的定义本来是一个注释。(CentOS-6 是在第 18 行)

它必须被取消注释及赋予一个数值,好避免与你现时安装了的内核互相抵触。这将这行更改如下列样子般:

%define buildid .your_identifier

"%" 与 "define" 这个字之间不可以有空格。

假若你有任何修正,你必须在两个地方提及它们。如果你没有任何修正,请跳至「修正部份到此为止」后面那一行。

首先,找寻含有 # empty final patch to facilitate testing of kernel patches 的那一行。(在 CentOS-6 请找寻含有 # empty final patch file to facilitate testing of kernel patches 的那一行)。紧接著该行,请以 40000 这数目开始加入你的申报,以免你的修正与 RHEL/CentOS 的内核修正产生冲突。例如:

Patch40000: my-custom-kernel.patch

接著,找寻含有 ApplyOptionalPatch linux-kernel-test.patch 的那一行。在该行之上加入一行来应用你的修正。例如:

ApplyOptionalPatch my-custom-kernel.patch

修正部份到此为止。

在 CentOS-6 之下,找寻含有 # Drop some necessary files from the source dir into the buildroot 的那一行。请把后随的那一行:

cp $RPM_SOURCE_DIR/config-* .

改为

cp $RPM_SOURCE_DIR/kernel-*.config .

在 CentOS-6 之下,请找寻以下一行并把它改为注释:

make -f %{SOURCE20} VERSION=%{version} configs

5. 编译新内核

开始编译:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` kernel.spec 2> build-err.log | tee build-out.log

注:包围 uname-m 的字符是反引号,不是引号。

你可以通过 --with 及/或 --without 这些选项及相关的引数在 rpmbuild 指令内加入一些有用的选项。值得留意的主要选项包括:

--with baseonly
--without up
--without debug
--without debuginfo
--without fips
--without kabichk

举个例说,单要创建基本内核组件,请使用:

--with baseonly --without debug --without debuginfo

6. 安装新内核

当编译完成后,你的自设内核的 rpm 文件可以在用户的 ~/rpmbuild/RPMS/`uname -m`/ 目录内找到。请以 root 身份,利用 yum 指令或 rpm 指令作行安装。

注:包围 uname-muname-r 的字符是反引号,不是引号。

譬如说,以 root 的身份(见 如何成为 root 用户)进入 ~user/rpmbuild/RPMS/`uname -m`/ 目录。然后执行以下指令:

若要安装所有 kernel-* 组件,执行:

[root@host]# yum localinstall kernel-*.rpm

你亦可采用 rpm 指令:

[root@host]# rpm -ivh kernel-*.rpm

6.1. 利用 yum 指令

要安装所有 kernel-* 组件,请以 root 身份执行 yum localinstall kernel-*.rpm 这个指令。

6.2. 利用 rpm 指令

当你利用 rpm 指令来安装 kernel-* 组件时,请留意 kernel 及 kernel-devel 必须通过 rpm -ivh 这个指令来安装,而不是更新。注:如果你创建了一个内核比现时安装的版本还要旧,你还须要在 rpm 指令里使用 --oldpackage 这个选项。

无论如何,切勿使用 rpm -Uvh 这个指令来安装你的 kernel 组件,因为这样做会更新(取替)你现时安装了的版本。假如你自设的内核有问题,你将会不能返回原先能正常运作的版本。

kernel 及 kernel-devel 以外的组件都必须利用 rpm -Uvh 这个指令来安装(更新)。请留意 -i(安装)及 -U(更新)这两个选项之间分别。

Translation of revision 197

zh/HowTos/Custom Kernel (last edited 2018-05-03 07:43:08 by TimothyLee)