前面写的makefile的相关只是都没有使用到变量,依照变量,makefile可以使用的非常多变。
foo = $(bar)
bar = Huh?
all:
@echo $(foo)
上面这个例子执行 make 将会打出 Huh?当 make 读到 foo = $(bar) 时,确定 foo 的值是 $(bar) ,但并不立即展开 $(bar) ,然后读到 bar = Huh? ,确定 bar 的值是 Huh?
通过上面这个特点,我们可以讲变量的值推迟到后面去定义:
main.o: main.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
CC = gcc
CFLAGS = -O -g
CPPFLAGS = -Iinclude
像上面这样,编译选项就可以展开生成为:gcc -O -g -Iinclude -c main.c
通常把 CFLAGS 定义成一些编译选项,例如 -O 、 -g 等,而把 CPPFLAGS 定义成一些预处理选项,例如 -D 、 -I 等。
如果希望makefile在遇到赋值的时候立刻展开,可以使用:=来代替= ,下面这个例子
root@wc:~/Codes/Learn# cat makefile
x := foo
y := $(x) bar!
all:
@echo "$(y)"
root@wc:~/Codes/Learn# make all
foo bar!
root@wc:~/Codes/Learn#
如果x 和 y的位置交换,那么赋值的时候x会被展开成为一个空值
还有一种有用的赋值运算符是?=:例如 foo ?= $(bar) 的意思是:如果 foo 没有定义过,那么 ?= 相当于 = ,定义 foo 的值是 $(bar) ,但不立即展开;如果先前已经定义了 foo ,则什么也不做,不会给 foo 重新赋值。
另一种是+=,其可以给变量追加值,+=依旧保持着=或者:=的特性,主要看这个变量原先是怎么定义的。如果变量还没有定义过就直接用 += 赋值,那么 += 相当于 = 。
类似$@这样的特殊变量还有:
$@ ,表示规则中的目标。
$< ,表示规则中的第一个条件。
$? ,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
$^ ,表示规则中的所有条件,组成一个列表,以空格分隔。
按照上面,下面的两条语句实际上就是等价的了:
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main: main.o stack.o maze.o
gcc $^ -o $@
这样即使以后又往条件里添加了新的目标文件,编译命令也不需要修改,减少了出错的可能。
$? 变量也很有用,有时候希望只对更新过的条件进行操作,例如有一个库文件 libsome.a 依赖于几个目标文件:
libsome.a: foo.o bar.o lose.o win.o
ar r libsome.a $?
ranlib libsome.a
这样,只有更新过的目标文件才需要重新打包到 libsome.a 中,没更新过的目标文件原本已经在 libsome.a 中了,不必重新打包。
第一节中可以看到默认规则中有很多变量,类似CC,CFLAGS,CC默认值为cc,而CFLAGS的默认值为空,类似的变量还有很多:
AR 静态库打包命令的名字,缺省值是 ar 。
ARFLAGS 静态库打包命令的选项,缺省值是 rv 。
AS 汇编器的名字,缺省值是 as 。
ASFLAGS 汇编器的选项,没有定义。
CC C编译器的名字,缺省值是 cc 。
CFLAGS C编译器的选项,没有定义。
CXX C++编译器的名字,缺省值是 g++ 。
CXXFLAGS C++编译器的选项,没有定义。
CPP C预处理器的名字,缺省值是 $(CC) -E 。
CPPFLAGS C预处理器的选项,没有定义。
LD 链接器的名字,缺省值是 ld 。
LDFLAGS 链接器的选项,没有定义。
TARGET_ARCH 和目标平台相关的命令行选项,没有定义。
OUTPUT_OPTION 输出的命令行选项,缺省值是 -o $@ 。
LINK.o 把 .o 文件链接在一起的命令行,缺省值是 $(CC) $(LDFLAGS) $(TARGET_ARCH) 。
LINK.c 把 .c 文件链接在一起的命令行,缺省值是 $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)$(TARGET_ARCH) 。
LINK.cc 把 .cc 文件(C++源文件)链接在一起的命令行,缺省值是 $(CXX) $(CXXFLAGS)$(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) 。
COMPILE.c 编译 .c 文件的命令行,缺省值是 $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c 。
COMPILE.cc 编译 .cc 文件的命令行,缺省值是 $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c 。
RM 删除命令的名字,缺省值是 rm -f 。