编译工具链 之一 基本概念、组成部分、编译过程、命名规则

  编译工具链将程序源代码翻译成可以在计算机上运行的可执行程序。编译过程是由一系列的步骤组成的,每一个步骤都有一个对应的工具。这些工具紧密地工作在一起,前一个工具的输出是后一个工具的输入,像一根链条一样,我们称这一系列工具为编译工具链。编译工具链是与其运行的平台(CPU 架构 和 操作系统)息息相关的。

编译工具链

  软件程序的编译过程由一系列的步骤完成,每一个步骤都有一个对应的工具。这些工具紧密地工作在一起,前一个工具的输出是后一个工具的输入,像一根链条一样,我们称这一系列工具为编译工具链(Toolchain)。编译工具链主要包含 编译器等可执行程序标准库(常用函数通用实现) 两大部分。
在这里插入图片描述
  能独立提供编译工具链的厂家并不多,嵌入式平台则更少,主要就是 ARM、IAR、GNU、LLVM。其中,ARM、IAR 是收费的专用软件,其支持的架构有限,而 GNU 的 GCC 则是一款支持众多架构的开源编译套件;LLVM 则是后起之秀,同样也支持众多架构,目前用的不如 GCC 广泛!如下是常用编译工具链:
在这里插入图片描述

编译器

  第一代编程语言的是汇编语言,因此,第一代编译器是编译汇编语言的。后来,高级语言逐步流行,但是编译工具链中仍然保留了高级语言到汇编语言这一步骤。而原来的汇编语言的编译器被称为汇编器,高级语言的编译器则就称为编译器。

链接器

  高级语言诞生之后,源代码被有效组织为了不同的模块,分别实现在不同的文件中,编译器处理每个源文件,而连机器则负责将各个编译后的二进制文件合并为最终的可执行文件。

实用工具

  除了编译器、链接器等工具,编译工具链中通常还会包含一些用来处理编译后二进制文件的辅助工具。例如,以 GCC 中的 objdumpreadelf 为代表的的用来处理对象文件的工具。

标准库

  标准库提供了一些通用函数的公共实现,绝大多数工具链都是提供一些预编译好的二进制文件(.o 文件),当我们编译自己的程序时,工具链自动以静态链接库的形式引入到我们的最终可执行程序中。这些公共实现的代码通过 include 中各头文件中的函数接口暴露给用户来引用。

通常,这些预编译的文件还会被打包成 存档文件(.a 文件) 来提供(编译工具链中有相应工具来解析执行存档文件,例如,GCC 中的 ar)。

编译过程

  要编译出最终的可执行程序,通常需要编译、链接、转换这三个阶段。其中,编译即编译器将源码翻译成对象文件,链接即链接器将各个对象文件组合成最终可执行程序。现代编译器通常产生一个通用格式(通常是带有调试信息)的最终可执行程序(ELF 文件),然后使用相应的工具从中提取出实际的纯可执行程序。
在这里插入图片描述
  具体到编译器,其编译过程通常也是分为多个阶段的。在编译原理这门课程中,我们学过三段式编译器架构,其在编译时要依次经过词法分析、句法分析、语义分析、中间代码生成、代码优化、代码生成 六大阶段。
在这里插入图片描述

交叉编译

  编译工具链产生可执行程序,但同时,编译工具链本身也是一个可执行程序。构建编译工具链本身时,构建编译工具链使用的平台编译出的编译工具链运行的平台使用编译出的编译工具链编译出的程序运行的平台三者可以完全不同。这三者就对应构建时设置 configure 的三个参数 --build--host--target。下图是 Windows 上的 MinGW 编译器配置信息:
在这里插入图片描述

  • --build:这个参数指出了构建编译工具链使用的平台。如果我们不显示指定这个参数的值,那么这个参数的值就会由 config.guess 自动识别。
  • --host:这个参数指出了编译出的编译工具链运行的平台。这个参数的值一般就等于 --build 的值。
  • --target:这个参数指出了使用编译出的编译工具链编译出的程序运行的平台。

  通常,本地编译工具链一般就是指的 --build = --host = --target 的情况,交叉编译工具链一般是--build = --host--target 的情况。不过,基本很少出现--build--host 的情况(例如,在 Linux 下构建 Windows 下运行的 GCC)。

交叉编译工具链

  在当前平台下(例如 x86 架构的 PC)下,直接编译出来程序(或者库文件),其不可以直接在当前的平台运行(或使用),必须放到目标平台上(例如 ARM)才可以运行(或使用),这个过程就叫做交叉编译,使用的编译工具叫做交叉编译工具链。例如 PC 中的 armcciar特定架构的 GCC特定架构的 LLVM 等。

由于历史原因,我们说到交叉编译工具链通常就是指 GCC

  交叉编译工具链又可以根据是否支持 Linux 系统分为 裸机程序交叉编译工具链Linux 程序交叉编译工具链 这两大类。我们上面的举例中,armcciar 都属于裸机交叉编译工具链;而特定架构的 GCC特定架构的 LLVM 则根据需要可以支持 Linux 系统,也可以不支持 Linux 系统,因此它既有裸机程序交叉编译工具链,也有 Linux 程序交叉编译工具链。

  1. 裸机程序交叉编译工具链不能编译 Linux 应用程序,但是,可以用于编译一些嵌入式实时操作系统(FreeRTOS、RT-Thread 等)
  2. Linux 程序交叉编译工具链不止可以编译 linux 应用程序,也可以编译裸机程序

本地编译工具链

  在当前平台(例如 x86 架构的 PC)下,直接编译出来程序(或者库文件),其可以直接在当前的平台运行(或使用)。这个过程就叫做本地编译,使用的编译工具叫做本地编译工具链(简称编译工具链)。例如 PC 上的 VCGCCLLVMTCC 等。

The xPack Project

  The xPack Project 是一个开源项目,其提供了一系列开发工具(重点是裸机下的 C/C++ 相关的)在不同平台的下的构建实例,其中就包含各平台的 GCC 交叉编译工具链,它使用一个多版本依赖管理器来管理各个实例。
在这里插入图片描述
  实际开发中,我们经常会独立使用它提供的某些工具。例如,Eclipse 的嵌入式 C/C++ 插件 Eclipse Embedded CDT 就包含一些 xPack 提供的工具,以此来实现创建、构建、调试和管理 Arm 和 RISC-V 项目。

  • xPack Windows Build Tools:包括在 Windows 上执行构建所需的额外工具( makerm 等)

  • xPack GNU Arm Embedded GCC:ARM 维护的官方 GNU ARM 嵌入工具链的一个代替,可以用于 Windows,MacOS和 GNU/Linux 平台。

  • xPack GNU RISC-V Embedded GCC:裸机 RISC-V GCC 发行版,由 SiFive 维护。Windows、macOS 和 GNU/Linux 都有可用的二进制文件。

  • xPack OpenOCD:OpenOCD 的一个新发行版,为更好/更方便地与 OpenOCD 调试插件集成而定制。Windows、macOS 和GNU/Linux 都有可用的二进制文件。

  • xPack QEMU Arm:QEMU(开源机器仿真器)的一个分支,旨在为 Eclipse Embedded CDT 中 的Cortex-M 仿真提供支持。Windows、macOS 和 GNU/Linux都有可用的二进制文件。

GCC

  我们使用最多交叉编译工具链就是特定架构的 GNU 工具链,也就是我们我们常说的 GCC 交叉编译工具链。注意,armcciar 也属于交叉编译工具链,但是,一说起交叉编译工具链,大家往往首先想到的就是 GCC,例如,ARM 官方提供的 Arm GNU Toolchain。

  随着开源运动的兴起,自由软件基金会开发了自己的开源免费的 C 语言编译器 GNU C Compiler,简称 GCC。GCC 中提供了 C Preprocessor 这个 C 语言的预处理器,简称 CPP。后来 GCC 又加入了对 C++ 等其它语言的支持,所以他的名字也改为 GNU Compiler Collection。

命名规则

  一般来说,交叉编译工具链的命名规则是:arch [-vendor] [-os] [-(gnu)abi]-*。但是,关于这个规则,我并没有找到在哪份官方资料上有介绍,实际有些交叉编译工具链也确实不符合上面的命名规则。如果有谁在官方资料上见到过此规则的详细描述,一定要私信告诉我。

  • arch: 表示编译工具链支持的体系架构,如 ARM、MIPS、RISC-V
  • vendor: 表示工具链提供商,没有 vendor 时,用 none 代替。
  • os: 表示工具链是有操作系统支持的,其编译出的程序可以在 os 给出的操作系统上运行,没有 os 支持时,也用 none 代替,表示裸机。如果同时没有 vendor 和 os 支持,则只用一个 none 代替。例如 arm-none-eabi 中的 none 表示既没有 vendor 也没有 os 支持。目前取值就只有以下两种:
    • none
      • C 库通常是 newlib
      • 提供不需要操作系统的 C 库服务
      • 允许为特定硬件目标提供基本系统调用
      • 可以用来构建 Bootloader 或 Linux Kernel,不能构建 Linux 用户空间代码
    • linux
      • 用于 Linux 操作系统的开发
      • linux 特有的 C 库的选择:glibc、uClibc-ng、musl
      • 支持 Linux 系统调用
      • 可以用来构建 Linux 用户空间代码,但也可以构建裸机代码,如 Bootloader 或 Linux Kernel
  • abi: 应用二进制接口(Application Binary Interface)
    • eabi: 嵌入式应用二进制接口(Embedded Application Binary Interface,EABI),这个是好像是 ARM 搞的一个标准,注意,AArch32 和 AArch64 的 EABI 并不相同。
    • gnu: 这个其实是早期 GNU 针对 AArch32 架构使用的名字,后来改名字为 gnueabi
    • gnueabi: 其实就是嵌入式应用二进制接口(Embedded Application Binary Interface,EABI),只不过是 GNU 出品的。
    • elf: 这个通常用在 64 位裸机架构的编译工具链中

  由于 ARM 的绝对市场地位,导致了在网上搜索交叉编译工具链基本都和 ARM 有关系。这个命名规则就源自 ARM,其他架构提供的交叉编译工具链也基本是按照这个命名规则来命名的。

组成部分

  GUN 交叉编译工具链中有三个核心组件:Binutils、GCC、C library,如果需要支持 Linux,则还有个 Linux kernel headers。在源代码组织上他们是相互独立的,需要单独进行交叉编译。

  • Binutils:GNU Binutils 是一个二进制工具的集合。
    • 官网:https://www.gnu.org/software/binutils/。
    • 获取源代码:git clone git://sourceware.org/git/binutils-gdb.git 或者 https://ftp.gnu.org/gnu/binutils,目前最新版是 2.39
    • 主要工具
      • ld:链接器
      • as :汇编器
      • gold:一个新的,更快的,ELF链接器。
    • 调试/分析工具和其他工具
      • addr2line :将地址转换为文件名和行号。
      • ar :一个用于创建、修改、提取存档的实用工具
      • c++filt :过滤器要求编码的c++符号
      • dlltool :用于构建和使用 dll 的文件
      • elfedit :用于编辑 ELF 格式文件
      • gprof :显示分析信息
      • gprofng :收集和显示应用程序性能数据
      • nlmconv :将目标代码转换为 NLM
      • nm :列出目标文件中的符号
      • objcopy :复制和翻译目标文件
      • objdump :显示来自目标文件的信息
      • ranlib :生成归档文件内容的索引
      • readelf :显示来自任何ELF格式目标文件的信息
      • size :列出对象或存档文件的节大小
      • strings :列出文件中的可打印字符串
      • strip :丢弃符号
      • windmc :一个 Windows 兼容的消息编译器
      • windres :Windows 资源文件的编译器
    • 需要针对每种 CPU 架构进行配置
  • gcc:GNU Compiler Collection
    • C、C++、Fortran、Go 等编译器前端
    • 各种 CPU 架构的编译器后端
    • Provides:
      • 编译器本身。例如 cc1 for C、cc1plus for C++

      • 编译器调用程序。gcc、g++ 不但调用编译器本身,也调用 binutils 中的 汇编器、连接器

        不要被 gcc 这个名字误导,它其实是个 wrapper,会根据输入文件调用一系列其他程序。国外资料中被称为 compiler driver,国内有些资料称为 引导器。

      • 目标库:libgcc(gcc 运行时)、libstdc ++(c ++ 库)、libgfortran(fortran运行时)

      • 标准 c++ 库的头文件

    • 构建 gcc 比构建 binutils 要复杂的多
  • Linux Kernel headers:构建需要支持 Linux 系统时必须提供。这些头文件定义了用户空间与内核之间的接口(系统调用、数据结构等)。
    • 为了构建一个 C 库,需要 Linux 内核头文件中系统调用号的定义、各种结构类型和定义。
    • 在内核中,头文件被分开:
      • 用户空间可见的头文件,存储在 uapi 目录中:include/uapi/arch/<ARCH>/include/uapi/asm
      • 内部的内核头文件
    • 在安装过程中需要使用
      • 安装包括一个清理过程,用于从头文件中删除特定于内核的结构体
      • 从 Linux 4.8 开始,安装 756 个头文件
      • 内核到用户空间 ABI 通常是向后兼容的。Kernel headers 的版本必须等于或者小于目标 Linux 的版本
  • C library
    • 提供 POSIX 标准函数的实现,以及其他几个标准和扩展

    • 基于 Linux 系统调用

    • 几个可用的实现

      • glibc:The GNU C Library 是 Linux C 库的事实标准,我们常见的 Linux 发行版中都使用它。支持众多的架构和操作系统,但是不支持没有 MMU 的平台,不支持静态链接。早些年由于硬件限制及 glibc 本身太大基本不能直接用于嵌入式,如今貌似也可以了。

      • uClibc-ng:以前叫 uClibc,始于 2000 年,支持非常灵活的配置。支持架构很多(包括一些 glibc 不支持的),但是仅支持 Linux 操作系统。支持多种没有 MMU 的架构,如 ARM noMMU、Blackfin 等,支持静态链接。

        STM32F MCU 没有 MMU,其嵌入式 Linux 环境中编译工具链就是用的它。

      • musl:始于 2011 年,开发非常积极,最近添加了对于 noMMU 的支持。它非常小,尤其是在静态链接时。兼容性好,并且严格遵循 C 标准。

      • bionic:安卓系统使用

      • 其他一些特殊用途的:newlib(用于裸机)、dietlibc、klibc

      musl 的作者对于 Linux 常用的这几个库做了一个对比,以下是对比情况图:
      在这里插入图片描述

    • 在编译和安装之后,提供了:

      • 动态链接器 ld.so
      • C 库本身 libc.so,及其配套库:libm、librt、libpthread、libutil、libnsl、libresolv、libcrypt
      • C 库的头文件:stdio.hstring.h 等等。

LLVM

  LLVM 是一组工具链和编译器技术。回顾 GCC 的历史,虽然它取得了巨大的成功,但开发 GCC 的初衷是提供一款免费的开源的编译器,仅此而已。可后来随着 GCC 支持了越来越多的语言,GCC 架构的问题也逐渐暴露出来。

  传统编译器的工作原理基本上都是三段式的,可以分为前端(Frontend)、优化器(Optimizer)、后端(Backend)。前端负责解析源代码,检查语法错误,并将其翻译为抽象的语法树(Abstract Syntax Tree);优化器对这一中间代码进行优化,试图使代码更高效;后端则负责将优化器优化后的中间代码转换为目标机器的代码,这一过程后端会最大化的利用目标机器的特殊指令,以提高代码的性能。

虽然这种三段式的编译器有很多优点,并且被写到了教科书中,但是在实际中这一结构却从来没有被完美实现过。

   LLVM 作为后起之秀,从开始就是按照前端(Frontend)、优化器(Optimizer)、后端(Backend)的三段式进行设计,整个编译器框架非常符合人们对于编译器的设计以及非常容易理解和学习。LLVM 的在很大程度上兼容 GNU,本文主要介绍 GNU。

  1. LLVM 的命名最早源自于底层虚拟机(Low Level Virtual Machine)的首字母缩写,但这个项目并不局限于创建一个虚拟机,开发者因而决定放弃这个缩写的意涵。现在 LLVM 是一个专用名词,表示编译器框架整个项目。
  2. 目前,很多平台都开始转投 LLVM 了,例如苹果、安卓、ARM 等等

参考

  1. https://elinux.org/Toolchains
  2. https://blog.csdn.net/linczone/article/details/45894181
  3. https://www.codenong.com/cs109691911/
  4. https://www.cnblogs.com/albertzheng/p/16695616.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/168756.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity 单例-接口模式

单例-接口模式 使用接口方式实现的单例可以继承其它类&#xff0c;更加方便 using System.Collections; using System.Collections.Generic; using UniRx; using UniRx.Triggers; using UnityEngine; namespace ZYF {public interface ISingleton<TMono> where TMono : M…

力扣第55题 跳跃游戏 c++ 贪心 + 覆盖 加暴力超时参考

题目 55. 跳跃游戏 中等 相关标签 贪心 数组 动态规划 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &…

Unity编辑器扩展 --- AssetPostprocessor资源导入自动设置

unity导入资源的编辑器设置: 防止策划资源乱导入,资源导入需要的格式&#xff0c;统一资源管理 AssetPostprocessor资源导入管线 AssetPostprocessor用于在资源导入时自动做一些设置&#xff0c;比如当导入大量图片时&#xff0c;自动设置图片的类型&#xff0c;大小等。Ass…

AlDente Pro for Mac: 掌控电池充电的终极解决方案

你是否曾经为了保护你的MacBook的电池&#xff0c;而苦恼于无法控制它的充电速度&#xff1f;AlDente Pro for Mac 是一款专为Mac用户设计的电池管理工具&#xff0c;它能帮助你解决这个问题。 AlDente Pro for Mac 是一款电池最大充电限制软件&#xff0c;它能够让你自由地设…

【数据结构与算法】二叉树的运用要点

目录 一&#xff0c;二叉树的结构深入认识 二&#xff0c;二叉树的遍历 三&#xff0c;二叉树的基本运算 3-1&#xff0c;计算二叉树的大小 3-2&#xff0c;统计二叉树叶子结点个数 3-3&#xff0c;计算第k层的节点个数 3-4&#xff0c;查找指定值的结点 一&#xff0c;二叉…

ResNet论文精读,代码实现与拓展知识

文章目录 ResNet 论文精读代码实现网络可视化代码 拓展知识 ResNets残差的调参残差链接的渊源残差链接有效性的解释ResNet 深度ResNeXt代码实现 能够提点的技巧「Warmup」「Label-smoothing」「Random image cropping and patching」「Knowledge Distiallation」「Cutout」「Ra…

Centos 7 Zabbix配置安装

前言 Zabbix是一款开源的网络监控和管理软件&#xff0c;具有高度的可扩展性和灵活性。它可以监控各种网络设备、服务器、虚拟机以及应用程序等&#xff0c;收集并分析性能指标&#xff0c;并发送警报和报告。Zabbix具有以下特点&#xff1a; 1. 支持多种监控方式&#xff1a;可…

SAP POorPI RFC接口字段调整后需要的操作-针对SP24及以后的PO系统

文章目录 问题描述解决办法 问题描述 在SAP系统的RFC接口结构中添加了字段&#xff0c;RFC也重新引用到了PO系统&#xff0c;Cache和CommunicationChannel都刷新或启停了&#xff0c;但是新增的字段在调用接口的时候数据进不到SAP系统&#xff0c;SAP系统内的值也出不来。经过…

postgresql14-模式的管理(三)

基本概念 postgresql成为数据库管理系统DBMS&#xff0c;在内存中以进程的形态运行起来成为一个实例&#xff0c;可管理多个database。 数据库databases&#xff1a;包含表、索引、视图、存储过程&#xff1b; 模式schema&#xff1a;多个对象组成一个模式&#xff0c;多个模…

nodejs+vue大学生社团管理系统

通过软件的需求分析已经获得了系统的基本功能需求&#xff0c;根据需求&#xff0c;将大学生社团管理系统平台功能模块主要分为管理员模块。管理员添加社团成员管理、社团信息管理&#xff0c;社长管理、用户注册管理等操作。 目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1…

JVM的几个面试重点

JVM的内存区域划分 JVM类加载机制 前言 Java程序最开始是一个 .java 的文件&#xff0c;JVM把它编译成 .closs 文件&#xff08;字节码文件&#xff09;&#xff0c;运行 Java 程序&#xff0c; JVM 就会读取 .class 文件&#xff0c;把文件内容读取到内存中&#xff0c;构造出…

多线程与高并发

1.线程创建的3种方式 2.线程的状态切换步骤 3.线程的5中状态 Java中的线程的生命周期大体可分为5种状态。 1. 新建(NEW)&#xff1a;新创建了一个线程对象。 2. 可运行(RUNNABLE)&#xff1a;线程对象创建后&#xff0c;其他线程(比如main线程&#xff09;调用了该对象的sta…

通义大模型使用指南之通义千问

一、注册 我们可以打开以下网站&#xff0c;用手机号注册一个账号即可。 通义大模型 (aliyun.com) 二、使用介绍 如图&#xff0c;我们可以看到有三个大项功能&#xff0c;通义千问、通义万相、通义听悟。下来我们体验一下通义千问的功能。 1、通义千问 通义千问主要有两个功能…

北邮22级信通院数电:Verilog-FPGA(6)第六周实验:全加器

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 先抄作业&#xff01;&#xff01;&#xff01;&am…

人工智能算法PPT学习

YOLO You only look once 是一种图像识别算法&#xff0c;速度较快。高效、灵活、泛化性能好&#xff0c;在工业中较为受欢迎。 图像金字塔 一幅图像的多个不同分辨率的子图构成的图像集合。是通过一个图像不断的降低采样率产生的&#xff0c;最小的图像可能仅仅有一个像素点…

如何在Ubuntu下安装RabbitMQ服务并异地远程访问?

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

Elasticsearch 8.X 分词插件版本更新不及时解决方案

1、关于 Elasticsearch 8.X IK 分词插件相关问题 球友在 ElasticSearch 版本选型问题中提及&#xff1a;如果要使用ik插件&#xff0c;是不是就使用目前最新的IK对应elasticsearch的版本“8.8.2”&#xff1f; https://github.com/medcl/elasticsearch-analysis-ik/releases/ta…

强大的虚拟机软件 VMware Fusion Pro 13中文最新 for mac

VMware Fusion Pro是一款虚拟化软件&#xff0c;它允许在Mac电脑上同时运行Windows和其他操作系统&#xff0c;而无需重启电脑&#xff0c;它采用了领先的虚拟化技术&#xff0c;能够保证在Mac电脑在同时运行多个操作系统时表现出极高的效率和稳定性。 VMware Fusion Pro具有以…

计算机网络的七层结构、五层结构和四层结构

为什么要分层&#xff1a; 这个就和我们平常写程序一样&#xff0c;高内聚、低耦合。将网络进行分层我们就可以根据每一层的功能分开开发设计&#xff0c;将复杂的网络问题分解为更简单和清晰的小问题&#xff0c;方便设计、实现和标准化。无需在意其他层是如何实现的&#xff…

maven仓库改国内源

今天准备复现漏洞环境&#xff0c;发现太慢&#xff0c;需要配置国内源 file -> settings 搜索maven 修改settings.xml&#xff0c;这里的需要修改两个文件 1.上图的settings.xml文件 2.idea的maven模块 settings.xml文件将原来的注释掉&#xff0c;然后把阿里的添加上&…