3. U-Boot源码获取与目录结构
说实话,很多初学者在U-Boot移植上栽跟头,十有八九是编译环境没搞对。我见过太多人花了两天时间配置环境,结果make的时候报一堆莫名其妙的错误——其实说白了,就是工具链版本不匹配或者路径没配好。
这一章咱们就把编译环境彻底捋清楚。你跟着我的步骤走,保证一次过。
3.1 交叉编译工具链的选择与安装
先回答一个关键问题:为什么非得用交叉编译工具链?
你想想看,U-Boot是要跑在ARM、RISC-V或者MIPS这类嵌入式处理器上的。你的开发机是x86架构,编译出来的二进制文件x86 CPU能直接跑,但ARM CPU读不懂。交叉编译器的作用,就是在x86机器上生成目标架构的机器码。
我个人习惯用Linaro提供的GCC工具链,稳定、社区支持好。当然你也可以用芯片厂商提供的SDK里的工具链,比如ST、NXP、TI都有自己的版本。但如果你刚开始学,我建议先用Linaro的,通用性强,踩坑少。
3.1.1 下载与解压
以ARM64(aarch64)为例,我常用的版本是gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu。下载后解压到/opt/toolchains目录:
sudo mkdir -p /opt/toolchains
sudo tar xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz -C /opt/toolchains/
解压完成后,检查一下目录结构:
ls /opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/
你应该能看到aarch64-none-linux-gnu-gcc、aarch64-none-linux-gnu-ld等可执行文件。嗯,看到这些就说明工具链本体没问题。
make CROSS_COMPILE=gcc,结果编译出来的U-Boot在目标板上跑不起来——因为那是x86的机器码。交叉编译器的前缀一定要带目标架构标识。
3.1.2 验证工具链
验证工具链能不能正常工作,跑一行代码就够了:
/opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc --version
输出应该类似:
aarch64-none-linux-gnu-gcc (GCC Toolchain for Arm) 10.3.1 20210621
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
看到版本号就说明工具链安装成功了。我曾经遇到过解压后权限不对,导致gcc无法执行的情况——chmod +x一下就好,小问题。
3.2 环境变量配置
工具链装好了,但每次编译都要敲一长串路径,太烦了。我们需要把工具链路径加到PATH里,再设置CROSS_COMPILE前缀。
3.2.1 临时配置(当前终端有效)
如果你只是临时编译一次,直接在终端里export就行:
export PATH=/opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH
export CROSS_COMPILE=aarch64-none-linux-gnu-
export ARCH=arm64
注意CROSS_COMPILE后面有个短横线,这个不能漏。U-Boot的Makefile会在这个前缀后面自动拼接gcc、ld、objcopy等工具名。
3.2.2 永久配置(推荐)
我个人习惯把这些配置写到~/.bashrc里,这样每次打开终端就自动生效:
echo 'export PATH=/opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH' >> ~/.bashrc
echo 'export CROSS_COMPILE=aarch64-none-linux-gnu-' >> ~/.bashrc
echo 'export ARCH=arm64' >> ~/.bashrc
source ~/.bashrc
.bashrc里写死CROSS_COMPILE和ARCH。更好的做法是:在.bashrc里只加PATH,然后在每个项目的根目录下写一个setenv.sh脚本,编译前source一下。这样切换项目时不会串环境。
3.2.3 验证环境变量
配置完成后,用下面几条命令确认一下:
echo $PATH | grep aarch64
echo $CROSS_COMPILE
echo $ARCH
如果都能正确输出,说明环境变量已经生效了。
3.3 基础编译命令:make 与 make menuconfig
环境搭好了,咱们来编译一个实际的U-Boot。这里我用qemu_arm64_defconfig做演示,这个配置可以在QEMU模拟器上跑,不需要真实硬件。
3.3.1 获取U-Boot源码
从官方仓库克隆最新稳定版:
git clone https://github.com/u-boot/u-boot.git
cd u-boot
git checkout v2024.01
我建议用tag版本,不要直接用master分支。master分支可能包含未稳定测试的代码,我在项目中吃过这个亏——编译没问题,但跑起来就挂。
3.3.2 make menuconfig:配置内核
先加载默认配置,再进入图形化配置界面:
make qemu_arm64_defconfig
make menuconfig
make menuconfig会打开一个基于ncurses的菜单界面。你可以在里面选择要支持的驱动、文件系统、命令等。对于初学者,我建议先不要乱改,直接退出保存就行。等后面学到具体模块时,再回来调整。
核心概念: make menuconfig实际上是在编辑.config文件。这个文件决定了U-Boot最终编译哪些功能进镜像。你手动改.config也行,但用menuconfig更安全,因为它会帮你检查依赖关系。
3.3.3 make:编译
配置完成后,直接执行make:
make -j$(nproc)
-j$(nproc)表示用所有CPU核心并行编译,能大幅加快速度。我第一次编译U-Boot时不知道这个参数,单核编译等了快10分钟。后来加了-j4,两分钟就搞定了。
编译成功后,你会在当前目录下看到u-boot.bin和u-boot(ELF格式)两个文件。前者是最终的二进制镜像,可以烧写到板子上;后者带调试信息,可以用GDB调试。
3.3.4 常见编译错误与解决
我整理了几个最常见的编译错误,你遇到了可以直接对照排查:
| 错误信息 | 原因 | 解决方法 |
|---|---|---|
arm-none-linux-gnueabi-gcc: command not found |
工具链不在PATH中 | 检查export PATH是否正确 |
*** Your GCC is too old |
编译器版本低于U-Boot要求 | 升级到GCC 10.x以上 |
*** Can't find libgcc |
工具链安装不完整 | 重新解压或安装完整版工具链 |
make: *** No rule to make target 'menuconfig' |
缺少ncurses库 | sudo apt install libncurses-dev |
apt install gcc-arm-none-eabi安装工具链,结果编译U-Boot时报__aeabi_uldivmod未定义。后来查了半天才发现,系统源里的工具链版本太旧,不支持某些内建函数。从那以后,我再也不用apt装交叉编译器了,一律从Linaro官网下载。
3.4 本章知识体系
下面这张图把编译环境搭建的整个流程串起来了,你可以对照着检查自己哪一步还没做:
嗯,到这里编译环境就全部搭好了。你可以在终端里跑一遍make qemu_arm64_defconfig && make -j$(nproc),如果顺利通过,恭喜你——你已经迈出了U-Boot移植的第一步。