日常玩Linux最大的意义在于自己实现Linux内核新功能,并编译进Linux内核。但新手往往因为编译报错,不明其原因就放弃。本次文章简要展示Linux内核编译相关概要。
先来看涉及Linux编译过程中的几个重要文件:
文件类型 | 说明 |
Makefile | 顶层Makefile文件 |
.config | 内核配置文件 |
arch/$(ARCH)/Makefile | 机器体系相关 |
scripts/Makefile.* | 所有内核Makefile共用规则 |
kbuild Makefiles | 其他Makefile文件 |
上述文件可以先做简单了解,后续有机会详细展开,下面看一些关于Linux内核构建的make命令:
- make mrproper: 检查.o文件及文件依赖关系的正确性
- make clean: 清除旧版本的目标文件
- make menuconfig: 配置内核并生成配置文件
- make bzImage: 编译并用gzip压缩1M以上的内核
- make modules: 编译模块
- make modules_install: 安装模块
- make install 安装内核
需要特别注意的是编译过程中主要是make bzImage与make modules,也可以直接用make,不带任何参数完成这两步的构建过程。两者主要构建两个主要的文件:vmlinux(内核镜像可执行文件)和模块文件。
如顶层Makefile中的构建语句:
......
vmlinux: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
vmlinux: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
vmlinux: __KEEPMAKEFILEO__C.o $(KBUILD_LDS) modpost
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux
......
根据Makefile中语句,打开如下scripts/Makefile.vmlinux,可以看到有调用link-vmlinux.sh,调用脚本 scripts/link-vmlinux.sh 的主要目的是把所有的 build-in.0链接成一个静态可执行文件vmlinux,和生成 System.map。
这里要注意此时生成的vmlinux是直接编译出来的原生未经过压缩,可直接用于调试的内核镜像文件。这里的System.map是用来记录Linux内核的符号信息,当Linux内核在运行出错时,会通过System.map进行解析,查到发生错误的地址对应的函数、变量名等,系统正常启动时不会读这个符号表,主要作用是出错时便于调试。
......
targets += vmlinux
vmlinux: scripts/link-vmlinux.sh __KEEPMAKEFILEO__B.o $(KBUILD_LDS) FORCE
+$(call if_changed_dep,link_vmlinux)
......
写本文时,顺便在Ubuntu 20.04上升级了一下Linux内核(5.19.8->6.1.1),安装如下步骤可以丝滑地更新Linux内核版本(前提是配置好Ubuntu编译Linux内核的环境)
- 下载Linux-6.1.1源码,并查看当前Linux内核版本
(https://mirrors.edge.kernel.org/pub/linux/kernel/)
- 进入源码的根目录下(根Makefile所在路径)
- make menuconfig
- make bzlmage
- make modules
- make INSTALL_MOD_STRIP=1 modules_install
(INSTALL_MOD_SRIP:删除跳过调试信息和符号表等不必要的信息,减少文件大小,减少磁盘占用,为可选项)
- make install; reboot
- 查看内核版本(uname -r)