makefile 书写规则
makefile中应该有一个目标
其他的目标是被这个目标所连带出来的,如果有很多个目标,那么make的第一个目标会称为最终目标
规则举例:
foo.o:foo.c defs.h #foo模块
cc -c -g foo.c
这个规则告诉我们两件事情:
1.文件的依赖关系foo.o 依赖于foo.c和defs.h沃尔玛可哦啊吗。如果foo.c和defs.h文件日期要比foo.o的文件日期要新,或者是foo.o并不存在,那么发生依赖关系
2.如果生成foo.o文件,也就是那个cc指令,其说明了如何生成foo.o这个文件(当然foo.c文件include了defs.h文件)
5.3在规则中使用通配符
如果我们想定义一系列比较类似的文件。我们很自然而然的使用通配符。make 中支持三种通配符%,×
比如*.c 标识后缀为c的文件
首先来看几个例子
clean:
rm -f *.o
上面这个例子不多说,这是操作系统的通配符,这是在命令中的通配符
print:*.c
lpr -p $?
touch orubt
上面这个例子说明了通配符也在我们的规则中,目标依赖于printf 所有的[.c]文件,其中$是一个自动化变量
objects = *.o
上面这个例子objects并不会展开,如果逆向让他展开需要使用
objects := $(wildcard *.o)
这种用法由关键字wildcard指出
5.4 文件搜索
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目
录中。所以,当 make 需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个
路径告诉 make ,让 make 在自动去找。
Makefile 文件中的特殊变量 “VPATH” 就是完成这个功能的,如果没有指明这个变量, make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么, make 就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:../headers
上面的定义指定两个目录src接../headers,make会按照这个顺序来查找,目录由冒号分割。
另一个设置文件搜索的路径是使用的make vpath 关键字,这不是变量,这是一个make的关键字
以下的方法有三种
1.vpath <pattern> <dir>
为符合模式的文件制定搜索目录
2.vpath <pattern>
清除复合模式的的文件的搜索目录
3.vpath
清除所有已经被设置好的文件搜索目录
vpath使用需要包含的%字符。%的意思是匹配若干个字符,例如,”%.h”表示所有以.h文件结尾的文件,而directories定义了要搜索的目录。
5.5伪目标
最早我们提出的clean 就是一个伪目标
clean:
rm *.o temp
伪目标不是一个文件,只是一个标签
PHONY 指明一个目标是伪目标
PHONY :clean
clean:
rm *.o temp
5.7 静态模式
我们看一个例子:
objects = foo.o bar.o
all:$(objects)
$(objects):%.o:%.c
$(CC) -c $(CFLAGS) $ < -o $@
$< 标识所有的依赖集(也就是 foo.c bar.c)。$@表示目标集(foo.o bar.o)
等价于:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
5.8 自动生成依赖性
makefile中-M属性可以自动寻找源文件包含的头文件,并且生成一个依赖关系
比如执行
cc -M main.c
其输出的是
main.o : main.c defs.h
这样可以让编译器自己生成依赖规则
%d:%.c
@set -e;rm -f $@;\
$(CC) -M $(CPPFLAGS) $< >$@.$$$$;
rm -f $@.$$$$
6 书写命令
make默认是/bin/sh
@会隐藏命令输出
exec:
cd /home/hchen
pwd
exec:
cd /home/hchen; pwd
6.3 命令出错
如果我们在指令前加入减号,表示不管命令执行成功与失败都默认为成功
我们make的时候有-k 指令 表示不管指令是否成功都继续执行。
6.4嵌套执行make
我们有时候makefile会被分配到多个目录下面 ,我们的总控makefile可以这样写:
subsystem:
cd subdir && $(MAKE)
等价于:
subsystem:
$(MAKE) -C subdir
我们把这个makefile叫做主控makefile,总控makefile的变量可以传递到下级的makefile中,但是不会覆盖下面的makefile中定义的变量,除非指定了”-e”参数,如果你想把变量传递到下级makefile中
可以声明
export <variable>
如果你不想让某些变量传递到下级:
unexport <variable ...>
例如:
示例一:
export variable = value
其等价于:
variable = value
export variable
其等价于:
export variable := value
其等价于:
variable := value
export variable
示例二:
export variable += value
其等价于:
variable += value
export variable
如果你要传递所有的变量,那么,只要一个export就可以了
我们要注意两个变量,一个是SHELL,一个是MAKEFLAGS,这两个变量不管你是否export都要传递到下层的makefile中,特别MAKEFLAGS其中包含了make的参数信息如果我们执行总控的makefile,上层定义了这个变量,那么它将会传递到下一层,因为他是一个系统级的变量。
但是makefile的几个参数并不往下传递 -C -f -h -o -w
还有一个执行嵌套比较有用的参数,”-w”或者是”-print-directory”会在make的过程中输出一些信息,让你看到当前的工作目录,比如我们make的下级目录是/home/hchen/gnu/make,如果我们使用make -w来执行,那么进入这个目录的时候,我们会看到
make:Entering directory `/home/hchen/gun/make`
而在完成make 离开目录的时候我们会看到
make: Leaving directory `/home/hchen/gnu/make
当你使用-c参数来指定下层makefile的时候,-w总是会被打开,如果参数中有-s,或者是-no-print-directory,那么-w总是失效的。
6.5 定义命令包
如果makefile中出现了一些相同的命令序列,那么我们可以为这些相同的命令定义一个变量,定义变量从define开始到endef结束,如:
define run-yacc
yacc $(firstw ord $^)
mv y.tab.c $@
endef
我们使用这个命令包
foo.c: foo.y
$(run-yacc)
命令包中的”run-yacc”中的$^忽悠上古foo.y,$@就是foo.c