36、构建和使用GNU GCC交叉编译器指南

构建和使用GNU GCC交叉编译器指南

1. 实时C++环境编程要点

在实时C++环境中,程序运行时间最好控制在几百微秒甚至几毫秒内。在多任务环境里,编写简短、快速的程序序列是更好的选择,这样可以快速处理信息或为状态机提供服务,并迅速将控制权交还给系统中的其他进程。中断服务程序应简洁高效,将运行时间控制在既定范围内,通常能使软件更具可预测性,提高其质量和可靠性。

2. 构建GCC交叉编译器的原因

构建GCC交叉编译器可能有多种原因,比如获取最新版本的编译器、启用额外的语言特性或支持其他语言等。下面将详细介绍为8位微控制器目标构建GNU GCC交叉编译器的步骤。

3. GCC的先决条件

构建GCC需要满足一些先决条件,即在构建GCC之前,必须安装并确保某些库可供构建系统使用。如果缺少任何先决条件,则需要在构建GCC之前安装或从源代码构建这些库。不同时期构建GCC的先决条件有所不同:
| 构建时期 | 先决条件 |
| ---- | ---- |
| 某一时期 | GMP(GNU多精度库)、MPFR(GNU多精度浮点库)、MPC(用于复数多精度算术的C库)、PPL(Parma多面体库,用于抽象几何多面体表示)、Binutils(交叉编译器的二进制实用工具,如链接器、汇编器、对象转储、C++名称解码器等) |
| 第二版编写时 | GMP、MPFR、MPC、ISL(整数集库,用于操作整数集,GCC用于其石墨循环优化,构建ISL需要安装CLooG库)、Binutils |

GCC需要这些看似奇特的数学函数库作为先决条件,是因为GMP、MPFR和MPC中的多精度函数用于编译时计算浮点数学表达式,而PPL(或ISL)中的几何多面体表示用于高级优化,包括程序循环分析、并行化和向量化。虽然二进制实用工具可被视为编译器的一部分,但这里将其作为先决条件,是因为构建GCC时需要使用它们,所以必须在构建GCC之前先构建并安装这些二进制实用工具。

4. 开始构建

构建GCC的先决条件和GCC本身可能需要数小时的手动工作,有时这项工作可能很繁琐,涉及复杂的命令行、详细的操作系统操作和仔细的监控。因此,最好在有足够时间和精力的情况下进行这项工作。构建、安装和使用GCC是一个复杂的话题。

构建GNU交叉编译器有时会成功,有时会失败。失败的原因可能包括先决条件缺失或构建不当、二进制实用工具或编译器源代码存在特定版本和目标的缺陷。经验丰富的编译器构建者通常会对新编译器版本的源代码进行补丁修复,以纠正小缺陷,并在后续版本中集成这些补丁以修复编译器漏洞。普通的编译器构建者和用户应避免进行如修补源代码这样的高级编译器开发工作,可能需要进行一些试验和错误,以找到能够和谐构建在一起的先决条件、二进制实用工具和编译器版本的组合。

整个构建过程,包括所有先决条件、二进制实用工具和GCC,最好在一个根目录下进行组织。不建议在组件的源树目录中进行构建,对于每个组件,我们使用两个目录,一个用于组件的源树,另一个是源树旁边的同级对象目录,用于进行构建。

首先,创建一个用于所有构建的根目录,例如:

# 创建根目录
mkdir /home/tmp
5. 构建各个组件
5.1 构建GMP(版本5.0.5)
# 进入根目录
cd /home/tmp
# 获取GMP源代码并解压到/home/tmp
# 创建GMP同级目录
mkdir objdir-gmp-5.0.5
# 进入GMP同级对象目录
cd objdir-gmp-5.0.5
# 配置GMP
../gmp-5.0.5/configure --prefix=/usr/local \
--build=i686-pc-mingw32 --disable-shared \
--enable-static --enable-cxx CPPFLAGS="-fexceptions"
# 编译GMP
make --jobs=2
# 安装GMP
make install
5.2 构建MPFR(版本3.1.1)
# 进入根目录
cd /home/tmp
# 获取MPFR源代码并解压到/home/tmp
# 创建MPFR同级目录
mkdir objdir-mpfr-3.1.1
# 进入MPFR同级对象目录
cd objdir-mpfr-3.1.1
# 配置MPFR
../mpfr-3.1.1/configure --prefix=/usr/local \
--build=i686-pc-mingw32 --disable-shared \
--enable-static --with-gmp=/usr/local
# 编译MPFR
make --jobs=2
# 安装MPFR
make install
5.3 构建MPC(版本0.9)
# 进入根目录
cd /home/tmp
# 获取MPC源代码并解压到/home/tmp
# 创建MPC同级目录
mkdir objdir-mpc-0.9
# 进入MPC同级对象目录
cd objdir-mpc-0.9
# 配置MPC
../mpc-0.9/configure --prefix=/usr/local \
--build=i686-pc-mingw32 --disable-shared \
--enable-static --with-gmp=/usr/local \
--with-mpfr=/usr/local
# 编译MPC
make --jobs=2
# 安装MPC
make install
5.4 构建PPL(版本0.12.1)
# 进入根目录
cd /home/tmp
# 获取PPL源代码并解压到/home/tmp
# 创建PPL同级目录
mkdir objdir-ppl-0.12.1
# 进入PPL同级对象目录
cd objdir-ppl-0.12.1
# 配置PPL
../ppl-0.12.1/configure --prefix=/usr/local \
--build=i686-pc-mingw32 --disable-shared \
--enable-static CPPFLAGS="-fexceptions" \
--with-gmp=/usr/local
# 编译PPL
make --jobs=2
# 安装PPL
make install
5.5 构建ISL

在MinGW/MSYS中构建ISL(必要时还需构建CLooG)的步骤与构建PPL类似,最新的构建说明可在互联网上找到。

5.6 构建交叉编译器的二进制实用工具(Binutils,版本2.22)
# 进入根目录
cd /home/tmp
# 获取binutils源代码并解压到/home/tmp
# 创建binutils同级目录
mkdir objdir-binutils-2.22-avr-unknown-elf
# 进入binutils同级对象目录
cd objdir-binutils-2.22-avr-unknown-elf
# 配置binutils
../binutils-2.22/configure \
--prefix=/usr/local/gcc-4.6.2-avr-unknown-elf \
--target=avr-unknown-elf --build=i686-pc-mingw32 \
--disable-__cxa_atexit --disable-nls \
--disable-threads --disable-shared \
--enable-static --disable-win32-registry \
--disable-sjlj-exceptions --with-dwarf2 \
--with-gmp=/usr/local --with-mpfr=/usr/local \
--with-mpc=/usr/local --with-ppl=/usr/local
# 编译binutils
make --jobs=2
# 安装binutils
make install

下面是构建过程的mermaid流程图:

graph LR
    A[创建根目录/home/tmp] --> B[构建GMP]
    B --> C[构建MPFR]
    C --> D[构建MPC]
    D --> E[构建PPL]
    E --> F[构建ISL(及CLooG)]
    F --> G[构建Binutils]
    G --> H[构建GCC]
5.7 构建交叉编译器(GCC版本4.6.2)
# 进入根目录
cd /home/tmp
# 获取GCC源代码并解压到/home/tmp
# 获取newlib源代码并解压到/home/tmp
# 创建GCC同级目录
mkdir objdir-gcc-4.6.2-avr-unknown-elf
# 复制newlib源代码到GCC源树
cd /home/tmp/newlib-1.20.0
cp -r newlib libgloss ../gcc-4.6.2
# 返回GCC同级对象目录
cd /home/tmp/objdir-gcc-4.6.2-avr-unknown-elf
# 配置GCC
../gcc-4.6.2/configure \
--prefix=/usr/local/gcc-4.6.2-avr-unknown-elf \
--target=avr-unknown-elf --build=i686-pc-mingw32 \
--enable-languages=c,c++ --with-newlib \
--disable-__cxa_atexit --disable-nls \
--disable-threads --disable-shared --enable-static \
--disable-win32-registry --disable-sjlj-exceptions \
--with-dwarf2 --with-gmp=/usr/local \
--with-mpfr=/usr/local --with-mpc=/usr/local \
--with-ppl=/usr/local
# 编译GCC
make --jobs=2
# 安装GCC
make install
6. 使用交叉编译器

假设已经成功完成GCC先决条件和GCC的构建工作,那么GCC的构建结果应位于安装目录 /usr/local/gcc-4.6.2-avr-unknown-elf 中。需要注意的是,MinGW/MSYS中的 /usr 目录可能是 /msys/1.0 等目录的别名。

构建结果中会安装两种版本的编译器工具,一种是带有修饰名称的工具,另一种是未修饰的普通名称的工具。例如,带有修饰名称的 g++ 版本为 bin/avr-unknown-elf-g++.exe ,未修饰名称的 g++ 版本为 avr-unknown-elf/bin/g++.exe 。这两种版本的工具链功能相同,但最好一次只使用其中一种,应根据交叉开发的需求选择并始终使用同一版本。

使用GCC时,可以将编译器可执行文件的路径添加到shell的 PATH 变量中,方便使用。在MinGW/MSYS中,可以在 /etc/profile 文件中添加交叉编译器的路径信息到 PATH 变量;在其他类Unix系统中,可以在 /home/.bashrc 文件中添加。

有些开发者建议不要移动GCC的安装目录,但如果将整个编译器的目录树作为一个整体移动,是可以将完全构建好的GCC安装到其他位置的。在MinGW/MSYS中构建的GCC安装也可以在MinGW/MSYS环境之外使用,例如通过使用另一个命令行界面。此时,需要将MinGW/MSYS安装中的几个动态链接库包含在编译器二进制文件的路径或构建环境中,参考项目的配套代码中使用了这种技术。

综上所述,按照上述步骤可以完成GCC交叉编译器的构建和使用,在实际操作中要注意各组件的版本兼容性和构建过程中的细节。

构建和使用GNU GCC交叉编译器指南

7. 工具版本及功能总结

为了更清晰地了解构建过程中所涉及的各个工具的版本和功能,下面以表格形式进行总结:
| 工具名称 | 版本 | 功能描述 |
| ---- | ---- | ---- |
| GMP | 5.0.5 | GNU多精度库,用于编译时计算浮点数学表达式 |
| MPFR | 3.1.1 | GNU多精度浮点库,辅助编译时浮点计算 |
| MPC | 0.9 | 用于复数多精度算术的C库,支持复杂数学计算 |
| PPL | 0.12.1 | Parma多面体库,用于抽象几何多面体表示,进行高级优化,如程序循环分析、并行化和向量化 |
| ISL | - | 整数集库,用于操作整数集,GCC用于其石墨循环优化(构建ISL需要安装CLooG库) |
| Binutils | 2.22 | 交叉编译器的二进制实用工具,提供如链接器、汇编器、对象转储、C++名称解码器等工具 |
| GCC | 4.6.2 | 交叉编译器,为 avr - unknown - elf 交叉目标构建,使用newlib库 |
| newlib | 1.20.0 | 为GCC提供标准库支持 |

8. 常见问题及解决思路

在构建和使用GCC交叉编译器的过程中,可能会遇到一些常见问题,以下是一些问题及相应的解决思路:
- 先决条件缺失或构建不当 :检查各个先决条件库是否正确安装,可通过重新安装或从源代码构建缺失的库来解决。例如,如果提示GMP库缺失,可按照构建GMP的步骤重新进行构建和安装。
- 编译失败 :查看编译过程中的错误信息,可能是由于编译器版本与目标不兼容、源代码存在缺陷等原因导致。可以尝试更换编译器版本或对源代码进行补丁修复,但普通用户应谨慎进行补丁操作。
- 工具无法找到 :检查工具的安装路径是否正确,是否已将编译器可执行文件的路径添加到 PATH 变量中。若未添加,可按照前面介绍的方法在相应的配置文件中添加路径信息。

9. 构建过程的优化建议

为了提高构建效率和成功率,可考虑以下优化建议:
- 并行编译 :在 make 命令中使用 --jobs 参数,如 make --jobs = 2 ,可以指定使用多个进程进行编译,加快编译速度。根据系统的CPU核心数,可以适当增加进程数量。
- 清理缓存 :在每次构建之前,可清理之前构建产生的缓存文件,避免缓存文件影响新的构建过程。例如,在进入组件的同级对象目录后,可执行 make clean 命令进行清理。
- 使用脚本自动化构建 :将整个构建过程编写成脚本,减少手动操作的繁琐和错误。以下是一个简单的示例脚本,用于构建GMP:

#!/bin/bash
# 创建根目录
mkdir /home/tmp
cd /home/tmp
# 获取GMP源代码并解压到/home/tmp
# 创建GMP同级目录
mkdir objdir - gmp - 5.0.5
cd objdir - gmp - 5.0.5
# 配置GMP
../gmp - 5.0.5/configure --prefix = /usr/local \
--build = i686 - pc - mingw32 --disable - shared \
--enable - static --enable - cxx CPPFLAGS = "-fexceptions"
# 编译GMP
make --jobs = 2
# 安装GMP
make install
10. 实际应用案例

假设我们要开发一个基于 avr - unknown - elf 目标的嵌入式项目,使用已构建好的GCC交叉编译器。以下是一个简单的开发流程:
1. 创建项目目录

mkdir my_avr_project
cd my_avr_project
  1. 编写源代码 :创建一个简单的C++文件,例如 main.cpp
#include <iostream>
int main() {
    std::cout << "Hello, AVR!" << std::endl;
    return 0;
}
  1. 编译源代码 :使用构建好的GCC交叉编译器进行编译:
avr - unknown - elf - g++ main.cpp -o main.elf
  1. 烧录到目标设备 :使用相应的烧录工具将生成的 main.elf 文件烧录到 avr 微控制器中。
11. 总结与展望

通过本文详细介绍的步骤,我们可以成功构建和使用GNU GCC交叉编译器,满足不同目标平台的开发需求。在构建过程中,要注意各个组件的版本兼容性、构建参数的配置以及环境变量的设置。同时,遇到问题时要仔细分析错误信息,采取合理的解决方法。

未来,随着技术的不断发展,GCC编译器可能会有更多的功能和优化,构建过程也可能会更加简化和自动化。我们可以持续关注GCC的官方更新,及时了解新的特性和改进,以提高开发效率和软件质量。

下面是一个总结整个构建和使用过程的mermaid流程图:

graph LR
    A[准备工作:了解需求和环境] --> B[构建先决条件库]
    B --> C[构建Binutils]
    C --> D[构建GCC]
    D --> E[使用GCC进行开发]
    E --> F[调试和优化项目]
    F --> G[部署到目标设备]

总之,掌握GCC交叉编译器的构建和使用是进行嵌入式开发等领域的重要技能,希望本文能为开发者提供有价值的参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值