接上一篇《C++/C入门之Gnu make》。下面是上一篇中用到的一个makefile的例子。
#Alias definistion
OUTPUT_OPTION = -o $@
interim_obj = interim_target1.o interim_target2.o
CC = gcc
CPPFLAGS = -lstdc++
COMPILE.cpp = $(CC) $(CFLAGS) -c
LINK.cpp = $(CC) $(CFLAGS) $(CPPFLAGS)
# Pattern matching rules
Final_Target: $(interim_obj)
$(LINK.cpp) $(interim_obj) $(OUTPUT_OPTION)
$(interim_obj):%.o: %.cpp
$(COMPILE.cpp) lt; $(OUTPUT_OPTION)
run:Final_Target
./Final_Target
clean:
rm $(interim_obj) Final_Target
下面从make的视角,来逐一解读这个文件。解读的同时,会引申出一些makefile的规则。
这个makefile的第一个target是Final_Target。它又依赖于由变量interim_obj定义一些列文件。这些文件的生成规则由$(interim_obj):%.o:%.cpp指定。这是个多目标生成规则,之前没接触过,所以要引入一个新makefile的规则:静态模式。
静态模式规则可以抽象成:
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
其中targets是一个或多个目标集合。对于对象中的每个集合,如果它能匹配target-pattern(%.o),并且能找到匹配prereq-pattern的文件(%.cpp),且prereq-pattern的文件较新或目标文件不存在,则执行command的内容。
例子中的command翻译过来就是 gcc -c lt; -o $@,其中$@代表目标文件,lt;代表由prereq-pattern匹配的一系列文件。lt;和$@都是由make预定义的宏变量。
%是一个通配符。它能匹配一个或多个字符,但是同一次匹配中,target-pattern和prereq-pattern中的匹配部分要一致。
对上述文件执行完make后,输出是:
gcc -c interim_target1.cpp -o interim_target1.o
gcc -c interim_target2.cpp -o interim_target2.o
gcc -lstdc++ interim_target1.o interim_target2.o -o Final_Target
读者如果希望写出更强大的makefile来适应自己的工程编译的需要,下面是一些建议。
最简单的,复制上面的例子,重新指定interim_obj的文件列表。注意,command命令之前的空白不是空格,而是一个tab制表符。
如果你的源文件包含头文件,简单的做法是另行定义规则。gcc编译器能通过gcc -MM <源文件>来为你指出源文件所依赖的头文件。gcc -M则会同时包含被依赖的标准库文件。
更为复杂一点,如果你的源文件或者头文件分布在不同的目录,则可用vpath告诉make源文件的位置。如vpath %.h /usr/local/headlib/告诉makefile去对应的目录读取头文件集。
如果你希望一次make执行多个目标,则可用伪目标。如makefile的第一条规则是all:target1 target2,后边不跟任何命令。命令行输入make,实际效果是target1和target2被执行,all被执行时不做任何动作。
GNU的make工作时的执行步骤入下:
1、读入所有的Makefile。
2、读入被include的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。
掌握以上make的知识,将足够阅读和编写一下简单的make文件。