3. U-Boot 配置与编译:从 menuconfig 到生成镜像

好,到了真正动手的环节了。配置和编译 U-Boot,说白了就是告诉它「你要跑在哪个板子上,用哪些功能」。这一步要是搞错了,后面调试起来会非常痛苦。我刚开始移植 U-Boot 的时候,就因为交叉编译链没选对,折腾了整整一个下午。

3.1 使用 menuconfig 进行配置

U-Boot 的配置系统继承自 Linux 内核,核心就是 make menuconfig。它会读取 arch/../Kconfig 和各个子目录下的 Kconfig 文件,生成一个图形化的配置菜单。

核心流程:

  1. 选择默认配置:make _defconfig 加载板级默认配置
  2. 定制功能:make menuconfig 打开图形界面调整
  3. 保存配置:自动写入 .config 文件

我个人习惯先跑一遍 make xxx_defconfig,再用 make menuconfig 微调。为什么?因为默认配置已经包含了该板子的基础参数——DDR 时序、时钟频率、外设地址。你从头配一遍,很容易漏掉某个关键选项。

小技巧: 配置完成后,用 make savedefconfig 生成精简的 defconfig 文件。这样下次移植到类似板子时,直接拿这个文件改,比重新配一遍快得多。

3.2 交叉编译工具链设置

交叉编译,就是在 PC 上编译出能在 ARM/RISC-V 等目标板上运行的代码。工具链选不对,编译出来的 U-Boot 根本跑不起来。

设置方法有两种:

方式 命令/变量 适用场景
环境变量 export CROSS_COMPILE=arm-linux-gnueabihf- 临时使用,适合测试
Make 参数 make CROSS_COMPILE=arm-linux-gnueabihf- 每次编译都要带,适合脚本
写入 Makefile 在 config.mk 中固定设置 长期项目,团队统一

我曾经踩过的坑: 用 arm-none-eabi- 工具链编译 U-Boot,结果链接阶段报错。后来才发现,U-Boot 需要 arm-linux-gnueabihf- 这种带 Linux 支持的工具链,因为 U-Boot 的某些库依赖 Linux 的 ABI。嗯,这个细节很容易被忽略。

验证工具链是否可用:

arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-objdump --version

如果提示「command not found」,说明工具链没装或者没加到 PATH 里。我建议把工具链路径写到 ~/.bashrc 里,省得每次开终端都要 export 一遍。

3.3 编译生成 u-boot.bin 与 u-boot.srec

配置好之后,直接 make 就行。但编译产物有好几种,你得知道它们分别干什么用。

产物 格式 用途
u-boot ELF 调试用,包含符号表
u-boot.bin 纯二进制 烧录到 SPI Flash / SD 卡
u-boot.srec S-Record (文本) 通过串口下载到 RAM 运行
u-boot.img U-Boot 镜像 + 头部 包含校验信息,用于启动链

你想想看,u-boot.bin 是裸的二进制,烧到 Flash 里直接从 0x0 地址执行。u-boot.srec 是文本格式,每行都带地址信息,适合用 Xmodem 协议通过串口下载到任意地址。我在调试早期启动阶段时,经常用 u-boot.srec 直接下载到 DDR 里跑,省去反复擦写 Flash 的时间。

编译命令速查:

# 完整编译
make CROSS_COMPILE=arm-linux-gnueabihf- -j4

# 只生成 u-boot.bin
make CROSS_COMPILE=arm-linux-gnueabihf- u-boot.bin

# 只生成 u-boot.srec
make CROSS_COMPILE=arm-linux-gnueabihf- u-boot.srec

3.4 知识体系:配置与编译流程

下面这张图,是我画给团队新人的。它把整个配置编译流程串起来了,你一看就明白。

U-Boot 配置与编译流程 U-Boot 配置与编译流程 U-Boot 源码树 make xxx_defconfig make menuconfig .config 配置文件 make CROSS_COMPILE=... u-boot.bin u-boot.srec 关键点 • 交叉编译链必须带 Linux ABI • .config 是编译的唯一依据 • 产物格式决定烧录方式 避坑提示 • 不要用 arm-none-eabi- • 先 defconfig 再 menuconfig

3.5 常见问题与避坑

  • 编译报错:undefined reference to `xxx' —— 大概率是工具链版本太老,或者 CROSS_COMPILE 前缀写错了。检查一下 arm-linux-gnueabihf-gcc -v 的输出。
  • menuconfig 界面空白 —— 缺少 ncurses 库。Ubuntu 下 sudo apt install libncurses5-dev 即可解决。
  • u-boot.bin 烧进去跑不起来 —— 检查一下 CONFIG_SYS_TEXT_BASE 是否和板子的启动地址匹配。我遇到过一块板子,DDR 起始地址是 0x80000000,但默认配置写的是 0x40000000,结果当然跑不起来。

我的调试习惯: 编译完成后,先用 arm-linux-gnueabihf-objdump -d u-boot 反汇编,看看入口地址对不对。如果 _start 的地址和 CONFIG_SYS_TEXT_BASE 不一致,那肯定是链接脚本出了问题。

嗯,配置和编译这部分,说白了就是三板斧:选配置、设工具链、编译。但每一板斧都有细节,细节决定成败。你按这个流程走一遍,应该不会出大问题。