Linux Kernel 编译

Table of Contents

最后更新:2024-02-19

1. 相关工具及命令

内核模块相关命令:

  • modinfo:查看已加载的内核模块信息
  • rmmod:卸载已加载的内核模块
  • insmod:加载新的内核模块 .ko 文件
  • lsmod:列出当前所有已加载的内核模块
  • modprobe:加载模块,并自动加载依赖模块

2. 内核编译

内核代码下载途径:

1、从 www.kernel.org 获取各种版本的源码

2、从发行版的软件源中下载,

内核的配置信息保存在内核源码根目录的 .config 文件中。

配置内核的几种方式:

  • make config:需要每项都交互式输入 y、n 和 m(编译成内核模块),反正我是从来不这样去配置内核的
  • make menuconfig:终端界面的配置
  • make xconfig:Qt 界面配置
  • make gconfig:GTK 界面配置
  • make defconfig:默认配置,据说是 Linus 的默认配置,但配置项比较随意
  • make oldconfig:载入 .config 中的配置,如果当前内核有新的配置选项没记录在 .config 时,会用交互式来手动设置,一般给内核源码更新了补丁后,就需要用到

我常用 make menuconfig,在 menuconfig 配置界面中,可以按“/”键,对配置项进行字符串查找。

编译内核

make oldconfig # 在编译以前,最好先运行 make oldconfig 验证一下配置文件 .config 的正确性,如无错误,再编译
make menuconfig # 配置内核选项
make -j3 # 编译内核源码,-j 参数指定多线程编译

2.1. 交叉编译

ARCH 参数指定目标体系架构类型,如:ARCH=i386、ARCH=arm。

如果需要专用的编译器,指定 CROSS_COMPILE 参数,如下,使用 arm-linux-gnueabi 来编译:

CROSS_COMPILE=arm-linux-gnueabi-

3. 安装内核

方法 1:

sudo make modules_install # 安装内核模块
sudo make install # 安装内核相关文件
grub2-mkconfig # 更新 Grub 内容,不写入文件,只是检查下配置是否有问题
grub2-mkconfig -o /boot/grub/grub.cfg # 如果检查没问题,就覆盖掉旧的配置

方法 2,将内核打包成 RPM,方便管理:

make rpm-pkg

生成的 .rpm 包在 ~/rpmbuild/RPMS/ 中,直接用 rpm/dnf 命令安装即可。

如果是 Debian 系列,在编译时指定 deb-pkg,编译完后自动生成相关的 .deb 包:

make -j16 deb-pkg

更多高级配置,可见 Documentation/kbuild 下的文档,或者运行 make help 命令获得编译帮助

3.1. 卸载内核

如果是手工安装的新内核(make install),就不能依靠包管理器,也需要手动去卸载,下面以 openSUSE 上卸载 Linux 6.1 为例:

sudo find /boot -name '*6.1*'   # 先确保列出的文件都是需要删除的
sudo find /boot -name '*6.1*' -exec rm -rf {} \; # 没问题再删除
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

4. 一些配置项

Kernel .config support:

在 General setup 中找到,配置该项的内核,会将配置文件保存到 /proc/config.gz 中,方便了解当前运行中的内核配置情况,以及复用配置文件,建议开启。

5. 升级内核源码

如果是从 kernel.org 上下载的源码,也能通过官网下载增量补丁,但是注意不能跨版本,比如当前源码树是 4.9.10,要升级到 4.9.13,就要先从 4.9.10 升级到 4.9.11,再从 4.9.11 升级到 4.9.12,最后才能升级到 4.9.13。

升级补丁从 kernel.org 下载,比如 4.x 内核的补丁在 https://www.kernel.org/pub/linux/kernel/v4.x/incr/ 找到。

现在,下载增加补丁:

patch-4.9.10-11.xz
patch-4.9.11-12.xz
patch-4.9.12-13.xz

接下来进入 4.9.10 源码目录,并打补丁:

cd linux-4.9.10
xzcat /tmp/patch-4.9.10-11.xz | patch -p1
xzcat /tmp/patch-4.9.10-12.xz | patch -p1
xzcat /tmp/patch-4.9.10-13.xz | patch -p1

源码升级完毕后,执行以下命令确认是否升级到 4.9.13:

$ head -4 Makefile
VERSION = 4
PATCHLEVEL = 9
SUBLEVEL = 13
EXTRAVERSION =

从 SUBLEVEL 可见升级成功。在更新内核源码后编译之前,记得执行 make oldconfig 更新并验证配置文件。

在官网上,能看到每个版本内核源码下载以外的,“patch”和“inc.patch”两种链接,“patch”这个链接的补丁是应用在主版本的内核源码中的,例如下载了 linux-5.10.tar.gz,patch-5.10.209.xz 就是应用在这个源码目录上的。

6. 编译某个模块

一般忘记编译某个独立的内核模块,或是该模块有 bug,才需要重新编译。

比如,上次遇到 rtl8192ce 驱动频繁断线的 bug,关注几日内核进展后,发现在 4.9.10 中得到修复(https://bugzilla.redhat.com/show_bug.cgi?id=1391987#c26 ),但是 Fedora 仓库里最新的内核还没有到 4.9.10(已经到 4.9.9了,还差一点点),从 Fedora Update System(https://bodhi.fedoraproject.org/updates/FEDORA-2017-0054c7b1f0 )看到 4.9.10 还有 3 个问题没解决,所以应该还需要一段时间才会释放出 4.9.10 的内核更新,由于平时在家需要连 Wifi,极不方便,所以需要手动来解决。

从 kernel.org 上下载 4.9.10 的源码,然后单独编译 rtl8192ce 模块来临时用着,直到 4.9.10 的更新出现为止。

找到 rtl8192ce 模块的路径:

find ./ -name 'rtl8192ce*'

位于 drivers/net/wireless/realtek/rtlwifi/rtl8192ce,进入该目录,然后编译模块:

cd ./drivers/net/wireless/realtek/rtlwifi/rtl8192ce
sudo make -C /lib/modules/4.9.9-200.fc25.x86_64/build M=`pwd` modules

参数 M 表示编译内核模块;

-C 表示先切换到指定目录去,再执行 make 操作

成功后安装模块:

sudo make -C /lib/modules/4.9.9-200.fc25.x86_64/build M=`pwd` modules_install

安装后 .ko 文件在 /lib/modules/4.9.9-200.fc25.x86_64/extra 目录中。先从内存中移除旧的模块:

sudo rmmod rtl8192ce

然后再挂载新的模块:

sudo insmod /lib/modules/4.9.9-200.fc25.x86_64/extra/rtl8192ce.ko