跳转至

交叉编译工具链

概述

交叉编译工具链(Cross Compilation Toolchain)是在一个平台上编译生成另一个平台可执行代码的工具集,是嵌入式开发的基础工具。

工具链组成

交叉编译工具链包含以下核心组件:

组件 说明
gcc C编译器
g++ C++编译器
ld 链接器
as 汇编器
ar 归档工具(创建静态库)
objcopy 目标文件转换
objdump 目标文件分析
strip 去除符号信息
gdb 调试器

工具链命名规则

Text Only
1
2
3
4
5
6
7
8
<arch>-<vendor>-<os>-<abi>

示例:
arm-linux-gnueabihf-gcc      # ARM架构, Linux系统, EABI, 硬浮点
arm-none-eabi-gcc            # ARM架构, 裸机, EABI
aarch64-linux-gnu-gcc        # ARM64架构, Linux系统
mips-linux-gnu-gcc           # MIPS架构, Linux系统
riscv64-linux-gnu-gcc        # RISC-V 64位, Linux系统

获取工具链

方法一:下载预编译工具链

ARM官方工具链

Bash
1
2
3
4
5
6
# 下载ARM GNU Toolchain
wget https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz
tar xvf arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz

# 添加到PATH
export PATH=/path/to/arm-gnu-toolchain-13.2.rel1/bin:$PATH

Linaro工具链

Bash
1
2
3
# Linaro ARM工具链
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
tar xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

Bootlin工具链

Bash
1
2
3
4
5
# Bootlin提供的预编译工具链(多种架构)
# https://toolchains.bootlin.com/

wget https://toolchains.bootlin.com/downloads/releases/armv7-eabihf--glibc--stable-2020.08-1.tar.bz2
tar xvf armv7-eabihf--glibc--stable-2020.08-1.tar.bz2

方法二:包管理器安装

Bash
1
2
3
4
5
6
7
8
9
# Ubuntu/Debian
sudo apt install gcc-arm-linux-gnueabihf     # ARM 32位
sudo apt install gcc-aarch64-linux-gnu       # ARM 64位
sudo apt install gcc-arm-none-eabi           # ARM 裸机
sudo apt install gcc-mips-linux-gnu          # MIPS
sudo apt install gcc-riscv64-linux-gnu       # RISC-V

# CentOS/RHEL
sudo yum install arm-linux-gnueabihf-gcc

方法三:使用Buildroot构建

Bash
1
2
3
4
5
6
7
8
9
# 在Buildroot中选择构建工具链
make menuconfig

Toolchain  --->
    Toolchain type (Buildroot toolchain)
    (*) GCC compiler version (gcc 12.x)
    (*) C library (glibc)
    [*] Enable C++ support
    [*] Enable compiler cache support (ccache)

方法四:使用Crosstool-NG构建

Bash
# 安装Crosstool-NG
git clone https://github.com/crosstool-ng/crosstool-ng.git
cd crosstool-ng
./bootstrap
./configure --prefix=/opt/ct-ng
make
make install

# 配置并构建工具链
/opt/ct-ng/bin/ct-ng menuconfig
/opt/ct-ng/bin/ct-ng build

工具链选择

GNU EABI vs GNU EABIHF

Bash
1
2
3
4
5
# 软浮点 (EABI)
arm-linux-gnueabi-gcc

# 硬浮点 (EABIHF) - 性能更好,推荐使用
arm-linux-gnueabihf-gcc

检查是否支持硬浮点:

Bash
arm-linux-gnueabihf-gcc -v 2>&1 | grep "hard-float"

glibc vs musl libc vs uClibc

C库 特点 适用场景
glibc 功能完整、体积大 资源充足的系统
musl libc 小巧轻量、兼容性好 资源受限的嵌入式
uClibc 非常小巧、兼容性一般 极端资源受限系统

查看工具链信息

Bash
# 查看GCC版本
arm-linux-gnueabihf-gcc --version

# 查看支持的架构
arm-linux-gnueabihf-gcc -dumpmachine

# 查看头文件路径
arm-linux-gnueabihf-gcc -print-sysroot

# 查看库文件路径
arm-linux-gnueabihf-gcc -print-search-dirs

使用交叉编译工具链

基本使用

Bash
# 设置环境变量
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=/path/to/toolchain/bin:$PATH

# 编译C程序
arm-linux-gnueabihf-gcc -o hello hello.c

# 编译C++程序
arm-linux-gnueabihf-g++ -o hello hello.cpp

Makefile中使用

Makefile
CC = arm-linux-gnueabihf-gcc
CXX = arm-linux-gnueabihf-g++
LD = arm-linux-gnueabihf-ld
AR = arm-linux-gnueabihf-ar
STRIP = arm-linux-gnueabihf-strip

CFLAGS = -Wall -O2 -march=armv7-a
LDFLAGS =

hello: hello.c
    $(CC) $(CFLAGS) -o $@ $<

# 静态编译
hello_static: hello.c
    $(CC) $(CFLAGS) -static -o $@ $<

CMake中使用

CMake
1
2
3
4
5
6
7
8
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(hello C)

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

add_executable(hello hello.c)

或使用工具链文件:

CMake
# toolchain-arm.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++)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Bash
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain-arm.cmake ..

autotools中使用

Bash
# 配置
./configure --host=arm-linux-gnueabihf \
    --prefix=/usr \
    CC=arm-linux-gnueabihf-gcc \
    CXX=arm-linux-gnueabihf-g++

# 编译
make

# 安装到指定目录
make DESTDIR=/path/to/rootfs install

常用编译选项

架构相关选项

Bash
# 指定CPU架构
-march=armv7-a                    # ARMv7架构
-mcpu=cortex-a7                   # Cortex-A7 CPU
-mtune=cortex-a7                  # 优化为Cortex-A7

# 浮点运算
-mfloat-abi=hard                  # 硬浮点
-mfpu=vfpv4                       # VFPv4浮点单元

# 指令集
-mthumb                           # Thumb指令集
-marm                             # ARM指令集

优化选项

Bash
1
2
3
4
5
6
-O0                               # 不优化
-O1                               # 基本优化
-O2                               # 标准优化(推荐)
-O3                               # 激进优化
-Os                               # 优化代码大小
-Ofast                            # 最快执行速度

调试选项

Bash
1
2
3
4
-g                                # 生成调试信息
-ggdb                             # GDB专用调试信息
-g3                               # 最大化调试信息
-fno-omit-frame-pointer           # 保留帧指针

链接选项

Bash
1
2
3
4
-static                           # 静态链接
-shared                           # 生成共享库
-fPIC                             # 位置无关代码
-Wl,-rpath,/lib                   # 运行时库路径

静态库与动态库

创建静态库

Bash
1
2
3
4
5
6
7
8
# 编译目标文件
arm-linux-gnueabihf-gcc -c lib.c -o lib.o

# 创建静态库
arm-linux-gnueabihf-ar rcs libmylib.a lib.o

# 使用静态库
arm-linux-gnueabihf-gcc main.c -L. -lmylib -o main

创建动态库

Bash
1
2
3
4
5
# 编译动态库
arm-linux-gnueabihf-gcc -shared -fPIC -o libmylib.so lib.c

# 使用动态库
arm-linux-gnueabihf-gcc main.c -L. -lmylib -o main

查看程序信息

查看依赖库

Bash
1
2
3
4
5
# 使用readelf
arm-linux-gnueabihf-readelf -d program | grep NEEDED

# 使用ldd(需要qemu-user)
qemu-arm -L /path/to/sysroot ldd program

查看符号信息

Bash
1
2
3
4
5
6
7
8
# 列出符号
arm-linux-gnueabihf-nm program

# 查看函数列表
arm-linux-gnueabihf-objdump -t program | grep ' .text '

# 反汇编
arm-linux-gnueabihf-objdump -d program

去除符号信息

Bash
1
2
3
4
5
6
7
8
# 去除调试符号
arm-linux-gnueabihf-strip program

# 只去除调试信息,保留符号表
arm-linux-gnueabihf-strip --strip-debug program

# 查看文件大小变化
ls -l program

调试程序

使用GDB远程调试

目标机:

Bash
# 启动gdbserver
gdbserver :1234 ./program

开发机:

Bash
1
2
3
4
5
6
7
# 启动GDB
arm-linux-gnueabihf-gdb ./program

# 连接目标机
(gdb) target remote 192.168.1.100:1234
(gdb) break main
(gdb) continue

使用QEMU模拟调试

Bash
# 安装qemu-user
sudo apt install qemu-user

# 运行ARM程序
qemu-arm -L /path/to/sysroot ./program

# 调试模式
qemu-arm -g 1234 -L /path/to/sysroot ./program &
arm-linux-gnueabihf-gdb ./program
(gdb) target remote :1234

sysroot配置

sysroot是目标系统的根文件系统,包含头文件和库文件。

Bash
1
2
3
4
5
# 使用sysroot
arm-linux-gnueabihf-gcc --sysroot=/path/to/sysroot hello.c -o hello

# CMake中使用sysroot
set(CMAKE_SYSROOT /path/to/sysroot)

常见问题

找不到头文件

Bash
1
2
3
4
5
# 指定头文件路径
arm-linux-gnueabihf-gcc -I/path/to/include hello.c -o hello

# 使用sysroot
arm-linux-gnueabihf-gcc --sysroot=/path/to/sysroot hello.c -o hello

找不到库文件

Bash
1
2
3
4
5
# 指定库路径
arm-linux-gnueabihf-gcc -L/path/to/lib -lmylib hello.c -o hello

# 指定运行时库路径
arm-linux-gnueabihf-gcc -Wl,-rpath,/lib hello.c -o hello

链接错误

Bash
1
2
3
4
5
6
7
# 检查库是否兼容
arm-linux-gnueabihf-readelf -h libmylib.so | grep Machine
arm-linux-gnueabihf-readelf -h program | grep Machine

# 确保架构一致
file libmylib.so
file program

参考资料