制作交叉编译工具链

交叉编译工具链实现教程

1. 基础概念

什么是交叉编译工具链?

交叉编译工具链是一套编译器、链接器、库和工具的集合,用于在一个架构(主机)上编译出能在另一个架构(目标)上运行的程序。

关键术语

  • Host(主机):运行编译器的系统
  • Target(目标):编译出的程序运行的系统
  • Build(构建):用于构建工具链的系统
  • Triplet(三元组):描述架构的格式,如 arm-linux-gnueabihf

2. 环境准备

2.1 安装依赖工具

# Ubuntu/Debian
sudo apt update
sudo apt install -y build-essential git wget curl \
    texinfo bison flex gawk m4 python3 python3-dev \
    libncurses5-dev libssl-dev libelf-dev bc

2.2 配置国内镜像源

为了加快下载速度,配置国内镜像源:

# 设置镜像源变量
export MIRROR_TSINGHUA="https://mirrors.tuna.tsinghua.edu.cn"
export MIRROR_USTC="https://mirrors.ustc.edu.cn" 
export MIRROR_ALIYUN="https://mirrors.aliyun.com"
export MIRROR_HUAWEI="https://mirrors.huaweicloud.com"

# 创建工作目录,很重要的一步!!!!!!
mkdir -p ~/cross-toolchain
cd ~/cross-toolchain
export WORKSPACE=$(pwd)  
export PREFIX=$WORKSPACE/toolchain
export PATH=$PREFIX/bin:$PATH
export TARGET=arm-linux-gnueabihf  # 目标架构 

2.3 配置包管理器镜像(可选)

# Ubuntu/Debian 配置清华镜像
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
sudo sed -i 's|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list
sudo sed -i 's|http://security.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list
sudo apt update

3. 下载源码

3.1 下载核心组件

# 创建源码目录
mkdir -p $WORKSPACE/src
cd $WORKSPACE/src

# 使用清华大学镜像源
MIRROR_TSINGHUA="https://mirrors.tuna.tsinghua.edu.cn"
MIRROR_USTC="https://mirrors.ustc.edu.cn"
MIRROR_ALIYUN="https://mirrors.aliyun.com"

# Binutils - 清华镜像
wget ${MIRROR_TSINGHUA}/gnu/binutils/binutils-2.41.tar.xz
tar -xf binutils-2.41.tar.xz

# GCC - 清华镜像
wget ${MIRROR_TSINGHUA}/gnu/gcc/gcc-13.2.0/gcc-13.2.0.tar.xz
tar -xf gcc-13.2.0.tar.xz

# Linux内核头文件 - 清华镜像
wget ${MIRROR_TSINGHUA}/kernel/v5.x/linux-5.4.284.tar.xz
tar -xf linux-5.4.284.tar.xz

# glibc - 清华镜像
wget ${MIRROR_TSINGHUA}/gnu/glibc/glibc-2.42.tar.xz
tar -xf glibc-2.42.tar.xz

3.2 下载GCC依赖(使用国内源)

cd gcc-13.2.0

# 修改下载脚本使用国内镜像
sed -i 's|ftp://gcc.gnu.org/pub/gcc/infrastructure/|https://mirrors.tuna.tsinghua.edu.cn/gnu/|g' contrib/download_prerequisites
sed -i 's|https://gcc.gnu.org/pub/gcc/infrastructure/|https://mirrors.tuna.tsinghua.edu.cn/gnu/|g' contrib/download_prerequisites

./contrib/download_prerequisites
cd ..

3.3 备用下载方案

如果自动下载失败,可手动下载GCC依赖:

cd gcc-13.2.0

# 手动下载依赖包
wget ${MIRROR_TSINGHUA}/gnu/mpfr/mpfr-4.1.0.tar.bz2
wget ${MIRROR_TSINGHUA}/gnu/gmp/gmp-6.2.1.tar.bz2  
wget ${MIRROR_TSINGHUA}/gnu/mpc/mpc-1.2.1.tar.gz
wget https://gcc.gnu.org/pub/gcc/infrastructure/isl-0.24.tar.bz2

# 解压并创建符号链接
tar -xf mpfr-4.1.0.tar.bz2 && ln -sf mpfr-4.1.0 mpfr
tar -xf gmp-6.2.1.tar.bz2 && ln -sf gmp-6.2.1 gmp
tar -xf mpc-1.2.1.tar.gz && ln -sf mpc-1.2.1 mpc  
tar -xf isl-0.24.tar.bz2 && ln -sf isl-0.24 isl

cd ..

4. 构建步骤

4.1 第一步:构建 Binutils#

mkdir -p $WORKSPACE/build/binutils
cd $WORKSPACE/build/binutils

$WORKSPACE/src/binutils-2.41/configure \
    --target=$TARGET \
    --prefix=$PREFIX \
    --with-sysroot=$PREFIX/$TARGET \
    --disable-nls \
    --disable-werror

make -j$(nproc)
make install

4.2 第二步:安装Linux内核头文件#

cd $WORKSPACE/src/linux-5.4.284

# 清理之前的安装(如果有)
make ARCH=arm mrproper

# 安装内核头文件到正确位置
make ARCH=arm INSTALL_HDR_PATH=$PREFIX/$TARGET/usr headers_install

# 验证安装是否成功
echo "=== 验证内核头文件安装 ==="
ls -la $PREFIX/$TARGET/usr/include/linux/errno.h
ls -la $PREFIX/$TARGET/usr/include/linux/limits.h
ls -la $PREFIX/$TARGET/usr/include/asm/

# 创建符号链接确保路径一致性
if [ ! -L $PREFIX/$TARGET/include ] && [ -d $PREFIX/$TARGET/usr/include ]; then
    ln -sf usr/include $PREFIX/$TARGET/include
fi

4.3 第三步:构建GCC第一阶段(Bootstrap)#

mkdir -p $WORKSPACE/build/gcc-stage1
cd $WORKSPACE/build/gcc-stage1

$WORKSPACE/src/gcc-13.2.0/configure \
    --target=$TARGET \
    --prefix=$PREFIX \
    --with-sysroot=$PREFIX/$TARGET \
    --with-newlib \
    --without-headers \
    --disable-nls \
    --disable-shared \
    --disable-multilib \
    --disable-decimal-float \
    --disable-threads \
    --disable-libatomic \
    --disable-libgomp \
    --disable-libquadmath \
    --disable-libssp \
    --disable-libvtv \
    --disable-libstdcxx \
    --enable-languages=c

make -j$(nproc) all-gcc all-target-libgcc
make install-gcc install-target-libgcc

4.6 第四步:完整构建glibc#

mkdir -p $WORKSPACE/build/glibc
cd $WORKSPACE/build/glibc

# 如果之前的构建出现链接错误,先清理
make clean 2>/dev/null || rm -rf *

# 设置交叉编译环境变量
export CC="$TARGET-gcc"
export CXX="$TARGET-g++"
export AR="$TARGET-ar"
export RANLIB="$TARGET-ranlib"

# 重新配置(使用更保守的选项)
$WORKSPACE/src/glibc-2.42/configure \
    --build=$(uname -m)-pc-linux-gnu \
    --host=$TARGET \
    --target=$TARGET \
    --prefix=$PREFIX/$TARGET \
    --with-headers=$PREFIX/$TARGET/usr/include \
    --disable-multilib \
    --disable-nscd \
    --disable-werror \
    --enable-kernel=5.4.0 \
    --disable-profile \
    --without-gd \
    libc_cv_forced_unwind=yes \
    libc_cv_c_cleanup=yes

# 构建glibc(如果并行编译出错,改用单线程)
make -j$(nproc) || make -j1

# 安装glibc
make install 

4.7 第五步:构建完整GCC(GCC第二步)

mkdir -p $WORKSPACE/build/gcc-stage2
cd $WORKSPACE/build/gcc-stage2

# 清理之前可能设置的交叉编译环境变量
unset CC CXX AR RANLIB STRIP

# 重新设置正确的PATH(确保使用刚构建的工具链)
export PATH=$PREFIX/bin:$PATH

# 配置完整的GCC,添加--build参数明确指定构建环境
$WORKSPACE/src/gcc-13.2.0/configure \
    --build=$(uname -m)-pc-linux-gnu \
    --host=$(uname -m)-pc-linux-gnu \
    --target=$TARGET \
    --prefix=$PREFIX \
    --with-sysroot=$PREFIX/$TARGET \
    --disable-nls \
    --enable-languages=c,c++ \
    --disable-multilib \
    --disable-libsanitizer \
    --disable-libssp \
    --enable-threads=posix \
    --enable-shared \
    --enable-__cxa_atexit \
    --with-arch=armv7-a \
    --with-float=hard \
    --with-fpu=vfpv3-d16

make -j$(nproc)
make install

4.8 修改库路径为相对路径

错误
~/cross-toolchain2$ $TARGET-gcc -o test test.c
/home/lx/cross-toolchain2/toolchain/lib/gcc/arm-linux-gnueabihf/13.2.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find /home/lx/cross-toolchain2/toolchain/arm-linux-gnueabihf/lib/libc.so.6 inside /home/lx/cross-toolchain2/toolchain/arm-linux-gnueabihf
/home/lx/cross-toolchain2/toolchain/lib/gcc/arm-linux-gnueabihf/13.2.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find /home/lx/cross-toolchain2/toolchain/arm-linux-gnueabihf/lib/libc_nonshared.a inside /home/lx/cross-toolchain2/toolchain/arm-linux-gnueabihf
/home/lx/cross-toolchain2/toolchain/lib/gcc/arm-linux-gnueabihf/13.2.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find /home/lx/cross-toolchain2/toolchain/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 inside /home/lx/cross-toolchain2/toolchain/arm-linux-gnueabihf
collect2: error: ld returned 1 exit status
~/cross-toolchain2$ 
cd $PREFIX/..
touch fix.sh  &&  chmod +x  fix.sh 
#!/bin/bash
# 设置变量

TARGET=$TARGET
PREFIX=$PREFIX


echo "=== 3. 修复 libc.so 链接脚本 ==="

# 备份原文件

cp $PREFIX/$TARGET/arm-linux-gnueabihf/lib/libc.so $PREFIX/$TARGET/arm-linux-gnueabihf/lib/libc.so.backup

######链接脚本改成这样
vim $PREFIX/$TARGET/arm-linux-gnueabihf/lib/libc.so
/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-armhf.so.3 ) )

5. 测试

5.1 简单测试

#!/bin/bash

# 设置环境变量

export PATH="/home/lx/cross-toolchain/toolchain/bin:$PATH"

TARGET=arm-linux-gnueabihf

echo "=== 1. 检查交叉编译器是否可用 ==="

which ${TARGET}-gcc

${TARGET}-gcc --version | head -1

echo ""

echo "=== 2. 检查 sysroot 配置 ==="

${TARGET}-gcc -print-sysroot

echo ""

echo "=== 3. 检查库搜索路径 ==="

${TARGET}-gcc -print-search-dirs | grep libraries

echo ""

echo "=== 4. 简单编译测试 ==="

cd /tmp

echo 'int main(){return 0;}' > test.c

echo "正在编译..."

if ${TARGET}-gcc test.c -o test.arm; then

  echo "✓ 编译成功!"

  file test.arm

else

  echo "✗ 编译失败,详细信息:"

  ${TARGET}-gcc -v test.c -o test.arm

fi

# 清理

rm -f test.c test.arm

5.2 全面测试

#!/bin/bash

# 设置环境变量
export PATH="/home/lx/cross-toolchain/toolchain/bin:$PATH"
TARGET=arm-linux-gnueabihf

echo "=== 交叉编译工具链全面测试 ==="
echo "时间: $(date)"
echo ""

echo "=== 1. 基本工具测试 ==="
echo "GCC: $(${TARGET}-gcc --version | head -1)"
echo "G++: $(${TARGET}-g++ --version | head -1)"
echo "AS:  $(${TARGET}-as --version | head -1)"
echo "LD:  $(${TARGET}-ld --version | head -1)"
echo "AR:  $(${TARGET}-ar --version | head -1)"
echo "STRIP: $(${TARGET}-strip --version | head -1)"
echo ""

echo "=== 2. C 程序编译测试 ==="
cd /tmp

# C程序测试
cat > test_c.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    printf("Hello from ARM cross-compiled C program!\n");
    printf("sizeof(int) = %zu\n", sizeof(int));
    printf("sizeof(long) = %zu\n", sizeof(long));
    printf("sizeof(void*) = %zu\n", sizeof(void*));
    
    char *str = malloc(100);
    strcpy(str, "Dynamic memory allocation works!");
    printf("%s\n", str);
    free(str);
    
    return 0;
}
EOF

if ${TARGET}-gcc test_c.c -o test_c; then
    echo "✓ C程序编译成功"
    file test_c
    echo "程序大小: $(du -h test_c | cut -f1)"
else
    echo "✗ C程序编译失败"
fi
echo ""

echo "=== 3. C++ 程序编译测试 ==="
cat > test_cpp.cpp << 'EOF'
#include <iostream>
#include <vector>
#include <string>

class TestClass {
private:
    std::string name;
    std::vector<int> numbers;
public:
    TestClass(const std::string& n) : name(n) {
        for(int i = 0; i < 5; i++) {
            numbers.push_back(i * 2);
        }
    }
    
    void display() {
        std::cout << "Hello from ARM cross-compiled C++ program!" << std::endl;
        std::cout << "Object name: " << name << std::endl;
        std::cout << "Numbers: ";
        for(int num : numbers) {
            std::cout << num << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    TestClass obj("ARM-Test");
    obj.display();
    return 0;
}
EOF

if ${TARGET}-g++ test_cpp.cpp -o test_cpp; then
    echo "✓ C++程序编译成功"
    file test_cpp
    echo "程序大小: $(du -h test_cpp | cut -f1)"
else
    echo "✗ C++程序编译失败"
fi
echo ""

echo "=== 4. 静态链接测试 ==="
if ${TARGET}-gcc -static test_c.c -o test_c_static; then
    echo "✓ 静态链接编译成功"
    file test_c_static
    echo "静态程序大小: $(du -h test_c_static | cut -f1)"
else
    echo "✗ 静态链接编译失败"
fi
echo ""

echo "=== 5. 优化编译测试 ==="
if ${TARGET}-gcc -O2 -march=armv7-a -mfpu=neon test_c.c -o test_c_optimized; then
    echo "✓ 优化编译成功"
    file test_c_optimized
    echo "优化程序大小: $(du -h test_c_optimized | cut -f1)"
else
    echo "✗ 优化编译失败"
fi
echo ""

echo "=== 6. 库依赖检查 ==="
echo "动态链接程序的库依赖:"
${TARGET}-objdump -p test_c | grep NEEDED || echo "无法获取依赖信息"
echo ""

echo "=== 7. 程序头信息 ==="
${TARGET}-readelf -h test_c | head -10
echo ""

echo "=== 8. 清理测试文件 ==="
rm -f test_c test_cpp test_c_static test_c_optimized test_c.c test_cpp.cpp
echo "测试文件已清理"
echo ""

echo "=== 测试总结 ==="
echo "✓ 交叉编译工具链工作正常!"
echo "✓ 可以编译 C 和 C++ 程序"
echo "✓ 支持动态和静态链接"
echo "✓ 支持优化编译"
echo "✓ 生成正确的 ARM 架构程序"
echo ""
echo "工具链位置: /home/lx/cross-toolchain/toolchain/"
echo "使用方法: export PATH=\"/home/lx/cross-toolchain/toolchain/bin:\$PATH\""
echo "然后就可以使用 ${TARGET}-gcc 进行交叉编译了!"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值