# GCC编译器
谈到 GCC,就不得不提 GNU 计划。GNU 全称 GNU's Not UNIX,又被称为“革奴计划”,由理查德·斯托曼于 1983 年发起。GNU 计划的最终目标是打造出一套完全自由(即自由使用、自由更改、自由发布)、开源的操作系统,并初步将其命名为 GNU 操作系统。
早期 GCC 的全拼为 GNU C Compiler,即 GUN 计划诞生的 C 语言编译器,显然最初 GCC 的定位确实只用于编译 C 语言。但经过这些年不断的迭代,GCC 的功能得到了很大的扩展,它不仅可以用来编译 C 语言程序,还可以处理 C++、Go、Objective -C 等多种编译语言编写的程序。与此同时,由于之前的 GNU C Compiler 已经无法完美诠释 GCC 的含义,所以其英文全称被重新定义为 GNU Compiler Collection,即 GNU 编译器套件。
GCC 编译器从未停止过改进。截止到今日(2020 年 5 月),GCC 已经从最初的 1.0 版本发展到了 10.1 版本,期间历经了上百个版本的迭代。作为一款最受欢迎的编译器,GCC 被移植到数以千计的硬件/软件平台上,几乎所有的 Linux 发行版也都默认安装有 GCC 编译器。
GCC是一个编译器的总称,并非一个 gcc 命令,还包括 g++ 等工具。实际使用中我们更习惯使用 gcc 指令编译 C 语言程序,用 g++ 指令编译 C++ 代码。需要强调的一点是,这并不是 gcc 和 g++ 的区别,gcc 指令也可以用来编译 C++ 程序,同样 g++ 指令也可以用于编译 C 语言程序。可以这样理解,gcc 是 GCC 编译器的通用编译指令,因为根据程序文件的后缀名,gcc 指令可以自行判断出当前程序所用编程语言的类别。
## GCC安装组件
| 部分 | 描述 |
| ----------- | ------------------------------------------------------------ |
| c++ | gcc 的一个版木,默认语言设置为 C++,而且在连接的时候自动包含标准 C++ 库。这和 g++ 一样 |
| ccl | 实际的C编译程序 |
| cclplus | 实际的 C++ 编泽程序 |
| collect2 | 在不使用 GNU 连接程序的系统上,有必要运行 collect2 来产生特定的全局初始化代码(例如 C++ 的构造函数和析构函数) |
| configure | GCC 源代码树根目录中的一个脚木。用于设置配置值和创建GCC 编译程序必需的 make 程序的描述文件 |
| crt0.o | 这个初始化和结束代码是为每个系统定制的,而且也被编译进该文件,该文件然后会被连接到每个可执行文件中来执行必要的启动和终止程序 |
| cygwin1.dll | Windows 的共享库提供的 API,模拟 UNIX 系统调用 |
| f77 | 该驱动程序可用于编译 Fortran |
| f771 | 实际的 Fortran 编译程序 |
| g++ | gcc 的一个版木,默认语言设置为 C++,而且在连接的时候自动包含标准 C++ 库。这和 c++ 一样 |
| gcc | 该驱动程序等同于执行编译程序和连接程序以产生需要的输出 |
| gcj | 该驱动程序用于编译 Java |
| gnat1 | 实际的 Ada 编译程序 |
| gnatbind | 一种工具,用于执行 Ada 语言绑定 |
| gnatlink | 一种工具,用于执行 Ada 语言连接 |
| jc1 | 实际的 Java 编译程序 |
| libgcc | 该库包含的例程被作为编泽程序的一部分,是因为它们可被连接到实际的可执行程序中。 它们是特殊的例程,连接到可执行程序,来执行基木的任务,例如浮点运算。这些库中的例程通常都是平台相关的 |
| libgcj | 运行时库包含所有的核心 Java 类 |
| libobjc | 对所有 Objective-C 程序都必须的运行时库 |
| libstdc++ | 运行时库,包括定义为标准语言一部分的所有的 C++ 类和函数 |
## GCC工具
| 工具 | 描述 |
| --------- | ------------------------------------------------------------ |
| addr2line | 给出一个可执行文件的内部地址,addr2line 使用文件中的调试信息将地址翻泽成源代码文 件名和行号。该程序是 binutils 包的一部分 |
| ar | 这是一个程序,可通过从文档中增加、删除和析取文件来维护库文件。通常使用该工具是为了创建和管理连接程序使用的目标库文档。该程序是 binutils 包的一部分 |
| as | GNU 汇编器。实际上它是一族汇编器,因为它可以被编泽或能够在各种不同平台上工作。 该程序是 binutils 包的一部分 |
| autoconf | 产生的 shell 脚木自动配置源代码包去编泽某个特定版木的 UNIX |
| c++filt | 程序接受被 C++ 编泽程序转换过的名字(不是被重载的),而且将该名字翻泽成初始形式。 该程序是 binutils 包的一部分 |
| f2c | 是 Fortran 到C的翻译程序。不是 GCC 的一部分 |
| gcov | gprof 使用的配置工具,用来确定程序运行的时候哪一部分耗时最大 |
| gdb | GNU 调试器,可用于检查程序运行时的值和行为 |
| GNATS | GNU 的调试跟踪系统(GNU Bug Tracking System)。一个跟踪 GCC 和其他 GNU 软件问题的在线系统 |
| gprof | 该程序会监督编泽程序的执行过程,并报告程序中各个函数的运行时间,可以根据所提供 的配置文件来优化程序。该程序是 binutils 包的一部分 |
| ld | GNU 连接程序。该程序将目标文件的集合组合成可执行程序。该程序是 binutils 包的一部 |
| libtool | 一个基本库,支持 make 程序的描述文件使用的简化共享库用法的脚木 |
| make | 一个工具程序,它会读 makefile 脚木来确定程序中的哪个部分需要编泽和连接,然后发布 必要的命令。它读出的脚木(叫做 makefile 或 Makefile)定义了文件关系和依赖关系 |
| nlmconv | 将可重定位的目标文件转换成 NetWare 可加载模块(NetWare Loadable Module, NLM)。该 程序是 binutils 的一部分 |
| nm | 列出目标文件中定义的符号。该程序是 binutils 包的一部分 |
| objcopy | 将目标文件从一种二进制格式复制和翻译到另外一种。该程序是 binutils 包的一部分 |
| objdump | 显示一个或多个目标文件中保存的多种不同信息。该程序是 binutils 包的一部分 |
| ranlib | 创建和添加到 ar 文档的索引。该索引被 Id 使用来定位库中的模块。该程序是 binutils 包的一部分 |
| ratfor | Ratfor 预处理程序可由 GCC 激活,但不是标准 GCC 发布版的一部分 |
| readelf | 从 ELF 格式的目标文件显示信息。该程序是 binutils 包的一部分 |
| size | 列出目标文件中每个部分的名字和尺寸。该程序是 binutils 包的一部分 |
| strings | 浏览所有类型的文件,析取出用于显示的字符串。该程序是 binutils 包的一部分 |
| strip | 从目标文件或文档库中去掉符号表,以及其他调试所需的信息。该程序是 binutils 包的一部 |
| vcg | Ratfor 浏览器从文木文件中读取信息,并以图表形式显示它们。而 vcg 工具并不是 GCC 发布中的一部分,但 -dv 选项可被用来产生 vcg 可以理解的优化数据的格式 |
| windres | Window 资源文件编泽程序。该程序是 binutils 包的一部分 |
## make
### 一、概念
C语言中,我们使用visual studio开发软件时候,写程序开始时候都会创建一个project项目文件,然后在文件里面编译 .h 和 .c 的文件。在Linux中,有一个叫make的东西,就相当于C语言的集成开发环境,我们只需要在make里面创建文件,写代码,make会帮我们管理这些文件。在源程序包里面,也有名为makefile的文件(m是小写),两个命名同时存在,这是合理的,在开发一个项目的时候,工程师一般都会命名为Makefile然后打包交给用户,用户觉得某个Makefile需要改动,用户改动后或者新建后的项目定义为makefile,并且在运行时候,先执行makefile,再执行Makefile文件。
### 二、编写Makefile
让我们先来粗略地看一看Makefile的规则。
```makefile
target ...:prerequisites ...
command
...
...
```
在默认的方式下,也就是我们只输入make命令。那么,
make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到"edit"这个文件,并把这个文件作为最终的目标文件。
如果edit文件不存在,或是edit所依赖的后面的.o文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
当然,你的C文件和H文件是存在的啦,于是make会生成.o文件,然后再用.o文件生成make的终极任务,也就是执行文件edit了。