在 Linux 内核的编译世界里,.config 文件无疑扮演着核心角色。它就像一份详细的“建筑图纸”,决定了内核的每一个功能特性是被编译进内核内部 (=y)、编译成可动态加载的模块 (=m),还是直接被忽略掉 (=n)。那么,我们有哪些途径可以生成它呢?
生成 .config 的三种方法
1. 复用现有系统配置
如果你正在为当前使用的桌面系统编译内核,最简单直接的方法就是复制 /boot 目录下已有的配置文件。通常,你可以找到一个类似 config-6.8.0-100-generic 的文件,将其复制到内核源码根目录并重命名为 .config 即可。

2. 使用预定义配置
内核源码针对不同处理器架构和硬件平台,提供了大量预定义的配置模板。这些文件通常存放在 arch/<架构>/configs/ 目录下,例如 arch/arm64/configs/。

使用命令 make ARCH=<架构> <平台>_defconfig 即可将指定的模板复制为源码根目录下的 .config 文件。例如,对于 ARM64 架构的 Rockchip 平台,可以执行:
make ARCH=arm64 rockchip_linux_defconfig

3. 交互式菜单配置
如果你想深度定制内核功能,make menuconfig 是最经典的工具。执行该命令后,会启动一个基于文本的图形菜单界面,你可以浏览并修改所有内核选项的状态。修改完成后,选择保存即可更新 .config 文件。

交叉编译环境的参数简化
为嵌入式等非 x86 平台编译内核时,每次都要在 make 命令后带上 ARCH 和 CROSS_COMPILE 参数,既繁琐又易错。别担心,我们有几种方法来简化这个流程。
1. 写入 Shell 配置文件
将这两个变量永久添加到你的 ~/.bashrc 文件中,这样每次打开终端都会自动生效。
export ARCH=arm64
CROSS_COMPILE=/home/g/workspace/tools/arm-gnutoolchain-15.2-rel-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-

2. 创建专用构建脚本
创建一个脚本文件(如 build.sh),将固定参数封装在里面。这种方法灵活性极高,你可以在同一个源码目录中为不同平台准备不同的脚本(如 build_arm.sh、build_x86.sh),互不干扰,还能方便地添加其他常用编译选项。
#!/bin/bash
make ARCH=arm64 CROSS_COMPILE=/home/g/workspace/tools/arm-gnu-toolchain-15.2.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu- "$@"

3. 直接修改顶层 Makefile
在内核源码的顶层 Makefile 文件开头直接赋值,这样运行 make 时就不需要额外指定参数了。但要注意,这种方法会影响该源码目录的所有编译。
ARCH ?=arm64
CROSS_COMPILE ?= /home/g/workspace/tools/arm-gnu-toolchain-15.2.rell-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-

内核 make 常用目标详解
获取帮助
当你对构建系统不熟悉时,make help 是你的好帮手。它会列出所有可用的构建目标及其简要说明。

清理构建文件
clean、mrproper 和 distclean 是三个层层递进的清理目标,它们帮助你将源码树恢复到不同的“干净”状态。
make clean: 删除大部分编译生成的中间文件(如 .o 文件),但保留 .config 配置文件,方便快速重新编译。
make mrproper: 在 clean 基础上,进一步删除所有配置文件(包括 .config)和各种备份文件,让源码树回到刚解压或打补丁前的状态。
make distclean: 这是最彻底的清理,在 mrproper 的基础上,还会删除编辑器备份文件、补丁文件等,力求使源码树与官方发布的原始包一致。
日常开发中,修改代码后常用 make clean && make 来重新编译;需要彻底重新配置时,用 make mrproper;准备打包或上传源码时,使用 make distclean。
配置内核
除了前面提到的 menuconfig,还有几个常用的配置命令:
make defconfig: 为当前指定的架构生成一个默认配置。如果你没有任何现成的 .config,这是快速开始的捷径。
make oldconfig: 当你升级内核版本后,使用此命令可以基于旧的 .config 文件,以交互方式处理新增或修改的配置项,保留原有设置。
执行构建
make 或 make all: 默认的构建目标。它会编译出内核镜像(vmlinux 或 bzImage 等)以及所有被配置为模块 (=m) 的内核模块。
make vmlinux: 只编译内核镜像本身,不编译模块。
make modules: 只编译内核模块。当你只修改了某个驱动代码,想快速验证时,这个命令非常高效。
make modules_install: 将编译好的内核模块安装到系统模块目录(通常是 /lib/modules/<内核版本>/ 下),通常需要 root 权限。
make install: 将编译好的内核镜像和 System.map 等文件安装到 /boot 目录,并可能更新引导加载程序(如 GRUB)的配置。此操作通常也需要 root 权限。
内核构建中的常用变量与技巧
合理地使用一些 make 变量和选项,能让你的构建过程更高效、更清晰。
make V=1: 开启详细输出模式。编译时会打印出实际执行的每一条完整命令,是调试编译错误的利器。
make -jN: 启用并行编译。N 指定并行任务数,通常设置为 CPU 核心数的 1 到 2 倍,能显著加快编译速度,例如 make -j8。
make O=/path/to/build/dir: 将编译输出目录与源码目录分离。所有生成的文件(包括 .config)都会存放在指定目录,保持源码目录清洁,也便于管理多个不同配置的构建版本。
make C=1 或 make C=2: 调用 Sparse 工具对代码进行静态检查。C=1 只检查重新编译的文件,C=2 则检查所有文件,有助于发现潜在代码问题。
make M=path/to/external/module: 编译外部内核模块。允许你在内核源码树之外独立开发、编译自己的内核驱动模块。
Makefile 中几种赋值操作的区别
理解内核顶层 Makefile 中变量赋值的细微差别,对于调试和定制构建过程很有帮助。这部分内容也属于通用的 计算机基础 知识。
= (递归扩展赋值): 变量的值在每次被引用时才展开。如果值中包含对其他变量的引用,这些引用会递归展开,可能产生“延迟”效果。
:= (简单扩展赋值): 变量的值在定义时立即展开并固定下来。后续即使引用的变量发生变化,该变量的值也不会改变。
?= (条件赋值): 仅当变量之前没有被定义过(即使值为空)时,才进行赋值。这常用于提供默认值,避免覆盖用户通过环境变量传入的设置。
+= (追加赋值): 将值追加到变量原有内容的后面,并自动插入一个空格作为分隔。
掌握这些构建内核的基础 & 综合知识和技巧,无论是为你的桌面系统定制一个新内核,还是为嵌入式设备进行交叉编译,都能做到心中有数,游刃有余。如果你在实践中遇到其他有趣的技巧或问题,欢迎到云栈社区与更多开发者交流探讨。