枫林在线论坛精华区>>程序设计 |
[255591] 主题: 跟我一起写 Makefile(二) |
作者: redhat (RedHat) | ||
标题: 跟我一起写 Makefile(二)[转载] | ||
来自: 192.168.*.* | ||
发贴时间: 2004年07月24日 12:21:29 | ||
长度: 6301字 | ||
三、make是如何工作的
在默认的方式下,也就是我们只输入make命令。那么, 1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件 。 2、如果找到,它会找文件中的第一个目标文件(target),在上面的 例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件 。 3、如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修 改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成 edit这个文件。 4、如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标 为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点 像一个堆栈的过程) 5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件, 然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直 到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最 后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义 的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性 ,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不 起,我就不工作啦。 通过上述分析,我们知道,像clean这种,没有被第一个目标文件直接或间 接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显 示要make执行。即命令——“make clean”,以此来清除所有的目标文件 ,以便重编译。 于是在我们编程中,如果这个工程已被编译过了,当我们修改了其中一个 源文件,比如file.c,那么根据我们的依赖性,我们的目标file.o会被重 编译(也就是在这个依性关系后面所定义的命令),于是file.o的文件也 是最新的啦,于是file.o的文件修改时间要比edit要新,所以edit也会被 重新链接了(详见edit目标文件后定义的命令)。 而如果我们改变了“command.h”,那么,kdb.o、command.o和files.o都 会被重编译,并且,edit会被重链接。 四、makefile中使用变量 在上面的例子中,先让我们看看edit的规则: edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入 一个新的[.o]文件,那么我们需要在两个地方加(应该是三个地方,还有 一个地方在clean中)。当然,我们的makefile并不复杂,所以在两个地方 加也不累,但如果makefile变得复杂,那么我们就有可能会忘掉一个需要 加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefi le中我们可以使用变量。makefile的变量也就是一个字符串,理解成C语言 中的宏可能会更好。 比如,我们声明一个变量,叫objects, OBJECTS, objs, OBJS, obj, 或是 OBJ,反正不管什么啦,只要能够表示obj文件就行了。我们在makefile一 开始就这样定义: objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 于是,我们就可以很方便地在我们的makefile中以“$(objects)”的方式 来使用这个变量了,于是我们的改良版makefile就变成下面这个样子: objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit $(objects) 于是如果有新的 .o 文件加入,我们只需简单地修改一下 objects 变量就 可以了。 关于变量更多的话题,我会在后续给你一一道来。 五、让make自动推导 GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于 是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的 make会自动识别,并自己推导命令。 只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中, 如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依 赖文件。并且 cc -c whatever.c 也会被推导出来,于是,我们的makefi le再也不用写得这么复杂。我们的是新的makefile又出炉了。 objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : rm edit $(objects) 这种方法,也就是make的“隐晦规则”。上面文件内容中,“.PHONY”表 示,clean是个伪目标文件。 关于更为详细的“隐晦规则”和“伪目标文件”,我会在后续给你一一道 来。 六、另类风格的makefile 即然我们的make可以自动推导命令,那么我看到那堆[.o]和[.h]的依赖就 有点不爽,那么多的重复的[.h],能不能把其收拢起来,好吧,没有问题 ,这个对于make来说很容易,谁叫它提供了自动推导命令和文件的功能呢 ?来看看最新风格的makefile吧。 objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h .PHONY : clean clean : rm edit $(objects) 这种风格,让我们的makefile变得很简单,但我们的文件依赖关系就显得 有点凌乱了。鱼和熊掌不可兼得。还看你的喜好了。我是不喜欢这种风格 的,一是文件的依赖关系看不清楚,二是如果文件一多,要加入几个新的 .o文件,那就理不清楚了。 七、清空目标文件的规则 每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这 不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”(呵呵, 还记得我的《编程修养》吗)。一般的风格都是: clean: rm edit $(objects) 更为稳健的做法是: .PHONY : clean clean : -rm edit $(objects) 前面说过,.PHONY意思表示clean是一个“伪目标”,。而在rm命令前面加 了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后 面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成mak e的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都 是放在文件的最后”。 上面就是一个makefile的概貌,也是makefile的基础,下面还有很多make file的相关细节,准备好了吗?准备好了就来。 -- ※作者已于 2004-07-24 12:25:05 修改本文※ |
||
========== * * * * * ==========
|
返回 |