分类: C/C++
2009-03-24 22:51:56
Makefile学习
虽然工作很忙,没什么空闲时间,但arraya也在像蜗牛一样慢慢地向前爬行,现在变成多目录了,编译就比较麻烦了,不用Makefile真不方便,于是自己在网上找来了通用的Makefile文件,看了看,就自己写了个出来,一编译,出错,明明定义的类,系统说找不到,哦,Makefile写得不对,改了又改还是有这样那样的错误,于是痛定思痛,系统地学习下Makefile,以后写什么程序,小项目,都自己写个Makefile,把这个基础搞定。
正式开始学习...
以前看过一点,知道Makefile最基本的结构,所以学习目标定为多文件多目录的Makefile有关于东西,另外要学习的是gcc命令,没经验啊,都不好意思说工作半年了。
第一条,make可以自动推导文件以及文件依赖关系的命令,所以没有必要去在每一个[.o]文件后都写上类似的命令,可以这样写:
obj = main.o command.o fun.o
execute : &(obj)
cc -o edit &(obj)
main.o : dfs.h
command.o : dfs.h command.h
fun.o : dfs.h fun.h
第二条,在Makefile中使用include关键字可以把别的Makefile包含进来,被包含的文件会原模原样的放在当前文件的包含位置
第三条,wildcard,如果想使用通配符[*],那么你就要使用这个wildcard了,例如:
obj = *.o #语法是正确的,但语义上并不表示当前目录下的所有.o文件
obj = $(wildcard *.o) #这才是你要的所有.o文件
第四条,VPATH特殊变量,定义这个变量可以让不同的目录成为make的默认搜寻目录,大概就是环境变量的意思,不同的目录以:分开,例如
VPATH = src:../include:../base #make时,会搜寻定义的三个目录来找Makefile规则中的文件
第五条是和第四条相对应的,vpath,这个关键字也是为make指定搜寻,这个更为灵活,它可以指定不同的文件在不同的搜索目录中:
vpath < pattern> < directories>
为符合模式< pattern>的文件指定搜索目录< directories>
vpath < pattern>
清除符合模式< pattern>的文件的搜索目录。
vpath
清除所有已被设置好了的文件搜索目录。
vapth使用方法中的
vpath %.h ../headers
该语句表示,要求make在“../headers”目录下搜索所有以“.h”结尾的文件。(如果某文件在当前目录没有找到的话)
第六条,伪目标,通常的make clean中的clean就是一个伪目标,这样写:
clean:
rm *.o
.PHONY : clean #这个是声明clean是一个伪目标,也就是说这个目标不是真实的文件
由第六条,可以得到使用一次make,得到多个可执行文件的方法:
all : prog1, prog2, prog3
.PHONY : all
prog1 : prog1.o
cc -o prog1 prog1.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o
cc -o prog3 prog3.o
为什么以上的Makefile可以生成三个可能执行文件prog1,prog2,prog3呢?make会把Makefile文件里第一个目标作为默认目标,所以以all这个伪目标作为默认目标,这个伪目标是不可能产生的实际文件的,它是依赖于三个文件,这三个文件是实际的文件,所以执行到这三个目标后,会生成三个可执行文件。
第七条,静态模式,这个东东好难讲清楚,举个例子:
OBJ = foo.o bar.o
all : $(OBJ)
$(OBJ) : %.o: %.c #这里就是静态模型,意思是等价于 $(OBJ) : foo.c bar.c
$(CC) -c $(CFLAGS) $< -o $@
第八条,自动生成依赖性,即.d文件的规则。让每一个.c文件都生成一个.d的文件Makefile文件,.d文件中就存放对应.c文件的依赖关系。在Makefile文件中写程序.c和 .d的依赖关系,让make自动更新或生成.d文件,并把其包含在我们的主Makefile中,一个模型规则产生的.d文件:
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
这个规则的意思是,所有的[.d]文件依赖于[.c]文件,“rm -f $@”的意思是删除所有的目标,也就是[.d]文件,第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成依赖文件,“$@”表示模式“%.d”文件,如果有一个C文件是name.c,那么“%”就是“name”,“$$$$”意为一个随机编号,第二行生成的文件有可能是“name.d.12345”,第三行使用sed命令做了一个替换,关于sed命令的用法请参看相关的使用文档。第四行就是删除临时文件。
第九条嵌套执行make,大的工程中,不同的模块源文件可能在不同的目录中,每个目录都可以写一个相应的Makefile,这有利于让我们的Makefile变得更加简洁。
例如,有一个子目录subdir,这个目录有个Makefile文件,来指明了这个目录下的文件编译规则,我们总控的Makefile可以这样书写:
subsystem:
cd subdir && $(MAKE) #MAKE是变量,表示make,可能有一些参数
另外,使用export声明变量,可以传递到子目录下的Makefile中使用
一些默认变量:
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a (bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。