从版本1到版本5如何编写牛逼的Makefile

2019-09-20 17:24:41 浏览数 (1)

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如下:

0 人点赞