嵌入式 Linux 开发绕不开交叉编译。开发机通常是 x86_64,目标板可能是 ARM、AArch64、MIPS 或 RISC-V。代码在开发机上编译,最终要在目标板上运行,这中间最容易出问题的是架构、动态链接器和依赖库。
一、确认目标架构
在板子上执行:
1 | uname -m |
常见输出:
1 | armv7l |
开发机上查看工具链:
1 | arm-linux-gnueabihf-gcc -v |
工具链前缀必须和目标架构、ABI、C 库匹配。
二、编译第一个程序
代码:
1 |
|
编译:
1 | arm-linux-gnueabihf-gcc hello.c -o hello |
传到板子:
1 | scp hello root@192.168.1.100:/tmp/ |
如果能打印内容,说明基本链路通了。
三、No such file or directory 不一定是文件不存在
嵌入式新手经常遇到:
1 | ./hello: No such file or directory |
但 ls 明明能看到文件。这通常是动态链接器不存在。
检查:
1 | readelf -l hello | grep interpreter |
输出可能是:
1 | [Requesting program interpreter: /lib/ld-linux-armhf.so.3] |
再到板子上确认:
1 | ls -l /lib/ld-linux-armhf.so.3 |
如果没有,要么换正确工具链,要么把对应运行库放进 rootfs。
四、动态链接和静态链接
动态链接:
1 | arm-linux-gnueabihf-gcc hello.c -o hello |
静态链接:
1 | arm-linux-gnueabihf-gcc hello.c -static -o hello_static |
静态链接部署简单,但文件大,部分库不适合静态链接。动态链接更常见,但要保证 rootfs 里有对应 .so。
查看依赖:
1 | readelf -d hello |
或在目标板上:
1 | ldd /tmp/hello |
精简 rootfs 不一定带 ldd,这时优先用 readelf。
五、Makefile 最小模板
1 | CROSS_COMPILE ?= arm-linux-gnueabihf- |
编译:
1 | make CROSS_COMPILE=arm-linux-gnueabihf- |
这个模板足够支撑入门阶段的多文件项目。
六、部署策略
调试阶段:
1 | scp device_agent root@192.168.1.100:/tmp/ |
验证稳定后:
- 放进 Buildroot package。
- 或放入 rootfs overlay 的
/usr/bin。 - 配套启动脚本放到
/etc/init.d。 - 配置文件放到
/data/config。
不要长期依赖手工 scp,否则重新烧录后环境无法复现。
七、排查清单
程序跑不起来时按顺序查:
1 | file device_agent |
再看:
- 架构是否匹配。
- ABI 是否匹配。
- 动态链接器是否存在。
.so是否存在。- 程序是否有执行权限。
- rootfs 是否缺少
/lib或/usr/lib。
交叉编译的重点不是记命令,而是能解释一个程序为什么能在目标板上运行。
- 本文链接: https://blog.hansong.icu/2026/06/26/Embedded_Linux_Series_02_Cross_Compile/
- 版权声明: 本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。