Bootstrap

Linux进阶·如何在Ubuntu安装、调试、运行gcc/g++,以及如何进行多文件编译

目录

1.  简介

2.  安装gcc

3.  gcc的编译流程

3.1  预处理

 3.2  编译

3.3  汇编

3.4  链接

4.  gcc相关参数

5.  多文件编译

6.  gcc和g++的区别


1.  简介

        gcc是Linux下的编译工具集,是GNU Compiler Collection的缩写,包含gcc, g++等编译器。这个工具集不仅包含编译器,还包含其他工具集,例如ar,nm等。

        gcc是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Objective-C等语言编写的程序。gcc又是一个交叉平台编译器,它能够在当前CPU平台上为多种不同体系结构的硬件平台开发软件,因此尤其适合嵌入式领域的开发编译。

        对于gcc支持的编译源文件的后缀名及其解释如下:

后缀名所对应的语言
.cC源程序
.C/.cc/.cxxC++源程序
.mObjective-C源程序
.i经过预处理的C源程序
.ii经过预处理的C++源程序
.s/.S汇编语言源程序
.h预处理文件(头文件)

.o

目标文件
.a/.so编译后的库文件

2.  安装gcc

        有些纯净版的 Linux 默认没有 gcc 编译器,需要自己安装,如果你不知道自己有没有安装gcc,可以输入一下命令进行查看:

//查看 gcc 的版本
gcc -v
//或者
gcc --version


//查看 g++ 的版本
g++ -v
//或者
g++ --version

        使用gcc -v查看如下: 

        下滑可以看到gcc当前的版本: 

        使用gcc --version可以看到,其显示的信息是比较少的,但版本信号是一样的:

        使用g++ -v查看:

        同样下滑可以看到当前版本:

        使用g++ --version:

        若是显示不是上面的,或者找不到gcc......,安装步骤如下:

//需要管理权限
//bubutu上面安装
sudo apt update //更新本地的软件下载列别列表,得到最新的下载地址

sudo apt install gcc g++ //通过下载列表提供的地址下载安装包,并安装


//centos上面安装
sudo yum update

sudo yum install gcc g++

        下面演示Ubuntu上下载:

3.  gcc的编译流程

        gcc的编译流程可分为四个阶段:预编译(预处理)→ 编译和优化 → 汇编 → 链接。

文件名后缀说明gcc参数
.c源文件
.i预处理后的C文件-E
.s编译后得到的汇编语言的源文件-S
.o汇编后得到的二进制文件-c

3.1  预处理

        编译器将*.c代码的头文件编译进来,例如我们头文件声明的是:include<stdio.h>那么就会将stdio.h编译进来,用户可以使用gcc的选项“-E”进行查看,该选项的作用是让gcc在预处理结束后停止编译过程。

        该阶段主要进行三件事:展开头文件、宏替换、去掉注释行。

        演示一下,首先我们先创建一个.c的文件:

        其中.c文件内容为:

         这里对于Linux的一些基础命令和vi/vim编辑器的使用不做过多的描述,想要详细了解的可以看:

Linux常用命令详细解析(含完整命令演示过程)-CSDN博客

Linux命令进阶·vi\vim编辑器详细命令介绍-CSDN博客

        主要演示gcc的过程:

        对于一下这条命令进行解读:

gcc -E hello.c -o hello.i
  • gcc: 是 GCC 编译器的命令,通常用于编译 C 语言程序。
  • -E: 这个选项告诉 GCC 只进行预处理,而不进行编译、汇编或链接。预处理包括宏替换、文件包含和条件编译等。
  • hello.c: 这是你输入的源代码文件,通常是 C 语言源代码文件。
  • -o hello.i: 该选项指定输出文件的名称。在这里,预处理的结果会被保存到 hello.i 文件中,.i 是预处理后的 C 代码文件扩展名。
     

        我们可以通过cat命令查看文件内容,首先是.c文件:

        对.i文件进行查看,可以看到头文件被展开了:

        往下翻可以看到,对比.c文件黄色部分的注释被清除了,蓝色部分3的位置开始时NUMBER的宏定义,此时被替换成3:

        我们也可以直接通过vim hello.i进行查看:

 3.2  编译

        在编译阶段,gcc首先要检查代码的规范性,以及收否有语法错误等,以确定代码是否能正常工作,无误后,gcc把代码翻译成汇编语言,用户可以使用“-S”选项进行查看,该选项只是进行编译而不进行汇编,最终生成一个汇编代码。

  • gcc: 是 GCC 编译器的命令。
  • -S: 这个选项告诉 GCC 执行到汇编阶段。它会把源代码编译成汇编语言代码,而不是生成机器码或可执行文件。
  • hello.i: 这是输入文件,应该是一个已经经过预处理的 C 语言源代码文件(通常是 .i 文件)。
  • -o hello.s: 这个选项指定输出文件的名称。这里的 hello.s 文件将包含生成的汇编代码。
     

        同样的,我们可以查看此时.s文件的内容:

3.3  汇编

        该阶段吧编译阶段生成的.s文件转换成目标文件,用户可以使用-c选项查看,汇编代码转换成后缀名为.o的二进制目标代码。

        查看一下,可以发现都是一些二进制文件,不过这里识别不出来,因此显示的是乱码:

3.4  链接

        编译成功后,就进入了链接阶段。

        函数库一般分为静态库和动态库两种:静态库在编译链接时,把库文件的代码全部加入可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了,其后缀名一般为".a”。动态库与之相反,在编译链接时并没有把库文件的代码加入可执行文件中,而是在程序执行时链接文件加载库,这样可以节省系统的开销,动态库的后缀名一般为“.so”。 gcc在编译时默认使用动态库。

        可以看到生成一个可自行程序 hello,点击运行看看:

        到这里一个程序就算运行完成,不过我们会发现,这个步骤太繁琐,实际上我们要执行程序不需要那么繁琐的步骤,上面只是为了演示其运行流程,实际我们可以直接使用:

gcc hello.c -o hello2(生成的链接名自己定义)

        或者我们可以直接省略-o:

        可以看到生成了一个a.out的链接,这是因为如果我们不指定生成的链接名。其会默认给出一个a.out的链接名。

4.  gcc相关参数

参数名称含义
-c只编译不链接成为可执行文件(生成后缀为 .o 的文件)
-S只编译不汇编和链接(生成后缀为 .s 的预编译文件)
-E仅执行预处理,不进行编译、汇编和链接(生成后缀为 .i 的预编译文件)
-o [file1] [file2]/[file2] -o [file1]将文件file2编程file1
-I dir(这里是大写的i)指定include包含文件的搜索目录
-L dir在库文件的搜索路径列表中添加dir目录
-l lib(这里是小写的L)指定程序要链接的库,lib为库文件名称。
-g生成调试信息,方便gdb调试
-D define预定义宏
-w不输出任何警告信息
-Wall开启编译器的所有警告选项
-static链接静态库生成目标文件,禁止使用动态库(在支持动态链接的系统上)
-share尽量使用动态库,但前提是系统存在动态库,生成的目标文件较小
-shared生成共享文件,然后可以与其它文件链接生成可执行文件
-fpic生成适用于共享库的与地址无关的代码(PIC)(如果机器支持的话)
-fPIC生成与位置无关的的代码,适用于使用动态库,与“-fpic”的区别在于去除去全局偏移表的任何限制(如果机器支持的话)
-fPIE使用与地址无关的代码生成可执行文件

5.  多文件编译

        首先我们随便找个地方存放以下文件,这里我将test文件里面的内容删除了,重新放入的:

        每个文件的内容为:

        以上那么多.c文件,若是我们要一个个链接太过繁琐:

        有一种简单的写法,可以使用通配符:

        可以看到生成了一个a.out的链接,运行可得:

6.  gcc和g++的区别

(1)在代码编译阶段(第二个阶段) 

后缀为.c 的,gcc 把它当作是 C 程序,而g++ 当作是 C++ 程序

后缀为.cpp 的,两者都会认为是 C++ 程序,C++的语法规则更加严谨一些

g++会调用gcc,对于C++代码,两者是等价的,也就是说gcc和g++都可以编译C/C++代码

(2)在链接阶段(最后一个阶段)

gcc 和g++都可以自动链接到标准C库

g++ 可以自动链接到标准 C++ 库,gcc 如果要链接到标准 C++ 库需要加参数 -1stdc++

(3)关于_cplusplus 宏的定义

g++ 会自动定义_cplusplus 宏,但是这个不影响它去编译 C程序

gcc 需要根据文件后缀判断是否需要定义_cplusplus宏(规则参考第一条)

Linux常用命令详细解析(含完整命令演示过程)_linux命令实例详解-CSDN博客

Linux命令进阶·vi\vim编辑器详细命令介绍-CSDN博客

Linux学习_时光の尘的博客-CSDN博客

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;