直接用apt安装gcc-aarch64-linux-gnu和g++-aarch64-linux-gnu可满足90%基础arm64项目;但集成opencv、cuda或qt,或目标板为定制rootfs(如jetson tx2)时,必须正确配置sysroot、glibc版本及pkg-config路径,否则链接阶段报undefined reference;需通过uname -m确认目标架构为aarch64后,再配环境变量与cmake toolchain文件协同生效。

直接用 apt 装 gcc-aarch64-linux-gnu 和 g++-aarch64-linux-gnu 就能跑通 90% 的 ARM64 基础项目;但如果你要集成 OpenCV、CUDA 或 Qt,或者目标板子上跑的是定制 rootfs(比如 Jetson TX2 的系统镜像),光装工具链远远不够——sysroot 不对、glibc 版本不匹配、pkg-config 找不到库,编译会卡在链接阶段,报一堆 undefined reference。
确认目标架构再选工具链:aarch64-linux-gnu 还是 arm-linux-gnueabihf?
先搞清你的板子是 ARM64 还是 ARM32:
- Jetson TX2、树莓派 4B/5、RK3399、所有基于 ARMv8-A 的设备 → 用
aarch64-linux-gnu-工具链 - 老旧 Cortex-A9/A7 板子(比如某些 STM32MP1 开发板)→ 可能得用
arm-linux-gnueabihf-
别凭感觉猜。登录目标板,运行:uname -m —— 输出 aarch64 就锁死用 aarch64-linux-gnu-gcc;输出 armv7l 或 armv8l 则大概率是 32 位,优先试 arm-linux-gnueabihf-gcc。
Ubuntu 官方仓库里这两个工具链是分开包的,装错一个就白忙活:
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
装完验证:aarch64-linux-gnu-gcc -v 要能打出版本号,且 Target: 行明确写着 aarch64-linux-gnu。
编译失败常见于头文件和库路径错乱:必须配 sysroot
工具链只是“编译器”,它默认用宿主机(x86_64 Ubuntu)的 /usr/include 和 /usr/lib,而你最终要在 ARM 板子上运行,必须告诉它:“去 ARM 系统的根目录里找头文件和库”。这个 ARM 系统根目录就是 sysroot。
最省事的方式是直接同步目标板的完整 / 目录(或官方 SDK 提供的 sysroot tar 包),解压到例如 /opt/arm64-sysroot。然后设置环境变量,**不要只靠 --sysroot 参数临时加**:
export SYSROOT=/opt/arm64-sysroot export CC=aarch64-linux-gnu-gcc export CXX=aarch64-linux-gnu-g++ export CFLAGS="--sysroot=$SYSROOT -I$SYSROOT/usr/include -I$SYSROOT/include" export CXXFLAGS="--sysroot=$SYSROOT -I$SYSROOT/usr/include -I$SYSROOT/include" export LDFLAGS="--sysroot=$SYSROOT -L$SYSROOT/lib -L$SYSROOT/usr/lib -L$SYSROOT/usr/lib/aarch64-linux-gnu" export PKG_CONFIG_SYSROOT_DIR=$SYSROOT export PKG_CONFIG_LIBDIR=$SYSROOT/usr/lib/aarch64-linux-gnu/pkgconfig
这样后续跑 make、cmake、pkg-config --cflags opencv4 都能自动命中 ARM 版头文件和 .so。
容易踩的坑:
• sysroot 里缺 libstdc++.so?检查是否把 $SYSROOT/usr/lib/aarch64-linux-gnu 加进 LDFLAGS 和 LIBRARY_PATH;
• pkg-config 找不到 opencv4?确认 $SYSROOT/usr/lib/aarch64-linux-gnu/pkgconfig/opencv4.pc 存在,且 prefix= 指向的是 $SYSROOT/usr,不是宿主机路径。
CMake 交叉编译配置不能只靠 toolchain file
很多教程让你写个 toolchain.cmake,里面设 set(CMAKE_SYSTEM_NAME Linux)、set(CMAKE_SYSTEM_PROCESSOR aarch64),这只能让 CMake 认出平台,**但它不会自动加载你上面配好的环境变量**。
真正可靠的做法是两层控制:
- 第一层:用
-DCMAKE_TOOLCHAIN_FILE=xxx指定 toolchain 文件,里面只做最低限度声明(如CMAKE_C_COMPILER) - 第二层:**在 shell 里提前 export 上面那一整套
CFLAGS/LDFLAGS/PKG_CONFIG_*,CMake 会自动读取并透传给pkg-config和底层编译命令**
一个最小可用的 toolchain.cmake 示例:
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++) set(CMAKE_FIND_ROOT_PATH /opt/arm64-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)
然后这样调用:cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
——前提是你的 export 已生效,否则 find_package(OpenCV) 仍会失败。
运行时报 “cannot execute binary file: Exec format error” 怎么快速定位?
这是最典型的“看着编译成功,一跑就跪”错误,根本原因只有一个:二进制不是为当前 CPU 架构生成的。
分三步秒查:
- 在宿主机上执行:
file ./your_program→ 必须看到ELF 64-bit LSB shared object, ARM aarch64。如果出现x86-64或ARM(没带aarch64),说明编译器没走对 - 在目标板上执行:
readelf -A ./your_program | grep Tag_ABI_VFP_args→ 如果报错或无输出,说明链接时没用对sysroot下的libc,导致 ABI 不兼容 - 检查动态依赖:
aarch64-linux-gnu-readelf -d ./your_program | grep NEEDED→ 所有NEEDED的库名(如libstdc++.so.6)必须能在目标板的/usr/lib或/lib下找到对应版本;若提示not found,说明sysroot缺库,或你用了宿主机的.so
复杂点在于:有些库(比如 CUDA 驱动相关的 libnvrm.so)只存在于 Jetson 的特定分区,无法简单塞进 sysroot;这种就得改 CMakeLists.txt,用 target_link_libraries(... INTERFACE) 显式指定绝对路径,或者编译时加 -Wl,-rpath,/usr/lib/nvidia。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











