一.最简单makefile的编写

 

        1.makefile的命名:makefile

        2.makefile的规则:目标,依赖,命令

        格式为:

第一行为目标:依赖(目标就是你要生成可执行文件的名字,依赖就是要编译的文件)

第二行,先开始有一个tab缩进。然后就是gcc的编译命令(注意开始有tab缩进

当编写完makefile之后直接make就可以执行编译文件。

二.提升版makefile

以上就是最简单的makefile的编写。但是很容易发现这种编写方式有一个很大的漏洞,如果我们有100个文件先编译完成了,当我们修改了其中的一个文件之后在进行编译时就会重新编译全部100个文件,这是十分浪费时间的。解决方法如下:

假设我们有sub和add两个文件需要进行编译。我们把第一行的依赖改成.o文件。这是makefile的执行顺序是,当第一行执行到add.o的时候,会向下查找是否有生成add.o的规则,如果有就去执行它。sub.o同理。也就是说该makefile会先生成add.o和sub.o然后再去生成app。

注意:生成终极目标的规则一定要写在最上面!

三.提升版是如何避免重复编译的

当我们编译了第一次,如上图所示我们生成了main.o ;add.o ;sub.o;mul.o这几个.o文件。放我们修改了其中的main.c文件的时候我们在重新编译,会发现makefie只重新编译了main.c文件,没有编译其他文件。

那么makefile是怎么判断一个.c文件是否被修改了的呢?

其实makefile是通过对比时间戳的方式来进行判断的。当我们生成了所有的.o文件之后,我们知道此时的.o文件的创建时间是要晚于.c文件的创建时间的。这时候如果我们修改了其中一个.c文件,那么就会是这个.c文件的创建时间更新使其时间比其他的.o文件还要晚。makefile检测到其创建时间过晚,就会认为该文件做过更新,所以就会重新编译它,而其他创建时间没被修改的.c文件则不会被编译。

四.变量的使用

我们通过使用了变量来对上述代码进行了简化,使得编写更为简单。

1.首先定义了一个obj变量和一个tar变量。让obj=add.o sub.o tar=app。然后通过$(obj)引用该变量的值

2.下面就是模式匹配了。因为下面都编译的语法格式都一样所以我们可以用一个统一的模板进行书写,这样第一个规则的依赖会自动套用该模式。

%.o:%.c  (终极目标需要add.o,其会向下查找发现有%.o自动用add.o匹配进去,由于%内容是对应的所以%.c即为add.c。sub也同理)

自动变量:

$<(代表的是规则中的第一个依赖,再add.c的例子中就是add.c)

$@(代表规则中的目标)

$^(代表规则中的所有依赖)

五.函数的使用

这里我们只介绍聊个函数wildcard(通过通配符来查找相应的文件) patsubst(替换函数)用法如下

第一行为查找该目录下的所有.c文件,给它赋值到变量src。

第二行为将所有的.c文件替换为.o文件,然后赋值给obj。

六.其他用法

当我们定义了一个和终极目标无关的规则:

如图中的clean规则,它没有依赖但是有命令。该规则和终极目标app的生成无关,那么他又什么作用呢?

上面可以看到当我们执行make clean的时候就自动执行了clean的命令。因为clean不会生成终极目标的依赖所以正常调用make的时候不会执行,只有再make clean的时候才会执行

注意:如果该目录下原本有一个clean文件那么执行make clean的时候就会:

显示clean已经更新,而不执行clean命令。为了应对该情况,要将clean规则添加到伪目标中

通过.PHONY声明这个clean。然后就可以直接执行了

 

 

 

 

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐