1.Makefile三要素
2.工作原理
3.开始编写
首先编写我们的程序,以c语言为例。
1)func.h
定义两个函数,分别为加法与减法:
2) 加法函数实现
3) 减法函数实现
4)main函数
3.1 版本1
最普通的版本:直接写即可,简单解释一下:当我们编译上述文件的时候,会通过gcc -o main main.c add.c sub.c。
那么我们将其转成Makefile,就是按照上述工作原理与规则进行转换。
比如sub.o就是依赖与sub.c通过gcc -c命令生成,那么这种依赖可通过:
sub.o: sub.c来实现,第二行写上实现的命令即可,注意第二行要有严格的类似python语法的tab控制。其余的类似操作。
3.2 版本2
我们发现版本1太长了,如何把他进行优化,可以根据语言的特性,当然Makefile也有,那就是变量来赋值,将上述的所有.o文件赋值给obj变量,main赋值给target变量。
引用这些变量则是:$(target)形式。$(变量)。
最后两行解释之前说一下自动变量:
代码语言:javascript复制$<: 规则中的第一个依赖
$@: 规则中的目标
$^: 规则中的所有依赖
所以最后一行就变成如下图所示的情况,而%.o与%.c表示匹配每一个.o与.c文件。对版本1进行修改就变成如下图所示:
3.3 版本3
引入CC变量,在Makefile中有一些内置变量,比如这里要使用的CC,我们可以对其进行赋值修改,也可以直接使用,进一步修改版本2,进一步修改版本2,变为版本3。
3.4 版本4
这里我们引入Makefile中的两个常用函数:wildcard与patsubst,分别为查找本地中的文件与模式匹配。
src=查找本地的所有.c文件,obj=将本地的所有.c文件替换为所有的.o文件。
3.5 版本5
在使用Makefile的时候我们需要clean掉所有的.o文件跟中间文件,那么如何在Makefile中实现呢。
就是通过clean,而在clean的过程中,普通的clean写法为:
代码语言:javascript复制clean:
rm *.o main
当我们clean连续两次就会出现问题,如下图:
这种问题是因为你删除了一次,本地磁盘没有相应文件,而报的错误,那么解决这种问题就是加上-f参数,让他强制喊出。
代码语言:javascript复制clean:
rm *.o main -f
当我们在本地创建了一个clean文件,再去make clean的时候,一直都显示最新的,如下图:
这里就要引入一个概念,伪目标,因为make clean,会将本地磁盘与make clean后的文件进行对比,而make clean并没有生成相应的文件,所以根据Makefile特性,每次更新后必定是新的,而本地磁盘就是现成的,那么肯定和新的,就会出现上述结果。
像make这种可以生成文件,而make clean没有生成文件,称之为伪目标,此时需要在Makefile中进行声明:
代码语言:javascript复制.PHONY: clean
clean:
rm *.o main
最后当我们在clean下面想做其他工作,比如创建文件操作的时候,如果没有相应的创建文件权限或者其他情况,直接后面的命令不会被执行。
示例如下:/usr/local下创建文件普通用户没有权限,所以必然会报错:
代码语言:javascript复制.PHONY: clean
clean:
mkdir /usr/local/a
rm *.o main
会发现直接报错了,解决这个问题很简单,在命令行前面加上一个横杠(-)。
代码语言:javascript复制.PHONY: clean
clean:
-mkdir /usr/local/a
rm *.o main
最后完整版Makefile如下: