
个人主页:小则又沐风
个人专栏:<数据结构>
<竞赛专栏>
<Linux>
座右铭
路虽远,行则将至;事虽难,做则必成
目录
前言
在之前的开发工具介绍的文章中我们简单的了解了怎么在Linux下下载软件也就是yum的使用
和vim的使用和配置
接下来我们进一步来了解Linux的开发工具
编译器gcc/g++
在vim的支撑下我们就可以进行简单的代码编写了,但是我们怎么把自己的代码进行编译运行呢?
这就是我们下面将要了解的开发工具编译器gcc/g++
了解代码的编译的过程
我们在C语言中的学习就知道了,代码的成功的运行不仅仅是一步就搞定的,他是经过
- 预处理
- 编译
- 汇编
- 链接
代码经过这四个步骤的处理才会正常的运行的
但是我们在之前使用无论是什么编译器(比如我使用的VS2022)就是一步到位的并没有什么这些复杂的步骤啊
这是因为我们的编译器一个集成开发环境这些东西有人帮我们做了我们不需要做而已
现在我们呢就来一步步了解一下这些步骤
预处理
预处理的过程就是把一个.c的文件变成一个.i文件
预处理功能主要包括宏定义,⽂件包含,条件编译,去注释等。
怎么在Linux下看到这个过程呢?
我们只需要gcc -E 目标源文件 -o 处理后的.i文件
我来演示一下
cpp
#include<stdio.h>
#define N 100
int main()
{
int a=N;
// jjjj
printf("%d",a);
return 0;
}
现在我们编写了一个带有注释 宏定义的代码
我们来预处理一下看看

我们进入这个.i文件之后我们就可以看到预处理过的文件把我们的代码进行了我们上述的处理

.c->.i
编译
编译是我们接触最多的东西了,如果我们的代码有语法上的错误,我们的编译环节就会检查出来
我们想查看这一过程可以使用gcc -S code.i -o code.s
这里的code.c是一个代表而已

.i->.s
汇编
汇编的话就是把我们写的代码变成计算机能够看懂的代码,也就是所谓的二进制代码
gcc -c code.s -o code.o

链接
gcc code.o -o code
在这的code的文件就是我们的可执行的文件了
我们知道在我们的代码中我们使用了一堆的库函数,但是我们这些函数并不是我们实现的,所以我们要想使用这个库函数的函数的话我们就需要把这个库函数的内容链接到我们的代码中
这个链接的方式有两种
- 动态链接
- 静态链接
举个例子:
我们在函数中使用了库函数中的printf函数
静态链接:
如果文件的链接的方式是静态的话就是我们把库中的printf的实现直接粘贴到了我们的代码中内
然后使用
动态链接:
动态链接的话就是我们得到的是这个printf函数的地址我们在需要调用这个函数的话我们直接去这个地址中去使用
更通俗的就是假设张三需要上网
静态链接就是张三配了一台电脑搬到了宿舍
动态链接就是去网吧
那么在解释了动静态的链接之后我们就需要了解一下动静态库
动静态库
库文件就是一个个实现好的文件,等待我们的使用的
动态库的话就是使用的是动态链接的方式实现的一般是.so的后缀文件
相反静态库就是依靠的是静态链接实现的一般是.a的后缀的文件
以上就是我们有关编译器开发工具的讲解了
但是这样的话我们编译代码的成本就太高了
在平常的使用的话我们只需要gcc code.c -o code

怎么运行呢?
.\我们的可执行文件就可以了
那么我们能不能依靠上面我们讲的东西来解决下面的问题呢?
假设我和舍友要共同完成一个作业
他把主要的函数的实现的部分交给我了他只负责把函数调用
我们想着他这么想要坐享其成我们怎么才能只让她使用不能让他看到我们的源代码呢?
很简单,我们只需要把我们实现的函数弄成.o文件最后把所有的.o文件链接到一起就好了
这就是我们依靠库函数的调用得到的启发
我们来实现一下

我们把实现好的.c文件编译成.o文件
然后把.h文件和.o文件拷贝到舍友的目录下

我们现在只需要把代码链接到一起编译就好了

这样我们就把我们的作业完成了,当我们舍友想要看源代码的话 你就可以让他给你买瓶水才让他看了
⾃动化构建-make/Makefile
makefile是一个非常好用的一个工具,我们只需要一个make语句就可以完成我们设计好的程序
那么设计一个好用的makefile文件就是一个非常强大的能力
基本使用makefile
使用这个makefile需要我们确定两个东西
- 依赖关系
- 依赖方法
这是什么东西呢?
我们直接来看一个例子

我们创建出一个code文件

在我们的makefile的文件中我们写上这些
我们来看看会发生什么

当我们输入make的时候我们会自动把这个code.c的文件自动编译
这是因为我们在makefile中是这么写的
我们现在就来介绍一下这个文件
上面我讲的依赖关系就是

我们最后生成的目标文件就是这个code他依赖的文件是这个code.c的文件
那么依赖的方法是什么就是我们下面这一行写的东西了
需要注意的是我们依赖关系这一行的开头要输入一个tab
可以发现我的makefile的文件中还有一个东西
就是.PHONY:clean
这一串东西
这是什么东西呢?
.PHONY修饰的是伪目标文件
这些的文件时总是被执行的
总是被执行&&不被执行
什么叫做总是被执行的?
这是因为我们有时候我们make的时候我们的文件内容并没有被修改
所以这时候我们执行make的时候我们的make时不被执行的
这就是不被执行但是有的文件我们是需要他总是被执行的所以我们需要这个伪目标文件
那么我们的机器是怎么知道这个文件是否需要执行这个make呢?
他是怎么知道这个文件是一个旧文件还是一个新文件呢?
这时候我们需要回想到我们之前在讲文件的时候我们讲的是
文件=文件属性+文件内容
那么文件属性中就存储着这些信息
我们来查看一下文件的属性

我们可以看到有三个时间的表示
- acess表示的是最后一次进入文件的时间
- modify表示的是文件的内容最后一次被修改的时间
- change表示的是文件的属性最后一次被修改的时间
那么我们需要查看的就是我们这个依赖文件的modify的时间和目标文件的modify的时间


我们可以看到我们的目标文件的modify的时间是更新的所以我们在去make的时候就不会执行

当我们修改一下code.c文件的内容后呢?

这时候我们的code文件的modify的时间就不是最新的了
我们这时候就可以make了

make是怎么执行的
在我们刚才的讲解中我们知道了make的执行是会找我们当前目录下的makefile文件的
然后自动执行文件中的第一个目标文件
但是我们来看下面的makefile文件

这样的话我们make一下

可以发现我们的执行的顺序是符合之前我们的讲解的
但是是怎么执行的呢?
我们要生成code可执行文件依赖.o文件
.o文件依赖.s文件
.s文件依赖.i文件
.i文件依赖.c文件
我们拥有的是.c文件所以我们在执行第一个目标文件的时候我们找不到依赖的文件
make会继续向下找就像一个栈一样
我们的依赖文件是.o文件就去找.o文件-----入栈
.o文件依赖.s文件----入栈
.........
直到我们通过这个.c文件生成.i文件----出栈
就是这样执行的
在找寻的过程中,如果出现错误,⽐如最后被依赖的⽂件找不到,那么make就会直接退出,并 报错,⽽对于所定义的命令的错误,或是编译不成功,make根本不理。
扩充知识

在这里我们开始的东西就相当于我们定义的变量一样,然后之后我们想要使用这些变量的话我们需要的是$(变量名)
其中@代表的是目标文件
^代表的是依赖文件

我来逐步介绍这个文件的内容
wildcard是来获得这个目录下之后
文件的
将与SRC同名的.c文件替换成.o文件
展开该目录下的所有的.c和.o文件
$<: 对展开的依赖 .c ⽂件,⼀个⼀个的交给 gcc
这样我们的make就可以操作大量的源文件了
总结
这篇文章主要讲解 C/C++ 开发基础流程,
核心内容如下:介绍gcc/g++编译器,拆解代码从预处理、编译、汇编到链接的完整过程,区分静态链接与动态链接,讲解动静态库概念;同时讲解make工具与Makefile自动化构建,包括目标执行规则、修改时间判断逻辑及$<、$@等自动化变量的用法
之后还会讲解开发工具的使用
谢谢大家的观看!!!