介绍
之前基于CentOS做了一些定制化项目,编译了多次内核,但是一直没有对RedHat给出的官方内核编译指导进行过仔细研究。之前编译内核往往是按照原版内核源码的经典编译方法来编译的,但事实上RedHat系列的发行版是有一套专门的内核编译工具的。rpmbuild,通过这个工具可以编译出debuginfo,debuginfo是crash调试用的。但是rpmbuild编译只针对RedHat系列官方发布的xxxx.src.rpm的编译,本文描述的就是这种场景。
首先要下载内核
源码包的下载地址可以从Sources.repo中找到
安装编译全家桶
如果安装了全家桶还是少包,依赖的包在PowerTools中
1 | yum groupinstall "Development Tools" |
创建工作目录
RedHat系列不推荐用root做内核编译,所以下面这个步骤建议用非root用户,但实际上用root也没啥问题
1 | mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} |
安装源码包
这一步执行后,在~/rpmbuild/BUILD下会出现解压后的src.rpm,~/rpmbuild/SPECS会出现kernel.specs文件
1 | rpm -i xxxx.src.rpm |
自定义内容
如果需要修改官方发布的源码,可以遵循这一小节的描述来做。如果不需要修改,可以直接做编译
修改.config
如果要修改.config,直接到~/rpmbuild/BUILD下找到源码目录,做需要的修改就好。按照官方说法,需要在自定义的.config的第一行添加架构信息。下面是以X86_64为例的格式,注意“#”也是必须的,“#”后面还有空格
1 | x86_64 |
同样的,官方资料还说,需要将修改后的.config保存到源码目录下方的configs目录,用类似如下命令
1 | cp .config configs/kernel-3.10.0-`uname -m`.config |
不知道上面这一步是不是必须的,没有看具体的编译脚本,既然官方这么说就按照他们资料来吧。
修改kernel.spec
如果当前内核运行的内核版本和需要编译的源码是同一个版本号,为了避免冲突,可以修改kernel.spec中的一些版本号信息。下面是CentOS7的例子,但是在CentOS8的源码包中没找到相同语句。CentOS7中,可以修改kernel.spec中下面语句的your_identifier为一个自定义的数字。
1 | define buildid .your_identifier |
如果有自定义的内核补丁,同样可以在向编译工程添加。补丁文件需要放在~/rpmbuild/BUILD目录,然后修改kernel.spec文件。找到如下语句,将 linux-kernel-test.patch改为自己的补丁文件名称
1 | ApplyOptionalPatch linux-kernel-test.patch |
编译内核
如果有修改官方发布的内核,可以用下面这个命令(如果没有修改,可以删掉target参数,不太清楚有啥影响)
1 | [user@host SPECS]$ rpmbuild -bb --target=`uname -m` kernel.spec 2> build-err.log | tee build-out.log |
上面的命令默认生成最全的rpm包,这里就有crash调试需要的debuginfor.pm。其实还有些参数可以加,用来控制生成的rpm包
1 | --with baseonly |
下面这个组合可以仅编译可运行的内核rpm包
1 | [user@host SPECS]$ rpmbuild -bb --target=`uname -m` --with baseonly --without debug --without debuginfo kernel.spec |
安装内核
批量安装源码包
1 | yum localinstall kernel-*.rpm |
还可以用rpm命令,注意不要用-Uvh,会覆盖当前运行的内核
1 | rpm -ivh kernel-*.rpm |
模块编译
Let us assume, as an example, you are applying a patch to the cifs module which is located in the ~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0-957.x86_64/fs/cifs/
directory.
Apply the patch(es) to the source file(s) as required.
Change to the root directory of the kernel source and, if this is the first time the kernel has been compiled, configure the kernel remembering to ensure that the relevant component of the kernel is set, within its configuration file (.conf), to be built as a module.
1 | cd ~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0-957.x86_64 |
- Create the files required for compiling external modules.
1 | [user@host linux-3.10.0-957.x86_64]$ make modules_prepare |
- Compile the module by specifying the relative path to the module’s Makefile and source code.
1 | [user@host linux-3.10.0-957.x86_64]$ make M=fs/cifs |
Note: The whole directory containing the module can be located anywhere. If, for example, it is in ~/mycifs
/ run the following command making sure that you are still in the root directory of the kernel source.
1 | [user@host linux-3.10.0-957.x86_64]$ make M=~/mycifs |
- Unless you have compiled this module for debugging purposes, it should now be stripped of unnecessary symbols.
1 | [user@host linux-3.10.0-957.x86_64]$ strip --strip-debug fs/cifs/cifs.ko |
- In this example, the file cifs.ko has just been created. As root, copy the .ko file to the /lib/modules/<*kernel-version*>/extra/ directory.
1 | [root@host linux-3.10.0-957.x86_64]# cp fs/cifs/cifs.ko /lib/modules/`uname -r`/extra |
- As root, run the depmod command to update the module dependency files.
1 | [root@host linux-3.10.0-957.x86_64]# depmod -a |