Linux 交叉编译实践笔记

x86_64 → ARM64(aarch64)


1. 什么是交叉编译

在一种架构的机器上,生成另一种架构可执行程序

项目 示例
构建机(build) x86_64 Linux
目标机(host / target) ARM64 Linux
编译器 aarch64-linux-gnu-gcc
产物 ARM64 ELF

2. 交叉编译三要素(核心)

要素 作用
Toolchain 决定生成哪种架构的代码
Sysroot 决定"用哪套头文件 / 库"
Build System 决定如何查找工具链与库

一句话总结:

Toolchain 决定"能不能编",Sysroot 决定"能不能跑"


3. 基础示例(无第三方依赖)

3.1 安装 ARM64 工具链(Ubuntu)

sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

生成的关键工具:

aarch64-linux-gnu-gcc aarch64-linux-gnu-g++ aarch64-linux-gnu-ld


3.2 示例代码

#include <stdio.h>

int main()

{

printf("Hello ARM64\n");

return 0;

}


3.3 编译与验证

aarch64-linux-gnu-gcc hello.c -o hello_arm64 file hello_arm64

输出:

ELF 64-bit LSB executable, ARM aarch64


4. Sysroot(工程级必备)

4.1 什么是 sysroot

目标系统"根目录"的最小拷贝

包含:

  • /lib

  • /usr/include

  • /usr/lib


4.2 获取 sysroot(推荐方式)

rsync -avz root@arm-board:/lib /opt/arm-sysroot/

rsync -avz root@arm-board:/usr/include /opt/arm-sysroot/usr/

rsync -avz root@arm-board:/usr/lib /opt/arm-sysroot/usr/

目录结构:

/opt/arm-sysroot

├── lib

└── usr

├── include

└── lib


4.3 使用 sysroot 编译

bash 复制代码
aarch64-linux-gnu-gcc  --sysroot=/opt/arm-sysroot  hello.c -o hello_arm64

5. CMake 交叉编译(常用)

5.1 Toolchain 文件(关键)

aarch64-toolchain.cmake

bash 复制代码
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_SYSROOT /opt/arm-sysroot)
set(CMAKE_FIND_ROOT_PATH /opt/arm-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)

5.2 构建流程

bash 复制代码
mkdir build-arm64 && cd build-arm64
cmake .. -DCMAKE_TOOLCHAIN_FILE=../aarch64-toolchain.cmake
make -j

6. Autotools 项目(configure)

bash 复制代码
./configure \
  --host=aarch64-linux-gnu \
  --build=x86_64-linux-gnu \
  CC=aarch64-linux-gnu-gcc

7. 运行与验证

7.1 拷贝到 ARM 设备

scp hello_arm64 root@arm:/tmp


7.2 使用 qemu 在 x86 上运行(调试神器)

sudo apt install qemu-user qemu-aarch64 ./hello_arm64

带动态库:

qemu-aarch64 -L /opt/arm-sysroot ./hello_arm64


8. 常见问题与踩坑

8.1 glibc 版本不匹配

表现:

version `GLIBC_2.xx' not found

原因:

  • 工具链 glibc ≠ 目标系统 glibc

结论:

Toolchain 和 sysroot 必须同源


8.2 CMake 找到宿主机库

解决:

bash 复制代码
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

8.3 pkg-config 找错架构

bash 复制代码
export PKG_CONFIG_SYSROOT_DIR=/opt/arm-sysroot 
export PKG_CONFIG_PATH=/opt/arm-sysroot/usr/lib/pkgconfig

9. 调试工具

工具 用途
file 查看二进制架构
readelf 查看依赖库
qemu-aarch64 x86 运行 ARM 程序
aarch64-linux-gnu-gdb 交叉调试

10. 一句话总结

交叉编译不是"换个 gcc",而是:
用对工具链 + 用对 sysroot + 禁止混入宿主库

交叉编译(ARM / x86)下 ldd 为什么不准 + 正确排错方式

bash 复制代码
###############################################################################
# 交叉编译场景下的动态库排错 Demo(ARM / x86)
# 重点:为什么 ldd 不准?正确怎么查?
###############################################################################

###############################################################################
# 一、问题背景
###############################################################################
# 你在 x86_64 Linux 上交叉编译了一个 ARM 程序:
#   - 构建机:x86_64
#   - 目标机:ARMv8 (aarch64)
#
# 常见错误认知:
#   "我在构建机上 ldd 一下 ARM 程序看看依赖"
#
# 结论:
#   ❌ 这是错的,ldd 在交叉场景下【不可靠 / 直接不可用】
###############################################################################


###############################################################################
# 二、为什么 ldd 在交叉编译下不准?
###############################################################################
# ldd 的本质:
#   - 使用【当前系统的动态链接器】模拟加载
#
# 问题点:
#   - x86 系统的动态链接器:/lib64/ld-linux-x86-64.so.2
#   - ARM 程序需要的动态链接器:ld-linux-aarch64.so.1
#
# 结果:
#   1) ldd 可能直接报错
#   2) ldd 显示 not found(但目标机其实能跑)
#   3) ldd 输出完全不可信
###############################################################################


###############################################################################
# 三、错误示例(不要这样做)
###############################################################################

# 在 x86 构建机上对 ARM 程序使用 ldd
ldd my_arm_binary

# 可能输出:
# not a dynamic executable
# 或
# libgrpc++.so.1 => not found

# 说明:
# - 不是 ARM 程序真有问题
# - 而是 x86 的 ldd 根本不会用 ARM 的链接器
###############################################################################


###############################################################################
# 四、正确姿势 1:readelf(最重要,首选)
###############################################################################
# readelf 不会尝试运行程序
# 它只是"读 ELF 文件结构",完全架构无关
###############################################################################

# 1️⃣ 查看 ELF 目标架构
readelf -h my_arm_binary

# 关键输出示例:
# Machine:                           AArch64

# 说明:
# - 确认这是 ARM 程序,而不是编错架构


# 2️⃣ 查看程序依赖哪些共享库(NEEDED)
readelf -d my_arm_binary | grep NEEDED

# 示例输出:
# 0x0000000000000001 (NEEDED) Shared library: [libgrpc++.so.1]
# 0x0000000000000001 (NEEDED) Shared library: [libprotobuf.so.32]
# 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

# 说明:
# - 这才是【真实的运行期依赖】
# - 不依赖当前系统架构
###############################################################################


###############################################################################
# 五、正确姿势 2:确认目标机动态链接器
###############################################################################

# 查看程序需要哪个动态链接器
readelf -l my_arm_binary | grep interpreter

# 示例输出:
# [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]

# 说明:
# - 目标机必须存在这个文件
# - 否则程序直接起不来
###############################################################################


###############################################################################
# 六、正确姿势 3:目标机上用 ldd(最权威)
###############################################################################
# 把程序和依赖拷到目标 ARM 设备上
###############################################################################

# 在 ARM 设备上执行
ldd my_arm_binary

# 示例输出:
# libgrpc++.so.1 => /usr/lib/libgrpc++.so.1
# libprotobuf.so.32 => /usr/lib/libprotobuf.so.32
# libc.so.6 => /lib/libc.so.6

# 说明:
# - 这是唯一"100%可信"的 ldd 结果
###############################################################################


###############################################################################
# 七、目标机缺库时的修复方式
###############################################################################

# 1️⃣ 确认库文件是否存在
ls /usr/lib/libgrpc++.so.1

# 2️⃣ 系统是否认识该库
ldconfig -p | grep grpc

# 3️⃣ 若库在自定义目录(例如 /opt/lib)
sudo vi /etc/ld.so.conf.d/custom.conf

# 写入:
# /opt/lib

# 更新缓存
sudo ldconfig

# 再次检查
ldconfig -p | grep grpc
###############################################################################


###############################################################################
# 八、交叉编译工程级"正确排错顺序"
###############################################################################
# 在构建机(x86):
#   1. readelf -h            → 看架构
#   2. readelf -d | NEEDED   → 看依赖库名
#   3. readelf -l | interpreter → 看动态链接器
#
# 在目标机(ARM):
#   4. ldd                   → 看实际加载路径
#   5. ldconfig -p           → 看系统是否认识库
#   6. sudo ldconfig         → 修复 not found
###############################################################################


###############################################################################
# 九、记住这 4 句"工程级结论"
###############################################################################
# 1️⃣ ldd ≠ ELF 分析工具,它是"运行期模拟器"
# 2️⃣ 交叉编译场景下,构建机 ldd 基本不可信
# 3️⃣ readelf 是交叉编译下的第一选择
# 4️⃣ 最终结果一定以【目标机 ldd】为准
###############################################################################
相关推荐
咕噜企业分发小米17 小时前
直播云服务器安全防护有哪些最新的技术趋势?
运维·服务器·安全
Dragon~Snow17 小时前
Linux-centOS Stream 9 系统 mysql-8.4.7 RPM版本
linux·mysql·centos
秋风未动蝉已先觉17 小时前
CentOs服务器 systemctl执行权限授权给普通权限work用户
linux·服务器
cly117 小时前
Ansible自动化(十五):加解密详解
运维·自动化·ansible
程序员zgh17 小时前
Linux 系统调用
linux·运维·服务器·c语言·c++·系统安全
Stuomasi_xiaoxin17 小时前
ROS2介绍,及ubuntu22.04 安装ROS 2部署使用!
linux·人工智能·深度学习·ubuntu
带土117 小时前
2. Linux下FFmpeg C++音视频解码+推流开发
linux·c++·ffmpeg
cly117 小时前
Ansible自动化(十二):Jinja2过滤器
运维·自动化·ansible
P-ShineBeam17 小时前
八卡A100服务器坏卡引发 CUDA initialization: cudaGetDeviceCount()异常
运维·服务器·人工智能·语言模型