分享

#C # C 主流编译器

 Baruch 2024-03-08 发布于四川

 文章所涉及内容更多来自网络,在此声明,并感谢知识的贡献者!

C++ 编译过程

C++的编译过程
编写完成一个C/C++程序后,想要运行起来,必须要经过四个步骤:预处理、编译、汇编和链接。每个步骤都会生成对应的文件,如下图所示(注意后缀名):

图片

预处理(Preprocess)
预编译把一些#define的宏定义完成文本替换,然后将#include的文件里的内容复制到.cpp文件里,如果.h文件里还有.h文件,就递归展开。在预处理这一步,代码注释直接被忽略,不会进入到后续的处理中,所以注释在程序中不会执行。
编译(Compile)
编译只是把我们写的代码转为汇编代码,它的工作是检查词法和语法规则,所以,如果程序没有词法或则语法错误,那么不管逻辑是怎样错误的,都不会报错。
编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程。
汇编(Assemble)
汇编过程将上一步的汇编代码(main.s)转换成机器码(machine code),这一步产生的文件叫做目标文件(main.o),是二进制格式。
汇编这一步需要为每一个源文件(本文示例代码中为main.cpp、func.cpp)产生一个目标文件。因此func.cpp也需要执行一次这个汇编过程产生一个func.o文件
链接(Link)
C/C++代码经过汇编之后生成的目标文件(*.o)并不是最终的可执行二进制文件,而仍是一种中间文件(或称临时文件),目标文件仍然需要经过链接(Link)才能变成可执行文件。
既然目标文件和可执行文件的格式是一样的(都是二进制格式),为什么还要再链接一次呢?
因为编译只是将我们自己写的代码变成了二进制形式,它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的。
链接(Link)其实就是一个“打包”的过程,它将所有二进制形式的目标文件(.o)和系统组件组合成一个可执行文件。完成链接的过程也需要一个特殊的软件,叫做链接器(Linker)。
此外需要注意的是:C++程序编译的时候其实只识别.cpp文件,每个cpp文件都会分别编译一次,生成一个.o文件。这个时候,链接器除了将目标文件和系统组件组合起来,还需要将编译器生成的多个.o或者.obj文件组合起来,生成最终的可执行文件(Executable file)。
以本文中的代码为例,将func.o和main.o链接成可执行文件main.out
参考资料
详解C/C++代码的预处理、编译、汇编、链接全过程 - 知乎 (zhihu.com)
https://zhuanlan.zhihu.com/p/618037867

C++ 常见编译器

C++ 编译器类型
GNU的gcc/g++、
LLVM的clang/clang++、
Windows的Mingw/MSVC、
CMake,make的升级版

Microsoft Visual C++ (MSVC)
MSVC 是 Microsoft 提供的 C++ 编译器,用于 Windows 平台。它是 Visual Studio 集成开发环境(IDE)的一部分,支持多种 C++ 标准,包括最新的 C++17 和 C++20 标准。

MinGW
即 Minimalist GNU For Windows。它是一些头文件和端口库的集合,该集合允许人们在没有第三方动态链接库的情况下使用 GCC(GNU Compiler C)产生 Windows32 程序。实际上 MinGW 并不是一个 C/C++ 编译器,而是一套 GNU 工具集合。除开 GCC (GNU 编译器集合) 以外,MinGW 还包含有一些其他的 GNU 程序开发工具 (比如 gawk bison 等等)。

Cygwin
是全面模拟了Linux的接口,提供给运行在它上面的的程序使用,并提供了大量现成的软件,更像是一个平台。
相对的 MingW 也有一个叫 MSys(Minimal SYStem)的子项目,主要是提供了一个模拟 Linux 的 Shell 和一些基本的 Linux 工具。因为编译一个大型程序,光靠一个 GCC 是不够的,还需要有 Autoconf 等工具来配置项目,所以一般在 Windows 下编译 ffmpeg 等 Linux 下的大型项目都是通过Msys 来完成的,当然 Msys 只是一个辅助环境,根本的工作还是 MingW 来做的。

GNU
GNU操作系统是一种由自由软件构成的类 Unix 操作系统,该系统基于 Linux 内核,目标在于建立一个完全相容于UNIX的自由软件环境。
gcc是GCC中的GNU C Compiler(C 编译器)
g++是GCC中的GNU C++ Compiler(C++编译器)

Makefile
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,也可以执行操作系统的命令。
make是一个命令工具,它解释Makefile 中的指令。在Makefile文件中描述了整个工程所有文件的编译顺序、编译规则。Makefile 有自己的书写格式、关键字、函数。像C 语言有自己的格式、关键字和函数一样。而且在Makefile 中可以使用系统shell所提供的任何命令来完成想要的工作。Makefile在绝大多数的IDE 开发环境中都在使用,譬如 Visual C++的 nmake、linux 下的 GNU make、Qt 的 qmake 等等。

CMake
不同的IDE所集成的make工具所遵循的规范和标准都不同,也就导致其语法、格式不同,也就不能很好的跨平台编译,会使得工作繁琐。那么cmake为了解决这个问题而诞生了,其允许开发者指定整个工程的编译流程,在根据编译平台,生成本地化的Makefile和工程文件,最后用户只需make编译即可。简而言之,可以把cmake看成一款自动生成 Makefile 的工具,所以编译流程就变成了:cmake—>make–>用户代码–>可执行文件

图片

 
LLVM
(Low Level Virtual Machine)是一个编译器基础设施项目,它提供了一个编译器的前端和后端之间的“中间表示”(Intermediate Representation,IR),使得编译器可以更容易地进行优化和跨平台操作。Clang和Clang++是LLVM项目中的C、C++、Objective-C和Objective-C++编程语言的编译器前端

Intel C++ Compiler (ICC)
Intel 提供的 C++ 编译器,主要针对 Intel 架构的处理器进行优化。它支持多种 C++ 标准,并提供了针对 Intel 架构的特定优化。

Xcode Clang
对于 macOS 开发者来说,Xcode 是官方的 IDE,它内置了 Clang 编译器,用于编译 C++ 代码。Xcode 提供了丰富的开发工具和界面,方便 macOS 应用的开发。

Clang-CL
Clang-CL 是 Clang 的一个变种,专门用于在 Windows 平台上进行编译,兼容 Microsoft Visual C++。

G++与Clang++ 对比

g++ 与 clang++对比
g++ 与 clang++安装
a. 安装较新版本的 GCC:
您可以通过使用 SCL (Software Collections) 来安装较新版本的 GCC,这将允许您在不影响系统的情况下安装并使用较新的 GCC。
sudo yum install centos-release-scl -y
sudo yum install devtoolset-10-gcc-c++ -y
激活 devtoolset-10 环境以使用新的 GCC 版本:
scl enable devtoolset-10 bash
b. 安装 Clang:
您也可以选择安装 Clang 编译器,它对 C++20 提供了良好的支持。
sudo yum install llvm-toolset-7 -y
激活 llvm-toolset-7 环境以使用 Clang:
scl enable llvm-toolset-7 bash
验证安装:
确保您已经成功安装了新版本的编译器。您可以通过以下命令来验证:
g++ --version
或者
clang++ --version
g++ 与 clang++优缺点
--g++(GCC)优点:
成熟稳定:GCC 是一个历史悠久的编译器,已经经过长时间的发展和测试,因此非常稳定。
广泛支持:GCC 在许多平台上都有良好的支持,包括各种 UNIX/Linux 发行版以及其他操作系统。
标准符合:GCC 对 C++ 标准的支持通常很好,并且在新标准发布后会迅速更新以支持新功能。
错误消息:一些开发人员认为 GCC 的错误消息更易于理解和调试。
社区活跃:GCC 有一个庞大的社区和开发团队,因此可以在广泛的环境中找到支持和资源。
g++ 缺点:
编译速度:相对而言,GCC 编译速度可能会比 Clang 慢一些,尤其是在大型项目中。
模板错误消息:有时 GCC 对模板错误的报告不够清晰,可能需要更多的工作来调试。
--clang++(Clang)优点:
速度:Clang 以其快速的编译速度而闻名,特别是对于大型项目来说,它通常比 GCC 编译速度更快。
清晰的错误消息:Clang 提供了非常清晰和易于理解的错误消息和警告,有助于更轻松地调试代码。
模块化设计:Clang 的设计更加模块化,这使得它更容易与其他工具集成,并且更容易为特定任务创建自定义编译器。
静态分析工具:Clang 自带了一套强大的静态代码分析工具,可以帮助您发现潜在的问题和改进代码质量。
clang++ 缺点:
标准支持:尽管 Clang 的标准支持逐渐改善,但在某些情况下可能会落后于 GCC,尤其是在新标准发布后不久的时候。
非 GNU 工具链兼容性:某些 GNU 工具链特性可能不被 Clang 完全支持,这可能导致在一些项目中的不兼容问题。
g++ 与 clang++
示范代码:
#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::cout << 'Numbers:';
    for (int num : numbers) {
        std::cout << ' ' << num;
    }
    std::cout << std::endl;
    return 0;
}

使用 GCC 10 编译
g++ -std=c++20 -o main main.cpp
使用 Clang 7 编译
clang++ -std=c++2a -o main main.cpp

使用 GCC 10 编译时添加优化选项, 使用优化选项来提高生成的可执行文件的性能
g++ -std=c++20 -O3 -o main main.cpp
使用 Clang 7 编译时添加优化选项
clang++ -std=c++2a -O3 -o main main.cpp

C++ 编译器优化级别

编译器的优化级别
-O0:
含义:无优化。
描述:编译器不执行任何优化,生成的代码与源代码相对应,用于调试目的。
-O1:
含义:基本优化。
描述:编译器执行一些基本的优化,如删除未使用的函数、变量和内联简单函数等。
-O2:
含义:常规优化。
描述:除了 -O1 中的优化之外,编译器还执行更多的优化,如函数内联、循环展开等。这是默认的优化级别。
-O3:
含义:更高级别的优化。
描述:除了 -O2 中的优化之外,编译器还执行更多的优化,如函数内联的限制更松、更激进的循环优化等。这可能会增加编译时间,并且生成的代码可能会更大。
-Os:
含义:优化代码大小。
描述:该选项主要优化生成的目标代码的大小,通常会牺牲一些性能来减小可执行文件的大小。
-Ofast:
含义:快速优化。
描述:这是一个特殊的优化级别,它试图尽可能快地生成代码,通常会关闭一些严格的符合标准的优化,如 IEEE 浮点数语义等。这可能会导致生成的代码在某些情况下不符合标准,并且可能会导致一些未定义行为。

参考资料

参考资料
执行脚本时,Cmake报错 “Unix Makefiles“_cmake error: cmake was unable to find a build prog-CSDN博客
https://blog.csdn.net/qq_42181775/article/details/131534688
详解三大编译器:gcc、llvm 和 clang - 知乎 (zhihu.com)
https://zhuanlan.zhihu.com/p/357803433    
gcc,clang,msvc等编译器有什么区别?- 知乎 (zhihu.com)
https://www.zhihu.com/question/445921363
MinGW到底是个什么ghost_mingw这是啥-CSDN博客
https://blog.csdn.net/lee_ham/article/details/81778581
有没有大佬给我讲解一下MSVC、MINGW,gcc、g++,qmake、cmake的联系和区别是什么?- 知乎 (zhihu.com)
https://www.zhihu.com/question/333560253

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多