背景知识
C++的编译其实严格来说应该是一个(build)的过程,它包含几个子步骤:
- 预处理 (preprocessing)
- 编译 (compiling)
- 链接 (linking)
预处理
预处理的工作主要有四种:
- 宏替换(#define)
- 条件编译(#if,#ifndef,#ifdef,#endif,#undef )
- 文件包含(#include)
- 布局控制(#progma)
编译
编译意味着把一个源文件(.cpp)转变成一个对象文件(object,.o 或 .obj)。
一个对象文件会把你程序里的每一个函数,封装成一个计算机处理器能理解的形式——机器指令。
链接
链接(Linking),是把一堆对象文件和库(有时也可能仅仅是一个对象文件,但也需要链接)创建成一个单独的可执行文件(比如 .exe 或 .dll)。
链接器通过一种适当的格式创建一个可执行的文件,并传递每个独立的对象文件内容到一个可执行的结果。链接器也处理含有对象文件源代码之外的其它函数的引用,比如 C++ 标准库里的函数。当你调用了一个 C++ 标准库的函数,如 cout <<“Hi”,你就在使用一个自己代码中没有定义的函数,它被定义在一个相关的对象文件中,但这是由编译器提供的,并不属于你。在编译时,编译器知道这个函数是有效的,因为你引出了 iostream 头文件,但由于这个函数不是 cpp 文件的一部分,编译器就会在调用树(call tree)留下一个存根(stub),链接器会遍历对象文件,针对每一个存根,它会找到正确的函数地址,然后从已链接过的其它对象文件中,用正确的地址替换掉对应的存根。
这个过程有时也叫做修正(fixup)。
Clang\GCC\gcc\g++
Mac 下,如果你安装了 Xcode ,那么你就拥有了 LLVM 和 GCC 两大编译工具。首先了解GCC:
GCC是 GNU 编译器套装(英语:GNU Compiler Collection,缩写为** GCC**),指一套编程语言编译器,以 GPL 及 LGPL 许可证所发行的自由软件,也是 GNU 项目的关键部分,也是 GNU 工具链的主要组成部分之一。GCC(特别是其中的 C 语言编译器)也常被认为是跨平台编译器的事实标准。1985 年由理查德 · 马修 · 斯托曼开始发展,现在由自由软件基金会负责维护工作。
要先明确一个点:GCC和gcc以及g++指代是不同的。
GCC:GNU Compiler Collection(GUN 编译器集合),它可以编译 C、C++、JAV、Fortran、Pascal、Object-C、Ada 等语言。
gcc 是 GCC 中的 GUN C Compiler(C 编译器)
g++ 是 GCC 中的 GUN C++ Compiler(C++ 编译器)
一个有趣的事实就是,就本质而言,gcc 和 g++ 并不是编译器,也不是编译器的集合,它们只是一种驱动器,根据参数中要编译的文件的类型,调用对应的 GUN 编译器而已,比如,用 gcc 编译一个 c 文件的话,会有以下几个步骤:
- Step1:Call a preprocessor, like cpp.
- Step2:Call an actual compiler, like cc or cc1.
- Step3:Call an assembler, like as.
- Step4:Call a linker, like ld
由于编译器是可以更换的,所以 gcc 不仅仅可以编译 C 文件
所以,更准确的说法是:gcc 调用了 C compiler,而 g++ 调用了 C++ compiler
gcc 和 g++
- 对于 *.c 和 *.cpp 文件,gcc 分别当做 c 和 cpp 文件编译(c 和 cpp 的语法强度是不一样的)
- 对于 *.c 和 *.cpp 文件,g++ 则统一当做 cpp 文件编译
- 使用 g++ 编译文件时,g++ 会自动链接标准库 STL,而 gcc 不会自动链接 STL
- gcc 在编译 C 文件时,可使用的预定义宏是比较少的
- gcc 在编译 cpp 文件时 / g++ 在编译 c 文件和 cpp 文件时(这时候 gcc 和 g++ 调用的都是 cpp 文件的编译器),会加入一些额外的宏。
- 在用 gcc 编译 c++ 文件时,为了能够使用 STL,需要加参数 –lstdc++ ,但这并不代表 gcc –lstdc++ 和 g++ 等价,它们的区别不仅仅是主要参数。
Clang与GCC
Mac 的 OS X 系统的 C 语言 编译器用的是 Clang,如下图,在 Terminal 输入 gcc -v 或者 gcc --version 后,显示 C 语言 的编译器:
macOS 中的 gcc 和 g++ 苹果开发者们并没有去改造和重写它们,只是分别指向 clang 和 clang++ 编译器。Clang 是一个 C++ 编写、基于 LLVM、发布于 LLVM BSD 许可证下的 C/C++/Objective C/Objective C++ 编译器,其目标(之一)就是超越 GCC。LLVM 历史 Apple(包括中后期的 NeXT) 一直使用 GCC 作为官方的编译器。GCC 作为开源世界的编译器标准一直做得不错,但 Apple 对编译工具会提出更高的要求。此外 GCC 作为一个纯粹的编译系统,与 IDE 配合得很差。加之许可证方面的要求,Apple 无法使用 LLVM 继续改进 GCC 的代码质量。于是,Apple 决定从零开始写 C、C++、Objective-C 语言的前端 Clang,完全替代掉 GCC。正像名字所写的那样,Clang 只支持 C,C++ 和 Objective-C 三种 C 家族语言。
到这里对GCC、Clang、g++、gcc应该有个比较清晰的理解了。
参考博文: