make和Makefile中的规则和变量
make机制的运行环境需要一个命令行程序make和一个文本文件Makefile。
make命令执行后有3个退出码:
|
make的使用格式是:
make [options] [target] ...
options为make工具的参数选项,target为makefile中指定的目标。
make工具的参数选项
选项 |
含义 |
-f filename |
显式地指定文件作为Makefile |
-C dirname |
指定make在开始运行后的工作目录为dirname |
-e |
不允许在Makefile中替换环境变量的赋值 |
-k |
执行命令出错时,放弃当前目标,继续维护其他目标 |
-n |
按实际运行时的执行顺序模拟执行命令(包括用@开头的命令),没有实际执行效果,仅仅用于显示执行过程 |
-p |
显示makefile中所有的变量和内部规则 |
-r |
忽略内部规则 |
-s |
执行但不显示命令 |
-S |
如果执行命令出错就退出 |
-t |
修改每个目标文件的创建日期 |
-I |
忽略运行make中执行命令的错误 |
-V |
显示make的版本号 |
make操作管理Makefile文件的规则
|
在makefile中,目标名称的指定通常有以下惯例:
|
Makefile的书写规则
Makefile的书写规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
Makefile中只有一个最终目标,第一条规则中的第一个目标将被确立为最终的目标。
Makefile里主要包含了5方面的内容:显式规则、隐式规则、变量定义、文件指示和注释。
|
Makefile的基本语法规则
Makefile的语法格式如下:
targets : prerequisites
command
...
或者是:
targets : prerequisites ; command
command
...
targets是目标文件名,多个文件以空格分开,可以使用通配符。一般说来,Makefile的目标是一个文件,但也有可能是多个文件。
prerequisites是目标所依赖的文件(或依赖目标)。
command是命令行,如果它不与”targets:prerequisites”在一行,那么必须以Tab键开头,如果和prerequisites在同一行,那么可以用分号作为分隔。如果命令太长,可以使用反斜杠“\”作为换行符。make对一行中有多少个字符没有限制。
对于Makefile文件: all : main.c foo1.c foo2.c foo3.c gcc main.c foo1.c foo2.c foo3.c -o all all是Makefile时最终目标,main.c,foo1.c,foo2.c,foo3.c是目标所依赖的源文件,而只有一个命令“gcc main.c foo1.c foo2.c foo3.c -o all”是生成目标的方法:
|
在规则中使用通配符
make支持3种通配符:“*”,“?”,“[...]”。
“~”字符在文件名中有特殊用途:比如“~/test”表示当前用户的$HOME目录下的test目录;“~zhangfan/test”则表示用户zhangfan的宿主目录下的test目录。
通配符代替了一系列的文件,如”*.c”表示了所有后缀名为.c的文件。如果文件名中含有通配符,如“*”,那么可以用转义字符斜杠”\”,如“\*”来表示真实的”*“字符,而不是任意长度的字符串。
可以使用一个特殊的标记“.PHONY”来显式地指明一个目标是伪目标,向make说明,不管是否有这个文件,这个目标都是伪目标:
.PHONY : clean
只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只要在命令提示符下输入命令“make clean”即可。于是整个过程可以这样写,例如:
.PHONY : clean
clean :
rm all main.o kbd.o command.o \
insert.o search.o files.o
自动生成依赖关系
可以使用GNU的C/C++编译器的“-MM”参数选项,使其自动寻找源文件中包含的头文件,并生成一个依赖关系。例如main.c文件中有defs.h头文件,那么:
gcc -MM main.c
其输出是:
main.o : main.c defs.h
变量
变量在声明时需要给予初值,而在使用时,需要在变量名前加上“$”符号,但最好用小括号“()”或是花括号”{}”把变量给引用起来。如果使用真实的”$”字符,那么需要用”$$”来表示。
下面Makefile等同:
objects=program.o foo.o utils.o
program:$(objects)
cc -o program $(objects)
$(objects):defs.h
等同于:
objects=program.o foo.o utils.o
program:program.o foo.o utils.o
cc -o program program.o foo.o utils.o
program.o foo.o utils.o:defs.h
赋值变量
1、使用“:=”操作符,使得前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。
2、使用”?=”操作符:例如foo ?= bar 如果foo没有被定义过,那么变量foo的值就是“bar”,否则此语句什么也不做,这段代码等同于:
ifeq($(origin foo),undefined)
foo=bar;
endif
3、使用“+=”操作符,可以追加值,
objects=main.o foo.o bar.o
objects+=another.o
等同于
objects=main.o foo.o bar.o
objects:=$(objects) another.o
define关键字
使用define定义的命令变量中没有以“Tab”键开头。
define two-lines
echo foo
echo $(bar)
endef
这段代码将变量two-lines定义为两条命令echo foo和echo $(bar)。
override指示符
有的变量时通过make的命令行参数进行设置的,那么Makefile将忽略这个变量的赋值。如果想在Makefile中设置这类参数的值,那么可以使用“override”指示符。
override =
override :=
override +=
在define关键字中也同样可以使用override指示符:
override define foo
bar
endef
目标变量和模式变量
1、目标变量
:
:override
为目标序列,可以是各种赋值表达式,如”=”、”:=“,”+=“,”?=”。第二个语法针对于make命令行参数带入的变量,或是系统环境变量。
prog : CFLAGS=-g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
$(CC) $(CFLAGS) prog.c
foo.o : foo.c
$(CC) $(CFLAGS) foo.c
bar.o : bar.c
$(CC) $(CFLAGS) bar.c
等同于
prog : prog.c foo.c bar.o
gcc -g prog.o foo.o bar.o
prog.o : prog.c
gcc -g prog.c
foo.o : foo.c
gcc -g foo.c
bar.o : bar.c
gcc -g bar.c
2、模式变量
可以给定一种“模式”,把变量定义在符合这个模式的所有目标中。
:
:override
是模式序列,可以是多种模式,override同样是针对系统环境传入的变量或是make命令行指定的变量。
make的模式变量一般是至少含有一个“%”的,所以,可以以如下方式给所有以”.o”结尾的目标定义目标模式变量:
%.o : CFLAGS=-o