第二章:开发环境搭建——交叉编译工具链安装、CMake构建系统配置、目标板环境准备

好,咱们正式开始动手了。

这一章,说白了就是给你手里的电脑和那块嵌入式板子“牵线搭桥”。你想想看,你的电脑是x86架构,目标板是ARM架构,代码在电脑上编译出来,板子才能认得。这中间的桥梁,就是交叉编译工具链。

我个人习惯,先把环境搞利索了再写代码。不然调试到一半发现工具链不对,那才叫一个头大。我记得刚入行那会儿,光装个交叉编译器就折腾了两天,最后发现是路径写错了……嗯,咱们今天就把这些坑都填平。

2.1 交叉编译工具链的安装

什么是交叉编译?简单说,就是在你的PC上(宿主机)编译出能在ARM板子上(目标机)运行的程序。这需要一套专门的工具集,包括编译器、链接器、库文件等等。

2.4.1 获取工具链

根据你的目标板,选择对应的工具链:

  • ARM Linux(如树莓派、全志系列):推荐使用 gcc-arm-linux-gnueabihf 或 Linaro 提供的工具链。
  • Android:必须使用 NDK 自带的工具链,或者通过 CMake 的 toolchain 文件来指定。

我个人习惯用 Linaro 的版本,更新及时,社区活跃。下载后解压到 /opt 目录下:

# 以 ARM 32位为例
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
sudo tar -xvf gcc-linaro-*.tar.xz -C /opt/

2.4.2 配置环境变量

解压完不算完,你得让系统能找到它。编辑 ~/.bashrc~/.zshrc,添加:

export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export CROSS_COMPILE=arm-linux-gnueabihf-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++

然后 source ~/.bashrc 使其生效。

注意: 我曾经遇到过 PATH 写错导致系统自带 gcc 被覆盖的情况。建议把交叉编译器的路径放在 $PATH 的末尾,或者单独设置变量,不要直接覆盖系统默认的 gcc。

2.4.3 验证安装

运行以下命令,看到版本信息就说明成功了:

arm-linux-gnueabihf-gcc --version

2.2 CMake 构建系统配置

CMake 的好处是跨平台,而且能很好地处理交叉编译。说白了,你只需要写一份 CMakeLists.txt,然后通过指定 toolchain 文件,就能在宿主机上编译出目标板能跑的程序。

2.2.1 编写 toolchain 文件

创建一个文件,比如 arm-linux-gnueabihf.cmake

# 设置目标系统名称
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++)

# 指定 sysroot(目标板的根文件系统路径)
set(CMAKE_SYSROOT /path/to/your/sysroot)

# 查找库文件时只在 sysroot 中查找
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)
小技巧: 如果你没有完整的 sysroot,可以先用 rsync 从目标板同步过来。我在项目中经常这么干,省去很多麻烦。

2.2.2 使用 CMake 进行交叉编译

在项目根目录下执行:

mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../arm-linux-gnueabihf.cmake ..
make

这样生成的二进制文件就是 ARM 架构的了。

2.2.3 常见问题

  • 找不到库文件:检查 CMAKE_SYSROOT 路径是否正确,以及目标板上的库是否完整。
  • 链接错误:确保你链接的库也是交叉编译出来的,不能混用宿主机上的 .so 文件。

2.3 目标板(ARM Linux/Android)环境准备

工具链装好了,CMake 配好了,接下来得让板子“活”起来。

2.3.1 ARM Linux 环境准备

你需要确保板子上有以下基础环境:

  • SSH 服务:方便远程登录和文件传输。
  • 必要的运行时库:比如 libstdc++、libc、libm 等。
  • 网络连接:有线或无线,用于下载依赖或同步代码。

我个人习惯用 scprsync 把编译好的程序传到板子上:

scp your_program user@board_ip:/home/user/

2.3.2 Android 环境准备

Android 的情况稍微特殊一点。你需要:

  • ADB 工具:用于连接设备和传输文件。
  • NDK:Android 的原生开发套件,里面包含了交叉编译工具链。
  • 目标设备的 ABI:armeabi-v7a、arm64-v8a、x86 等,编译时要对应上。

举个例子,用 NDK 编译一个可执行文件:

# 使用 NDK 的独立工具链
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
export CC=$TOOLCHAIN/bin/aarch64-linux-android21-clang
export CXX=$TOOLCHAIN/bin/aarch64-linux-android21-clang++

$CC -o hello_android hello.c
核心要点: 无论是 ARM Linux 还是 Android,核心思路是一样的——在宿主机上编译,在目标板上运行。区别只在于工具链和运行时环境。

2.3.3 验证环境

把编译好的程序传到板子上,运行一下:

# 在 ARM Linux 上
./your_program

# 在 Android 上(通过 ADB)
adb push your_program /data/local/tmp/
adb shell chmod +x /data/local/tmp/your_program
adb shell /data/local/tmp/your_program

看到输出,就说明环境搭建成功了。

2.4 避坑指南

最后,分享几个我踩过的坑:

  • 工具链版本不匹配:我曾经用 gcc 7 编译的程序,在只支持 gcc 5 的板子上跑不起来。建议编译时加上 -static 参数,或者确保板子的 libc 版本够新。
  • 路径硬编码:CMake 里如果写了绝对路径,换台机器就废了。尽量用相对路径和变量。
  • 忽略 sysroot:不设置 sysroot 的话,链接器可能会找到宿主机上的库,导致运行时崩溃。

好了,环境搭建就到这里。下一章咱们开始写第一个推理程序,到时候你就知道今天这些功夫没白费。