makefile可以使用变量,使用变量可以使makefile变的更加紧凑,但是makefile中的变量和通常意义上的变量有所不同。makefile文件中的变量代表了一个字符串。
一、使用普通变量
用户可以在makefile中定义变量,makefile文件中的变量代表了一个字符串。因此这些变量更像是C语言中的宏,在makefile文件执行过程中会展开在所使用的地方。makefile变量的命名可以包含字符、数字、下划线(可以是数字开头),并且大小写敏感。传统的makefile的变量名是全大写的命名方式。
makefile变量在声明的时候需要对其进行赋值,而在使用该变量时需要在变量名前加上$符号,例如$(VARNAME)。如果用户需要在makefile文件中使用$字符,则用$$来表示,这种应用多出现在对shell变量的使用上。
下面演示在makefile中使用变量:
objects = main.o kdb.o command.o display.o \ insert.o serach.o files.o utils.oedit : $(objects) gcc -o edit $(objects)main.o: main.c defs.h #生成 main.o gcc -c main.ckdb.o: kdb.c defs.h command.h #生成 kdb.o gcc -c kdb.ccommand.o: command.c defs.h command.h #生成 command.o gcc -c command.cdisplay.o: display.c defs.h buffer.h #生成 display.o gcc -c display.cinsert.o: insert.c defs.h buffer.h #生成 insert.o gcc -c insert.cserach.o: serach.c defs.h buffer.h #生成 serach.o gcc -c serach.cfiles.o: files.c defs.h buffer.h command.h #生成 files.o gcc -c files.cutils.o: utils.c defs.h #生成 utils.o gcc -c utils.cclean: rm edit $(objects).PHONY : clean
在很多情况下,用户应将编译器及编译器选项定义为变量,这样可以增强makefile文件的灵活性。下面演示了使用这中方法的编译器工程的makefile文件,该makefile文件中的编译器和变异选项都是可以替换的。
CC = gccFLAGS = -cobjects = main.o kdb.o command.o display.o \ insert.o serach.o files.o utils.oedit : $(objects) $(CC) -o edit $(objects)main.o: main.c defs.h #生成 main.o $(CC) $(FLAGS) main.ckdb.o: kdb.c defs.h command.h #生成 kdb.o $(CC) $(FLAGS) kdb.ccommand.o: command.c defs.h command.h #生成 command.o $(CC) $(FLAGS) command.cdisplay.o: display.c defs.h buffer.h #生成 display.o $(CC) $(FLAGS) display.cinsert.o: insert.c defs.h buffer.h #生成 insert.o $(CC) $(FLAGS) insert.cserach.o: serach.c defs.h buffer.h #生成 serach.o $(CC) $(FLAGS) serach.cfiles.o: files.c defs.h buffer.h command.h #生成 files.o $(CC) $(FLAGS) files.cutils.o: utils.c defs.h #生成 utils.o $(CC) $(FLAGS) utils.cclean: rm edit $(objects).PHONY : clean
当需要使用新的编译器对其进行编译时,只需要更改变量CC和变量FLAGS即可。
二、变量中的变量
在makefile文件中定义变量的值时,用户可以使用其他变量来构造变量的值。在makefile中使用变量定义变量值的方式有三种。
1.使用“=”操作符
该方式非常简单,=左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处。也就是说,右侧的变量不一定是已定义好的值,其也可以使用其后面定义的值。下面演示=的使用:
foo = $(bar)bar = $(ugh)ugh = hello?all : echo $(foo)
执行结果为:
由上可知,makefile中的变量是可以使用后面的变量来定义的。这种定义变量值的方法有一个潜在的危险就是递归定义。例如:
a = $(b)b = $(a)
make会检测出这种错误。
2.使用“:=”操作符
使用“:=”操作符定义变量的值可以避免前述递归定义的危险。使用其定义变量时,前面的变量不能使用后面的变量,只能使用前面已定义好的变量。如果使用前面未定义变量,则该变量为空。下面演示这样的定义:
y := $(x) barx := $(foo)all : echo $(y).PHONY : all
执行结果为:
输出的值是变量y的值,由于在定义y值时x的变量未定义,所以其值为空。
3.使用“?=”操作符
该操作符的含义是,如果变量之前没有被定义过,那么变量的值就被定义。如果变量的值之前已被定义过,则赋值语句什么也不做。下面实例演示了使用“?=”定义一个变量:
a := hellob ?= worlda ?= HELLOall : echo $(a) echo $(b).PHONY : all
执行结果如下:
由于变量a在a ?= HELLO之前已经被定义,所以a变量的值没有被改变。b变量在“b ?= world”之前没有定义,所以变量b的值被定义为world。
三、追加变量的值
makefile文件允许给一个变量追加一个值,其操作符为“+=”。由于makefile文件的变量本身是一个字符串,所以追加操作实际上是一个字符串链接操作,如下:
objects = main.o foo.o bar.oobjects += another.o
上面的代码等价于:
objects = main.o foo.o bar.oobjects = $(objects) another.o
如果变量之前没有定义过,“+=”操作符会自动变成“=”操作符,如果前一次变量定义时使用“:=”操作符,“+=”会以“:=”作为其操作符,如下:
objects := main.o foo.o bar.oobjects += another.o
等价于:
objects = main.o foo.o bar.oobjects := $(objects) another.o
四、自动化变量
makefile中允许使用自动化变量,这些变量的名称是由make工具已经定义好的。makefile中一共有7个自动化变量,如下:
自动化变量 | 表示的意义 |
$@ | 表示规则中的目标文件集 |
$% | 仅当目标是函数库文件时,表示规则中的目标成员名。例如,一个目标是foo.a(bar.o),那么,$%就是bar.o,$@就是foo.a。如果目标文件不是函数库文件,其值为空 |
$< | 依赖列表中的第一个依赖的名字 |
$? | 所有比目标新的依赖的合集,以空格分隔 |
$^ | 所有依赖的集合,以空格分隔。如果依赖中有多个重复的,只保留一份 |
$+ | 这个变量很像$^,也是所有依赖的集合,但是它不去除重复的依赖 |
$* | 这个变量表示目标模式中“%”及之前的部分 |