关于Makefile 1——基础篇

关于Makefile的知识,推荐大家看一下陈皓的《跟我一起写makefile》,讲解的非常好,
同时华清创客里小美老师的视频也很不错。
下面是陈皓《跟我一起写makefile》中关于Makefile书写格式介绍:
下面是华清小美老师视频的对Makefile的格式说明:
举例说明:
1、创建 Makefile 文件,注意文件名为 makefile 和 Makefile 都行,但是不要是其他名字,同时创建的是文件不是目录,所以不能用mkdir创建

2、目标生成文件 :test,需要依赖文件:f1.o f2.o main.o
如何通过依赖文件生成目标文件呢?那就需要通过下面的命令:
gcc f1.o f2.o main.o -o test
注意gcc前面一定要有个<Tab>不能是4个空格,否则报错。
可是生成目标文件的依赖文件并没有怎么办,那就需要通过相关方式产生依赖文件,什么方式呢?递归生成:
f2.o:f2.c
gcc -c -wall f2.c -o f2.o
这意思是目标文件:f2.o 需要依赖文件:f2.c
通过命令:gcc -c -wall f2.c -o f2.o 来实现
编辑完后退出保存Makefile文件

3、查看目录下的文件:
为什么会有 a.out 呢?那不是保存Makefile产生的,是之前用gcc编译运行时产生的。

4、执行Makefile就是通过输入 make 回车,能看到执行Makefile的整个过程,有没有发现和我们编写时不一样的地方?
我们编写时是不是先写的目标 test 文件,然后 .o 依赖文件,由于没有 .o 的依赖文件,所以我们又写了通过 .c 文件生成 .o 文件的步骤;而我们执行时变了,成了先执行 .c 文件生成 .o文件,在执行 .o 文件生成目标 test 文件。是不是有点递归函数编写和执行的味道在里面?

5、查看执行完 make 后目录会出现什么变化呢?
是不是多出了相应的 .o 文件和一个 test 文件了啊

6、运行编写的程序:
以前我们使用 gcc 编译时是不是想运行需要输入 ./a.out 回车,现在我们要做的就是 ./test 回车就行了,看到下面的运行结果了吗。

7、当我们发现输出信息不对称,想修改 Message:f2.c 的输出和上面 Message: f1.c 一致时,我们需要到 f2.c 文件里修改,修改完了保存退出。
如果用 gcc 编译时它会将所有的 .c 文件全部重新编译,而现在使用 Makefile 只需要重新执行 make 命令,编译器会只编译 f2.c 这个修改的文件,而对于 f1.c 和 main.c 就不会再重新编译,结果如下:
思考:编译器是如何判断哪些需要执行,哪些不需要呢?
编译器是根据相应文件的时间戳来判断的,当执行时发现某一个 .c 文件的生成时间比相应的 .o 文件时间更新,编译器就会判断这个文件被修改了我需要通过依赖文件重新编译生成目标文件,而其他的依赖文件比目标文件更旧(语文不好不知道如何表达比更新相对的,只能用更旧了)也就是依赖文件没更新,所以不用重新编译,于是结果如下:

8、再次运行编译的程序:

9、Makefile 对中间文件的清理:
只需要在 Makefile 里加入 clean 命令(clean也可以写成其他单词,但是为了见文知意,用clean更好些),代码如下:
rm *.o test 表示删除所有 .o 文件 和 test 文件

10、执行 clean 命令:make + clean
我们看到相应的 .o 和 test 文件已经删除了。
思考1:之前我们运行 test 时只输入 make ,为什么现在是 make + clean 呢?
执行 make 时默认是执行 Makefile 第一个目标名,如果想执行其中某一个目标名时需要在后面加上相应的目标名。
思考2:为什么执行 test 时会生成 test 文件,而执行 clean 却没有生成 clean 文件呢?
test 和clean 都是目标名不是文件名,具体执行内容是看下面的命令,test 目标名的内容是:gcc f1.o f2.o main.o -o test
而 clean 目标名的内容是:rm *.o test 。

11、当目录下正好有一个 clean 文件时会出现什么情况呢?
会显示 clean 是最新的,如果我每次都想执行 Makefile 里的clean 怎么办呢?
这时我们需要在 Makefile 文件里加一条伪目标: .PHONY:clean 后再次执行就OK了


12、比较实用的信息:
陈皓《跟我一起写makefile》中对何时会执行目标文件的解释

陈皓《跟我一起写makefile》中对clean等目标的解释
下面的 Makefile 命令你看懂了吗?
为什么输入 make 就能执行 Makefile 里的命令呢?