Makeflie 中允许四种方式定义变量
x = foo
x := foo
x ?= foo
x += foo
x = foo
定义的特点是允许使用未赋值的变量进行定义,例如
x = $(y)
y = foo
y 的值是在为 x 赋值后赋值的,但是此时 x 仍然能成功赋值为 foo
这样做带来的问题就是会出现递归的赋值,如
x = $(y)
y = $(x)
这样会导致 make 出现错误,为了避免这种情况,可以使用x := foo
进行赋值,例如
x := foo
y := $(x)
x := bar
这时x的值为 bar,y 的值为 bar,如果使用在后面定义的变量则不会有值,如
x := $(y) foo
y := bar
这时 x 的值为 foo 而不是 foobar
x ?= foo
的作用是如果 x 在前面没有值则赋值为 foo,若有值则什么也不干
x += foo
的作用是在 x 的后面追加赋值,若 x 没有值则等价与 :=,例如
x += foo
x += bar
这时 x 的值为 foobar
Makefile 中可以替换变量中共有的部分,例如
foo := a.o b.o c.o bar := $(foo: .o = .c)
则 bar 的值即为 a.c b.c c.c,也可使用如下方式替换
foo := a.o b.o c.o bar := $(foo: %.o = %.c)
这样bar 的值即也为 a.c b.c c.c,%表示任意长度的非空字符串
以上是在网上书上很多地方都看见过这样的用法,但是经过实测发现
不能这样赋值
不能这样赋值
不能这样赋值
我的make版本是GNU make 4.1,如果哪位大神知道怎样使用这种赋值方法请联系我
如果要实现相同的功能应采用如下的方式
foo :=a.o b.o c.o
bar :=$(patsubst %.o, %.c, $(foo))
patsubst 的作用是替换变量中的通配符,这时 bar 的值是 a.c b.c c.c
Makefile 中允许使用目标变量和模式变量,例如
CC = gcc
main: CFLAGS = -o
%.o : CFLAGS = -c
main: main.o insert.o search.o
$(CC) $(CFLAGS) main main.o insert.o search.o
main.o: main.c
$(CC) $(CFLAGS) main.c
insert.o: insert.c
$(CC) $(CFLAGS) insert.c
search.o: search.c
$(CC) $(CFLAGS) search.c
clean:
rm *.o
rm main
此时在目标 main 中 CFLAGS 的值为 -o 而在符合 %.o 这个模式的目标中 CFLAGS 的值为 -c
Makefile 中根据目标和依赖文件定义了一系列自动化变量,如下表
变量 | 说明 |
---|---|
$@ | 表示目标,如果有多个目标则表示他们的集合,以空格分割 |
$% | 表示静态库的一个成员名。例如,目标是 foo.a(bar.o),那么,$% 的值就为 bar.o,$@ 的值为 foo.a 如果目标不是静态库文件,其值为空 |
$^ | 表示所有依赖目标的集合,如果依赖目标中出现了重复的则会自动去除掉重复的 |
$+ | 表示所有依赖目标的集合,但是不会去除掉重复的 |
$< | 表示依赖目标中第一个目标的文件名,如果目标以模式(即%)定义的,则是他们的集合 |
$? | 表示所有比目标新的依赖目标的集合 |
$* | 表示模式中 % 及其之前的部分,如果目标是 /home/foo.o,且目标模式为 /home/%.o 则 $* 的值为 /home/foo,如果目标没有模式但目标的后缀能被 make 识别则 $* 的值为除了后缀的那一部分,后缀不能识别则为空 |
需要注意的是这些自动化变量在隐含规则中并没有意义,使用了自动化变量的 Makefile 文件如下
main: main.o insert.o search.o
gcc -o $@ $^
clean:
rm *.o
rm main