开发环境搭建:准备好你的Linux工作台
说实话,很多初学者拿到交叉编译任务时,第一反应是直接开干。
结果呢?装包装到一半缺依赖,编译报错说找不到头文件,折腾半天连hello world都没跑起来。
嗯,这种事我见得太多了。
所以这一章,我们先不急着写代码。先把屋子打扫干净,工具摆整齐。环境搭好了,后面的事自然顺风顺水。
用哪个Linux发行版?
我个人习惯用 Ubuntu,尤其是20.04 LTS或22.04 LTS版本。
为什么?
包管理成熟,社区活跃,遇到问题一搜就有答案。你要是喜欢Debian、Fedora或Arch也没问题,但别在环境搭建上搞特殊化。团队里统一用Ubuntu,能省去一堆“为什么你那能编译我这不能”的破事。
必备软件包清单
先更新你的包索引,然后安装下面这些东西:
sudo apt update
sudo apt upgrade -y
sudo apt install -y \
build-essential \
gcc \
g++ \
make \
cmake \
autoconf \
automake \
libtool \
pkg-config \
flex \
bison \
texinfo \
libncurses-dev \
libssl-dev \
libgmp-dev \
libmpfr-dev \
libmpc-dev \
git \
wget \
curl \
file \
unzip \
python3 \
python3-pip
这里挑几个重点说说:
build-essential —— 包含gcc、g++、make等基础编译工具,装了它基本不会缺核心编译器。
libgmp-dev、libmpfr-dev、libmpc-dev —— 这三个是数学库,交叉编译器本身依赖它们做高精度运算。忘了装?编译gcc时会报“找不到GMP/MPFR/MPC”的错误,很烦人。
flex、bison、texinfo —— 处理词法分析、语法分析和文档生成,构建binutils和gcc时用得到。
选择目标架构与交叉工具链
你要清楚自己交叉编译的目标是什么。
常见的目标架构有这么几类:
| 目标架构 | 常见场景 | 工具链前缀示例 |
|---|---|---|
| ARM (32-bit) | 嵌入式Linux设备、树莓派 | arm-linux-gnueabihf- |
| AArch64 (ARM64) | 手机、服务器、树莓派3/4/5 | aarch64-linux-gnu- |
| MIPS | 路由器、网关设备 | mips-linux-gnu- |
| RISC-V (64-bit) | 开源硬件、新项目 | riscv64-linux-gnu- |
| x86_64 (Linux) | 本地编译,或交叉编译到x86目标 | x86_64-linux-gnu- |
怎么安装它们?
两种主流方式:
- 直接从包管理器装预编译工具链
# 装ARM 32位工具链
sudo apt install -y gcc-arm-linux-gnueabihf
# 装ARM 64位工具链
sudo apt install -y gcc-aarch64-linux-gnu
# 装RISC-V 64位工具链
sudo apt install -y gcc-riscv64-linux-gnu
这种方式最快,几分钟搞定。但预编译的工具链版本不一定最新,有时候和你的项目不太兼容。
- 自己编译交叉工具链(使用crosstool-NG)
如果你需要高度定制,比如改gcc版本、指定内核头文件版本、加特定参数,那就得自己来。
crosstool-NG 是时下最顺手的工具链构建工具。
# 克隆crosstool-NG
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
# 安装它的依赖
sudo apt install -y help2man gperf
# 启动bootstrap
./bootstrap
./configure --enable-local
make -j$(nproc)
装完后,用它配置和构建你的工具链:
# 列出支持的样本配置
./ct-ng list-samples | grep arm
# 选择一个样本,比如
./ct-ng arm-unknown-linux-gnueabihf
# 进入菜单配置界面
./ct-ng menuconfig
# 开始构建(会花30分钟到2小时,取决于机器性能)
./ct-ng build
验证你的工具链是否可用
装完了,怎么知道它能不能用?
写个最简单的hello world试试:
# 创建一个测试文件
cat > hello.c << 'EOF'
#include
int main() {
printf("Hello, Embedded World!\n");
return 0;
}
EOF
# 用交叉编译器编译(这里以ARM 32位为例)
arm-linux-gnueabihf-gcc hello.c -o hello-arm
# 检查生成的可执行文件是哪个架构的
file hello-arm
你应该看到类似这样的输出:
hello-arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, not stripped
看到“ARM”了吗?说明交叉编译成功。本地x86机器上生成的就是ARM架构的可执行文件,这就是交叉编译的核心能力。
整体环境结构图
把上面这些组件之间的关系理清楚,对你理解交叉开发的整个流程很有帮助。下面这张图展示了从宿主机到目标设备的工具链全貌:
避坑指南:我遇到过的那些问题
1. 64位系统编译32位应用
我曾经在64位Ubuntu上编译32位ARM程序时,链接阶段报错说缺少32位运行时库。解决方法:
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install -y libc6:i386 libncurses5:i386 libstdc++6:i386
嗯,这种问题在你用预编译工具链时偶尔会碰到。装上32位兼容库就好。
2. 环境变量冲突
如果你同时装了多个交叉工具链(比如ARM和AArch64),一定要小心PATH环境变量。我见过有人把两个工具链的bin目录都加进PATH,结果arm-linux-gnueabihf-gcc调用的却是AArch64的gcc前缀,编译出来的二进制不兼容目标硬件。
我的做法:每次进一个新终端,只把当前项目需要的工具链bin目录加进PATH,其他的不动。或者在Makefile里显式指定全路径:
CROSS_COMPILE = /usr/bin/arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
3. 磁盘空间和swap
用crosstool-NG自建工具链时,gcc编译阶段极度消耗内存。如果你的机器只有4GB内存,建议设置至少2GB的swap空间,否则编译到一半可能被OOM Killer干掉。
检查swap:
free -h
swapon --show
如果不够,临时添加:
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
./ct-ng build 2>&1 | tee build.log这样报错时你能快速定位是在哪一步挂掉的,不用盯着终端看。
环境搭建是整个交叉编译SDK开发的地基。地基没夯实,后面盖的楼再漂亮也站不稳。花30分钟把这一章的东西做一遍,你会发现后续的编译、调试、部署顺畅得多。