Makefile学习心得
昨天花好长一段时间来练习Makefile,同时也在练习gcc,颇有收获。gcc其实简单,只要明白其操作过程和命令就能很好掌握。make的知识量要多一些,容我细细回顾!Makefile单词太长,我设个宏MF下面就用它代替说明。
MF的目标是什么,为什么会出现这个工具,这个工具是为了解决什么问题的?其实只要思考这个问题,我们能更清楚的了解MF,由于在MF之前老前辈们编程序的规模越来越大,导致老式的方法一个文件一个文件的编译,那太麻烦太耗时了,而采用脚本来执行则所有的操作都会重新做一次,这样的方式对大型项目来说是绝对跟不上节奏的。所有有前辈就设计一个软件来完成事情,考虑到平常编译过程中,先要将源文件编译成目标文件,再将目标文件链接成执行文件,在这里,若源文件被修改,那么对应的目标文件也必须被重新编译,同样若目标文件被修改,需要链接它来生成的执行文件需要重新连接,而且只要保证这个规则就能保证,按这个要求来得到的执行文件就是那些源文件编译后的结果。这也就是MF的核心啦,所有的功能概念规则约定都是在这个基础上来扩展的。总的来说那就是这三条:
1. 所有的源文件没有被编译过,则对各个C源文件进行编译并进行链接,生成最后的可执行程序;
2. 每一个在上次执行make之后修改过的C源代码文件在本次执行make时将会被重新编译;
3. 头文件在上一次执行make之后被修改。则所有包含此头文件的C源文件在本次执行make时将会被重新编译。
通过比较要生成的文件和其依赖的文件的修改时间,就可以确定是否进行编译,若生成的文件不存在那就更要进行编译啦。这样就产生了MF中的规则啦,如:
TARGET... : PREREQUISITES...
COMMAND
...
...
冒号左边的为要生成的文件,叫目标,右边为目标的依赖,即指出生成这个文件需要哪些文件。第二行开始为操作命令,必须以Tab缩进,为将依赖生成目标的命令行命令。比如gcc。而MF是将这些规则写入MF文件中,再分析依赖规则,最后决定操作哪些命令。
好了上面为一些简单的介绍,可以说明MF的大体轮廓了,实际中的MF文件包含更多内容,而make工具也提供更多功能。因为管理大型项目需要,若是这样简单也会很麻烦,比如:文件有几百个,那么要写几百个这样的规则么;目标和依赖的路径一般也会很长,如何保证不出错呢或者更简便......所以MF还提供变量的功能,代替一些长的串,这样能使目录管理更方便。还提供一些函数使写MF更加方便快捷。详细的就不说了可以看文档,我是通过《GNU make中文手册》,《跟我一起写Makefile》来学的,这样系统些,网络上的文章也大多是零散的。
再说明几个知识点和使用技巧:
1.MF可以认为分为两个步骤,首先分析依赖关系,这样可以得到一棵树结构啦,并且可以发现哪些规则需要执行,然后就执行需要执行的规则,若没有会提示make无需做任何事情。提示这点主要是在make不正常工作时,分析问题所在。
2.MF第一个规则,为默认规则,使用make不指定目标时就从这个目标开始分析。模式依赖规则,只作为工具,不做最终规则。
3.MF一个目标可以有多个规则,并且依赖将是这个目标所有规则的依赖的并集,这一点很重要,在自动产生依赖中要用到。
4.MF中可以使用一些伪目标来进行变量显示,这也是为了分析问题而做的。比如我:
clean:
@echo cealn .d .o $(TARG)
@-rm -f $(DEPS) $(OBJS) $(TARGET) #在命令前加- 表示某一下出问题后选择继续进行
@echo 显示变量 SCRS:$(SCRS) OBJS:$(OBJS) DEPS:$(DEPS)
5.MF的自动产生依赖,当我们源文件很多时,我需在MF文件中为每个文件写一个规则,那这样显然不合习惯啦,所以可以自动产生依赖来完成这个操作。而这个机制其实不是MF提供的,他是采用系统命令来和依赖信息文件来实现的。因为gcc 的-M命令可以产生系统输出文件对应的全部依赖信息,利用这一点,我们将这些信息写入到MF文件中,在上面提到这些依赖信息将有效。然后在MF文件中写出所有规则,这个简便方法就可行了。先看下面模板:
$(DD)/%.d:$(SD)/%.$(SEXT)
@echo 生成依赖文件 $@
@$(CC) -MM $(CFLAGS) $(IFLAG) $< | \
sed -e 1's,^,$(OD)/,' > $@
sinclude$(DEPS)
$(OD)/%.o:$(SD)/%.$(SEXT)
@echo 生成目标文件 $@:$<
@-$(CC) -o $@ -c $< $(CFLAGS) $(IFLAG)
DD为依赖信息文件目录变量,SD为原文件目录变量,OD为目标文件目录变量。这套sed命令表示在这一行串前加上目标文件目录,因为gcc -MM产生的字符串冒号左边的不带目录,所以要使用此命令,再输出重定向到对应的.d文件中。之后使用sinclude来加入这些信息,再随便写个生成所以目标文件的规则,依赖甚至可以不写。
6.MF的include和sinclude,他们的参数可以为文件或者目录,目录的话表示加入目录内所有文件,include若包含的文件不存在,make会终止,而sinclude不会,sinclude与make的参数-include作用相同。
7.MF的匹配,make使用%来进行两个模式的匹配,从模式块中提取字符串保存在%中,再展开匹配块中的%。
后记,通过几天的学习和操作,make现在以及基本掌握啦,现在可以使用make来管理我的项目咯!