1. 项目概述为什么要在树莓派上折腾内核编译给树莓派编译一个新内核这听起来像是资深玩家才会去碰的“高级操作”离普通用户很远。但如果你已经点开了这篇文章大概率是遇到了某个驱动不兼容、需要某个新内核特性或者像我一样纯粹是想把手上的树莓派“榨干”最后一滴性能并完全掌控它。这不是一个简单的apt upgrade就能搞定的事情而是一个从源码开始亲手构建系统核心的过程。简单来说树莓派官方提供的系统镜像如 Raspberry Pi OS已经预编译好了内核开箱即用。但官方内核为了兼容性通常比较“保守”不会启用所有最新的优化和驱动模块。自己编译内核意味着你可以启用官方未开启的硬件特性或驱动比如你想用最新的摄像头模块、特定的USB网卡或者内核里某个实验性的文件系统。进行深度定制与优化剔除掉你用不到的驱动和功能让内核更精简启动更快占用内存更少。学习与调试这是理解 Linux 内核工作方式、学习系统底层知识的绝佳实践。当系统出现深层次问题时一个自己编译的、带调试信息的内核是无可替代的。跟进最新安全补丁与特性不必等待官方镜像更新你可以随时合并最新的稳定分支代码第一时间用上修复和优化。这个过程涉及获取源码、配置选项、交叉编译、安装替换等多个环节每一步都有不少细节。我最近因为需要在树莓派 4B 上使用一个较新的无线网卡驱动官方内核版本不够于是完整走了一遍流程。下面就把这次从准备到成功的完整经验包括踩过的坑和总结的技巧毫无保留地分享出来。2. 编译前的核心准备工具链与源码动手编译前准备工作至关重要。这里有两个主流选择直接在树莓派本机上编译或者在一台性能更强的x86电脑上进行交叉编译。我强烈推荐交叉编译。在树莓派上编译一个完整内核即使对树莓派 4B 或 5 来说也可能需要数小时而在一台普通的台式机上通常只需要十几到几十分钟。2.1 选择并搭建交叉编译环境交叉编译简单说就是在A机器如你的x86电脑上生成能在B机器ARM架构的树莓派上运行的代码。我们需要对应的“交叉编译工具链”。方案选择使用官方推荐的工具链树莓派基金会维护了一个预构建的工具链兼容性好。使用发行版包管理器安装例如在 Ubuntu/Debian 上安装gcc-aarch64-linux-gnu等包。这种方式方便但版本可能不是最新的。我选择的是第一种为了获得最好的兼容性。实操步骤在Ubuntu 22.04 LTS宿主机上# 1. 安装必要的依赖 sudo apt update sudo apt install -y git bc bison flex libssl-dev make libc6-dev libncurses5-dev crossbuild-essential-arm64 # 2. 创建工作目录并克隆官方工具链 mkdir -p ~/raspberrypi cd ~/raspberrypi git clone https://github.com/raspberrypi/tools.git克隆下来的tools目录里有多个工具链。对于 64 位系统如 Raspberry Pi OS 64-bit我们使用aarch64版本。为了方便将其路径加入环境变量# 3. 将工具链路径添加到环境变量临时仅当前终端有效 export PATH$PATH:~/raspberrypi/tools/arm-bcm2708/gcc-linaro-aarch64-linux-gnu-raspbian-x64/bin # 验证工具链是否可用 aarch64-linux-gnu-gcc --version如果能看到 GCC 的版本信息说明工具链就绪。注意如果你希望每次打开终端都有效可以将export那一行添加到你的~/.bashrc文件末尾。但为了避免污染全局环境我更喜欢在编译时临时指定。2.2 获取正确版本的内核源码内核源码是核心。树莓派的内核源码仓库在 GitHub 上。# 进入工作目录 cd ~/raspberrypi # 克隆内核源码仓库这个仓库很大需要耐心 git clone --depth1 https://github.com/raspberrypi/linux.git--depth1参数表示只克隆最近一次提交节省时间和空间。对于编译特定版本来说足够了。接下来是关键一步切换到你需要的内核分支或标签。树莓派内核仓库有几个主要分支rpi-5.10.yrpi-5.15.yrpi-6.1.y等这些是长期支持LTS版本的分支以树莓派前缀命名包含了针对树莓派的特定补丁最稳定最推荐。raspberrypi-kernel_1.20250205等这是官方镜像使用的内核版本标签与发布的镜像完全一致。你可以通过git branch -a查看所有远程分支。假设我们想编译与当前最新 Raspberry Pi OS 镜像同步的内核可以先查看树莓派版本信息# 在树莓派上执行 uname -r假设输出是6.1.21-v8。那么我们可以切换到对应的分支# 在宿主机上进入linux源码目录 cd ~/raspberrypi/linux # 查看远程分支找到类似 rpi-6.1.y 的分支 git branch -a | grep rpi-6.1 # 切换到该分支 git checkout rpi-6.1.y # 拉取最新代码如果你之前克隆过 git pull实操心得直接使用rpi-版本号.y分支是最省心的选择。它已经集成了树莓派的所有必要补丁如BCM2835/2711芯片支持、GPU驱动对接等。如果你去克隆主线 kernel.org 的内核需要手动打大量补丁过程极其繁琐不推荐新手尝试。3. 内核配置的艺术从基础到定制获取源码后下一步是配置。这是整个编译过程中最具技术含量、也最能体现定制化的一步。内核配置决定了哪些功能被编译进去、哪些是模块、哪些被排除。3.1 获取基础配置我们不需要从零开始配置。树莓派基金会为不同型号提供了默认配置文件。# 确定你的树莓派型号。例如树莓派 4B/400/CM4 是 bcm2711 # 对于 64 位内核我们通常使用 bcm2711_defconfig cd ~/raspberrypi/linux # 应用默认配置 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- bcm2711_defconfig这条命令做了几件事ARCHarm64指定目标架构为 ARM 64位。CROSS_COMPILEaarch64-linux-gnu-指定交叉编译工具链前缀。bcm2711_defconfig使用arch/arm64/configs/bcm2711_defconfig这个默认配置文件作为起点。执行后会在源码根目录生成一个.config文件这就是我们后续定制的基础。3.2 进入图形化配置界面推荐面对上千个配置项手动编辑.config文件是不现实的。内核提供了友好的图形化配置工具。# 安装依赖如果之前没装libncurses # sudo apt install libncurses5-dev (之前已安装) # 启动图形化配置界面 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- menuconfig一个基于 ncurses 的文本图形界面会打开。你可以使用方向键导航空格键选择状态[*]编译进内核[M]编译为模块[ ]不编译/键搜索。几个关键的定制方向驱动模块如果你知道需要某个特定驱动比如我的无线网卡rtl88x2bu可以在这里搜索并启用它。路径通常在Device Drivers - Network device support - Wireless LAN。内核调试与性能分析Kernel hacking目录下有很多调试选项生产环境可以关掉以减小内核体积和提高性能。文件系统确保你使用的文件系统如ext4,btrfs,zfs等被支持。File systems下可以找到。CPU 频率调节CPU Power Management - CPU Frequency scaling里可以启用CPU_FREQ并选择适合的调速器如ondemand,conservative这对功耗和性能有影响。精简内核对于资源紧张的场合如 Zero W可以在General setup - Configure standard kernel features里禁用一些特性或者通过搜索功能将你用不到的硬件驱动如老旧ISA声卡、不用的显卡驱动全部设为[ ]。配置完成后选择 Save 然后 Exit 直到退出。注意事项menuconfig中的修改会直接更新.config文件。建议在重大修改前备份一下这个文件cp .config .config.backup。4. 编译与安装生成内核与模块配置完成后就可以开始编译了。这个过程耗时最长主要看你的电脑 CPU 核心数。4.1 启动编译过程# 使用多核编译-j 后面的数字通常是你的CPU核心数1例如8核机器可以用 -j9 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc)编译过程会输出大量信息。如果一切顺利最终你会看到内核镜像Image或Image.gz和大量模块.ko文件生成。关键输出文件路径内核镜像arch/arm64/boot/Image未压缩或arch/arm64/boot/Image.gz压缩版通常用这个。设备树二进制文件arch/arm64/boot/dts/broadcom/*.dtb 特别是你的树莓派型号对应的.dtb文件如bcm2711-rpi-4-b.dtb。内核模块散落在各个驱动目录最终会被安装到指定目录。4.2 安装模块到临时目录我们不能直接把模块安装到宿主机的系统里。需要先安装到一个临时目录然后打包复制到树莓派。# 创建一个临时目录用于存放模块 mkdir -p ~/raspberrypi/modules # 安装模块指定安装路径 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- INSTALL_MOD_PATH~/raspberrypi/modules modules_install执行后所有编译好的内核模块.ko文件以及它们的依赖关系modules.dep等文件都会被安装到~/raspberrypi/modules/lib/modules/新内核版本号目录下。记下这个新内核版本号后面会用到。4.3 准备内核文件现在我们需要把编译好的内核镜像和设备树文件准备好。# 进入工作目录 cd ~/raspberrypi # 创建一个文件夹存放要复制到树莓派的所有文件 mkdir -p firmware_new # 复制内核镜像使用压缩版以节省空间 cp linux/arch/arm64/boot/Image.gz firmware_new/kernel8.img # 注意对于32位内核文件是 kernel7l.img 或 kernel7.img64位通常是 kernel8.img # 复制设备树文件 cp linux/arch/arm64/boot/dts/broadcom/*.dtb firmware_new/ # 复制设备树叠加层如果有需要的话 cp linux/arch/arm64/boot/dts/overlays/*.dtbo firmware_new/overlays/ 2/dev/null || : # 复制设备树 blob 的配置文件 cp linux/arch/arm64/boot/dts/overlays/README firmware_new/overlays/ 2/dev/null || :5. 部署到树莓派替换与测试这是最紧张的一步因为操作不当可能导致树莓派无法启动。务必谨慎。5.1 安全备份与文件传输首先将准备好的文件从宿主机复制到树莓派。假设树莓派的IP是192.168.1.100你可以使用scp。# 从宿主机执行将文件复制到树莓派的home目录 scp -r ~/raspberrypi/firmware_new pi192.168.1.100:~/ scp -r ~/raspberrypi/modules pi192.168.1.100:~/然后通过 SSH 登录到树莓派。ssh pi192.168.1.100登录后第一件事备份当前内核# 在树莓派上执行 sudo cp -r /boot /boot.backup sudo cp -r /lib/modules /lib/modules.backup这样万一新内核启动失败我们还可以从SD卡的另一分区FAT32的/boot或通过其他方式恢复旧内核。5.2 替换内核与模块现在开始替换操作。# 1. 替换内核镜像和设备树 cd ~/firmware_new sudo cp kernel8.img /boot/ sudo cp *.dtb /boot/ sudo cp -r overlays /boot/ 2/dev/null || : # 2. 替换内核模块 cd ~/modules sudo cp -r lib/modules/* /lib/modules/5.3 更新引导配置树莓派从config.txt文件读取启动参数。我们需要确保它指向正确的新内核。# 编辑 config.txt sudo nano /boot/config.txt检查或修改以下行# 对于64位内核确保有这一行 arm_64bit1 # 指定内核文件名对应我们复制的 kernel8.img kernelkernel8.img保存并退出CtrlX 然后Y 回车。5.4 更新 initramfs如果需要如果你的系统使用了initramfs例如全盘加密或复杂的分区方案需要更新它。# 查看新内核版本号假设是 6.1.21-v8-custom ls /lib/modules # 更新该版本内核的 initramfs sudo update-initramfs -c -k 6.1.21-v8-custom5.5 重启并验证激动人心的时刻到了。sudo reboot重启后重新 SSH 登录树莓派运行uname -r如果输出是你编译的新内核版本号例如6.1.21-v8-custom那么恭喜你成功了同时检查你之前定制的功能比如新加的驱动是否正常工作# 例如检查无线网卡驱动 lsmod | grep rtl88x2bu # 或者查看内核启动信息中是否有相关模块加载 dmesg | grep -i your_driver_name6. 常见问题与排查技巧实录即使步骤清晰实际操作中还是会遇到各种问题。下面是我踩过的一些坑以及解决方法。6.1 编译阶段错误问题1make menuconfig报错提示缺少ncurses库。现象*** Unable to find the ncurses libraries or the required header files.解决确保已安装libncurses5-dev或libncursesw5-dev。sudo apt install libncurses5-dev。问题2编译过程中出现undefined reference或语法错误。现象通常出现在编译中后期提示某个函数未定义或某行代码有语法错误。排查检查工具链版本是否与内核源码匹配。太新或太旧的 GCC 可能导致问题。使用官方工具链是最稳妥的。检查是否完整拉取了源码并切换到了正确的分支。可以尝试make clean后重新开始。错误信息通常会指向某个具体的驱动文件。可以尝试在menuconfig中暂时禁用该驱动看编译是否能继续。这可能是该驱动代码与当前内核版本不兼容。问题3编译时间过长或卡住。现象编译进度缓慢或在某个点停滞。解决确认-j参数设置正确充分利用多核。检查系统内存是否充足。编译内核需要大量内存如果内存不足会使用交换分区导致极慢。确保可用内存至少 4GB推荐 8GB 以上。可以尝试先make clean然后只编译内核镜像而不编译模块make Image.gz看是否能通过以缩小问题范围。6.2 部署与启动阶段错误问题4树莓派启动失败屏幕无输出或卡在彩虹屏。这是最严重的问题意味着内核或设备树文件有问题。应急恢复将SD卡插入读卡器连接到另一台电脑。电脑会挂载SD卡的FAT32引导分区通常名为boot。用备份的旧文件覆盖新文件将kernel8.img重命名为kernel8.img.bad。将备份的boot.backup分区中的原kernel8.img或kernel7l.img复制回来。同样恢复*.dtb文件和overlays文件夹。安全弹出SD卡插回树莓派启动。原因分析与后续解决内核镜像不对确认编译的是Image.gz并正确重命名为kernel8.img64位。32位内核要用kernel7l.img。设备树不匹配确认复制的.dtb文件与你的树莓派型号完全匹配如 Pi 4B 用bcm2711-rpi-4-b.dtb。配置错误可能在内核配置中错误地禁用了关键硬件支持如CPU类型、串口控制台等。建议首次编译时在defconfig基础上只做最小改动。问题5系统能启动但某些硬件如USB、网络不工作。现象uname -r显示新内核但网卡找不到、USB口没反应。排查lsmod查看已加载的模块对比旧内核看关键驱动模块如xhci_pci,dwc2,lan78xx等是否缺失。检查dmesg输出寻找硬件初始化时的错误信息。很可能的原因在menuconfig中将某些必须的驱动编译成了模块[M]但没有将这些模块文件.ko正确复制到树莓派的/lib/modules下或者模块依赖关系未更新。解决在树莓派上检查/lib/modules/新内核版本/目录下是否有modules.dep文件。如果没有说明modules_install步骤可能有问题。可以尝试在宿主机重新执行make modules_install并确保scp复制了整个模块目录。更根本的方法是在内核配置中将这些关键的基础硬件驱动尤其是启动早期需要的直接编译进内核[*]而不是作为模块。问题6新内核版本号与模块目录不匹配。现象启动后系统可能因为找不到对应版本的模块而加载失败。解决确保你在modules_install后复制到树莓派的模块目录名称如6.1.21-v8-custom与uname -r的输出完全一致。内核版本号由.config中的CONFIG_LOCALVERSION等设置决定编译前后不要随意修改。6.3 性能与优化问题问题7编译出的内核体积过大。目标为资源有限的设备如 Pi Zero减负。优化策略在menuconfig中进入General setup - Configure standard kernel features可以禁用一些不必要的特性。在Device Drivers中大刀阔斧地移除你绝对用不到的硬件驱动如老式显卡、不存在的 RAID 卡、特定品牌的笔记本传感器等。将尽可能多的驱动设为[M]模块而不是[*]内置。这样它们只在需要时加载。使用make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- bindeb-pkg生成安装包它会自动进行一些压缩优化。问题8如何后续更新或打补丁小版本更新进入内核源码目录git pull拉取最新代码然后重新执行make编译即可。.config文件会保留通常可以直接使用。应用特定补丁如果需要应用非官方的第三方补丁如某些驱动补丁可以使用git apply patch_file命令。但需注意补丁与内核版本的兼容性。整个流程走下来从最初的生疏到后来的熟练最大的体会是耐心和备份是最重要的两个工具。每一次进入menuconfig做重大改动前备份.config每一次替换树莓派系统文件前备份整个/boot和/lib/modules。这样无论遇到什么情况你都有一条安全的退路。自己编译的内核就像为自己量身定做的系统核心那种掌控感和解决实际问题后的成就感是直接用现成镜像无法比拟的。