Linux Kernel 编译
最后更新:2024-02-19
1. 相关工具及命令
- GCC:部分内核代码依赖 GCC
- util-linux:提供了一些基本的实用工具,如挂载硬盘、弹出光驱等等,下载地址:https://www.kernel.org/pub/linux/utils/util-linux/
- module-init-tools:提供了内核模块挂载、卸载和列出等工具,下载地址:https://www.kernel.org/pub/linux/utils/kernel/module-init-tools/
内核模块相关命令:
- 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