1.make/Makefile是什么?
make是一个命令,Makefile是一个文件。
我们此时拥有一个名叫text的c语言源文件,我们想要编译这个文件最简单的方法就是使用我们前面所讲的gcc进行编译,如果此时我们工作路径下有很多源代码需要编译,我们就要一直写gcc指令,因此就需要使用make/Makefile了,首先我们先创建一个叫Makefile的文件(M可大写也可小写)
然后使用vim编辑Makefile文件。

上图第一行代码是一个依赖关系,生成text依赖的是text.c,而第二行必须以Tab键进行开头,含义是想以什么样的方式将text.c变成text。从此我们进行编译就不需要写gcc命令了,只需要使用make命令就可以了

2.Makefile的基本概念
依赖关系:上面Makefile文件中第一行代码表示的就是依赖关系
依赖方法:第二行代码表示的就是依赖方法
3.完善Makefile
此时我们并不满足于只进行代码的编译,我们还要实现对代码的清理,这要如何实现呢?
这里我们需要定义一个".PHONY",这个可以理解为Makefile中的一个修饰符,由它修饰的clean我们称之为伪目标(伪目标就是对应的依赖关系跟依赖方法总是被执行,忽略对比文件是否被更新)
什么叫做总是被执行呢?不妨反过来想一下什么叫做总是不被执行
如上图就是总是不被执行的例子,如果源代码没有被更新过只允许我们执行一次,这样就很好理解总是被执行的概念了。

在这里补充一点依赖关系也可以为空,如上图中的clean的依赖关系就为空。上图中的clean和rm也是一组依赖关系跟依赖方法
至此,我们就可以将一个源文件使用make命令的组合实现自动化的代码编译。
注:make命令扫描Makefile文件的时候,从上到下扫描文件,默认形成第一个目标文件。


上面两张图片可以理解为make在扫描Makefile文件时会维护一种类似于栈结构的东西,从上到下扫描时,如果找不到依赖文件时就就对命令进行入栈操作,然后向下扫描,当找到依赖文件时进行一系列的出栈并执行命令最后生成text文件,这就是Makefile进行目标文件推导的基本规则。
但我们平常不会像上面一样去写Makefile


上图中的$()表示的是引用一个变量,我们可以发现使用这条命令时会回显这条命令,我们如何避免回显命令呢?只需要在相应的命令前加一个@符号即可如下图

下图是我们进行Makefile编写时的常用写法

这里Makefile中的变量相当于以前我们学过的宏,当我们想要改变任一文件的名称只需要更改变量就可以了。
我们还可以像下图中的第七行一样写,这里的@永远指的是你最终的目标文件,而^指的是你依赖的众多文件列表。

上面所说的都是对一个文件进行编译,如果一次性有超级多的文件需要编译呢,这里引入一个新的写法:


这里出现了两个新符号分别是:
%:类似于makefile下的通配符,表示把当前路径下的所有 .o / .c 文件依次展开,例如文件中有一百份分别为text1.c~text100.c的源文件,Makefile会根据你写的这个自动生成一百份这组依赖关系
$<:将展开的依赖关系一个一个拿过来
通过上面的讲解我们并没有看出Makefile相比于gcc的出色之处,尽管不需要写gcc了但是我们在Makefile中也写了很多代码,那么就需要进行更新更好的写法了。
因为Makefile是可以直接执行命令行命令的,因此这里使用固定用法$(shell 命令)来让SRC自动获取这个命令在shell下执行的结果,我们就不需要进行手动输入了是不是很方便。
还有另一种做法,Makefile自己就有相应的做法,它内部包含一些类似于函数的东西,这里使用的是wildcard,如上图所示是它的用法,含义为默认将当前路径下的所有.c文件通配出来。而变量OBJ需要使用下图中的用法来将SRC中的.c文件替换成同名的.o文件: