交叉编译工具链
概述
交叉编译工具链(Cross Compilation Toolchain)是在一个平台上编译生成另一个平台可执行代码的工具集,是嵌入式开发的基础工具。
工具链组成
交叉编译工具链包含以下核心组件:
| 组件 |
说明 |
| gcc |
C编译器 |
| g++ |
C++编译器 |
| ld |
链接器 |
| as |
汇编器 |
| ar |
归档工具(创建静态库) |
| objcopy |
目标文件转换 |
| objdump |
目标文件分析 |
| strip |
去除符号信息 |
| gdb |
调试器 |
工具链命名规则
| Text Only |
|---|
| <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 |
|---|
| # 下载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 |
|---|
| # 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 |
|---|
| # 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 |
|---|
| # 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 |
|---|
| # 在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)
|
| 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 |
|---|
| # 软浮点 (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 |
|---|
| # 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 ..
|
| 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 |
|---|
| -O0 # 不优化
-O1 # 基本优化
-O2 # 标准优化(推荐)
-O3 # 激进优化
-Os # 优化代码大小
-Ofast # 最快执行速度
|
调试选项
| Bash |
|---|
| -g # 生成调试信息
-ggdb # GDB专用调试信息
-g3 # 最大化调试信息
-fno-omit-frame-pointer # 保留帧指针
|
链接选项
| Bash |
|---|
| -static # 静态链接
-shared # 生成共享库
-fPIC # 位置无关代码
-Wl,-rpath,/lib # 运行时库路径
|
静态库与动态库
创建静态库
| Bash |
|---|
| # 编译目标文件
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 |
|---|
| # 编译动态库
arm-linux-gnueabihf-gcc -shared -fPIC -o libmylib.so lib.c
# 使用动态库
arm-linux-gnueabihf-gcc main.c -L. -lmylib -o main
|
查看程序信息
查看依赖库
| Bash |
|---|
| # 使用readelf
arm-linux-gnueabihf-readelf -d program | grep NEEDED
# 使用ldd(需要qemu-user)
qemu-arm -L /path/to/sysroot ldd program
|
查看符号信息
| Bash |
|---|
| # 列出符号
arm-linux-gnueabihf-nm program
# 查看函数列表
arm-linux-gnueabihf-objdump -t program | grep ' .text '
# 反汇编
arm-linux-gnueabihf-objdump -d program
|
去除符号信息
| Bash |
|---|
| # 去除调试符号
arm-linux-gnueabihf-strip program
# 只去除调试信息,保留符号表
arm-linux-gnueabihf-strip --strip-debug program
# 查看文件大小变化
ls -l program
|
调试程序
使用GDB远程调试
目标机:
| Bash |
|---|
| # 启动gdbserver
gdbserver :1234 ./program
|
开发机:
| Bash |
|---|
| # 启动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 |
|---|
| # 使用sysroot
arm-linux-gnueabihf-gcc --sysroot=/path/to/sysroot hello.c -o hello
# CMake中使用sysroot
set(CMAKE_SYSROOT /path/to/sysroot)
|
常见问题
找不到头文件
| Bash |
|---|
| # 指定头文件路径
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 |
|---|
| # 指定库路径
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 |
|---|
| # 检查库是否兼容
arm-linux-gnueabihf-readelf -h libmylib.so | grep Machine
arm-linux-gnueabihf-readelf -h program | grep Machine
# 确保架构一致
file libmylib.so
file program
|
参考资料