日常玩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)