banner
NEWS LETTER

嵌入式开发进阶:交叉编译、CMake 工具链与部署

Scroll down

一、什么是交叉编译

交叉编译是指在一种平台上编译另一种平台运行的程序。比如在 x86_64 Ubuntu 电脑上编译 ARM 开发板运行的程序。

常见组合:

1
2
开发机:x86_64 Linux
目标板:ARM Linux

为什么需要交叉编译:

  • 开发板性能弱,编译慢。
  • 开发板存储小,不适合安装完整工具链。
  • CI/CD 通常运行在服务器上。
  • 需要统一构建环境。

二、确认目标架构

在开发板上查看:

1
uname -m

常见输出:

1
2
3
armv7l
aarch64
x86_64

查看系统 ABI:

1
file /bin/sh

输出里会包含架构、位数、动态链接器等信息。

三、交叉编译器命名

常见工具链前缀:

1
2
3
arm-linux-gnueabihf-
aarch64-linux-gnu-
arm-none-eabi-

区别:

  • arm-linux-gnueabihf:ARM Linux,硬浮点 ABI。
  • aarch64-linux-gnu:64 位 ARM Linux。
  • arm-none-eabi:裸机或 RTOS,通常没有 Linux。

查看编译器:

1
2
arm-linux-gnueabihf-gcc --version
aarch64-linux-gnu-gcc --version

Ubuntu 安装示例:

1
2
sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

四、最小交叉编译

hello.c

1
2
3
4
5
6
#include <stdio.h>

int main(void) {
printf("hello embedded linux\n");
return 0;
}

编译 ARM 32 位:

1
arm-linux-gnueabihf-gcc hello.c -o hello_arm

检查文件:

1
file hello_arm

复制到开发板:

1
scp hello_arm root@192.168.1.100:/tmp/

开发板运行:

1
2
chmod +x /tmp/hello_arm
/tmp/hello_arm

五、CMake 工具链文件

创建 toolchain-armhf.cmake

1
2
3
4
5
6
7
8
9
10
11
12
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

构建:

1
2
cmake -S . -B build-arm -DCMAKE_TOOLCHAIN_FILE=toolchain-armhf.cmake
cmake --build build-arm

六、项目结构建议

1
2
3
4
5
6
7
8
9
10
11
12
embedded-app/
├── CMakeLists.txt
├── cmake/
│ └── toolchain-armhf.cmake
├── include/
│ └── app.h
├── src/
│ └── main.c
├── scripts/
│ ├── build-arm.sh
│ └── deploy.sh
└── README.md

scripts/build-arm.sh

1
2
3
4
5
#!/usr/bin/env bash
set -euo pipefail

cmake -S . -B build-arm -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-armhf.cmake
cmake --build build-arm

scripts/deploy.sh

1
2
3
4
5
#!/usr/bin/env bash
set -euo pipefail

target=${1:-root@192.168.1.100}
scp build-arm/app "$target:/usr/local/bin/app"

七、动态库问题

交叉编译后复制到开发板运行,可能出现:

1
No such file or directory

明明文件存在,为什么提示不存在?常见原因是动态链接器或依赖库不匹配。

检查:

1
2
file app
readelf -l app | grep interpreter

查看依赖:

1
arm-linux-gnueabihf-readelf -d app

在开发板上:

1
ldd ./app

如果依赖库不存在,需要把库一起部署,或者使用目标板对应的 sysroot 编译。

八、sysroot

sysroot 是目标系统根目录的一个镜像,里面包含目标板的头文件和库。

常见来源:

  • SDK 提供。
  • 从开发板复制。
  • Buildroot / Yocto 生成。

使用 sysroot:

1
set(CMAKE_SYSROOT /opt/arm-sysroot)

编译器会从 sysroot 里找目标平台的头文件和库,避免错误链接到开发机库。

九、部署方式

常见方式:

  • scp 复制单个程序。
  • 打包 tar.gz。
  • 制作 deb/rpm 包。
  • 放进 rootfs 镜像。
  • OTA 升级。

入门阶段建议先用 scp,流程简单,便于快速验证。

1
2
scp build-arm/app root@board:/tmp/
ssh root@board /tmp/app

稳定后再考虑系统化部署。

十、常见问题

10.1 Exec format error

架构不匹配。例如把 x86 程序放到 ARM 板运行。

检查:

1
2
file app
uname -m

10.2 GLIBC 版本不匹配

开发机工具链生成的程序依赖较新 glibc,目标板系统太旧。

解决:

  • 使用板厂 SDK。
  • 使用和目标板一致的 sysroot。
  • 使用 Buildroot/Yocto 统一生成工具链和系统。

10.3 找不到动态库

检查:

1
ldd ./app

临时:

1
LD_LIBRARY_PATH=./lib ./app

长期:

  • 安装库到系统路径。
  • 配置动态链接器。
  • 部署启动脚本。

十一、总结

嵌入式交叉编译的核心不是会敲一条编译命令,而是保证工具链、目标架构、sysroot、动态库和部署环境一致。

一旦出现运行失败,优先检查:

1
file -> readelf -> ldd -> sysroot -> 目标板系统版本

这条链路能解决大部分交叉编译入门问题。

其他文章
目录导航 置顶
  1. 1. 一、什么是交叉编译
  2. 2. 二、确认目标架构
  3. 3. 三、交叉编译器命名
  4. 4. 四、最小交叉编译
  5. 5. 五、CMake 工具链文件
  6. 6. 六、项目结构建议
  7. 7. 七、动态库问题
  8. 8. 八、sysroot
  9. 9. 九、部署方式
  10. 10. 十、常见问题
    1. 10.1. 10.1 Exec format error
    2. 10.2. 10.2 GLIBC 版本不匹配
    3. 10.3. 10.3 找不到动态库
  11. 11. 十一、总结
请输入关键词进行搜索