第二章、变量和模式
1. 变量
同其他编程语言一样,Makefile 支持变量的语法。使用变量可以代替一段字符串,在需要的时候可以使用引用变量的方式来将变量的值(字符串)替换到相应的位置。
使用变量可以让 Makefile 更易于阅读和修改。
在了解变量之前,我们先来了解 make 命令执行的两个阶段。第一阶段读取 Makefile(或makefile)文件,解析其内置变量及值,构造目标和依赖等。第二阶段是根据目标执行规则。
变量的四种定义方法
# 创建立即变量
立即变量名 := 值(立即计算)
# 创建延时变量
延时变量名 = 值(延时计算)
# 如果没有定义变量时使用创建延时变量
延时变量名 ?= 值(延时计算)
# 在原有变量上追加值
延时变量名或立即变量名 += 值
说明:
- 变量创建需要在 Makefile 内部书写,不能写在规则中。
- 立即变量会在创建变量是直接计算值并交给变量。
- 延时变量在创建时不会计算值,只有在使用时才会动态的计算其值(即延时计算)。
?=是在没有此变量时,使用该值创建延时变量,如果变量已经存在则不执行赋值操作。+=是在已有变量的基础上追加值,如果变量是立即变量则立即计算该值,如果变量是延时变量则延时计算该值。
示例:
简化上节课的 Makefile 文件如下:
.PHONY: all clean
all: hello # 编译最终目标
hello : hello.o
gcc -o hello hello.o
hello.o : hello.c
gcc -o hello.o -c hello.c
clean: # 清除目标文件
rm hello.o
现在我们依旧可以使用 hello.c 来生成 hello 这个可执行文件。
现在有个需求,就是将生成的可执行程序由 hello 改成 myapp,将目标文件名由 hello.o 改为 temp.o。每次名称的修改我们都要修改多处,并容易出错。如果以后还会有改动,那我们最好使用变量。
我们将 hello 用立即变量 TARGET 代替。hello.o 用立即变量 OBJECT 代替。
示例:
改写后的 Makefile 文件如下:
.PHONY: all clean
# 创建立即变量 TARGET、OBJECT 并立即取值
TARGET := hello
OBJECT := hello.o
all: $(TARGET) # 编译最终目标
$(TARGET) : $(OBJECT)
gcc -o $(TARGET) $(OBJECT)
$(OBJECT) : hello.c
gcc -o $(OBJECT) -c hello.c
clean: # 清除目标文件
rm $(OBJECT)
其中 TARGET := hello 和 OBJECT := hello.o 是创建两个立即变量。后续使用 $(TARGET) 和 $(OBJECT) 是变量引用。
变量引用
变量引用 是取其变量的值,将其放入到引用的地方。
变量引用的语法
$(变量名)
# 或
${变量名}
说明:
- 使用
$()和${}的两种语法没有实质的区别。两者可以替换。
上述使用变量的 Makefile 和没有使用变量的 Makefile 效果相同。但如果将生成的可执行文件改名为 myapp 则只需要修改变量 TARGET 的值即可,如:TARGET := myapp
立即变量和延迟变量的区别:
- 立即变量会在 赋值
:=或+=时直接计算变量值并改变变量,即在 make 执行的第一阶段计算值。 - 延时变量会在 赋值
=、+=或?=时只赋值表达式,在变量引用时才计算变量值,即在 make 执行的第二阶段计算值。
立即变量示例
# 创建MYVAR1 变量
MYVAR1 := aaa
# 取 MYVAR1的值作为 MYVAR2的值
MYVAR2 := $(MYVAR1)
# 修改MYVAR1变量的值
MYVAR1 := bbb
all:
echo "MYVAR1: $(MYVAR1)"
echo "MYVAR2: $(MYVAR2)"
执行结果如下:
weimingze@mzstudio:~$ make
echo "MYVAR1: bbb"
MYVAR1: bbb
echo "MYVAR2: aaa"
MYVAR2: aaa
延时变量示例
# 创建MYVAR1 变量
MYVAR1 := aaa
# 取 MYVAR1的值作为 MYVAR2的值
MYVAR2 = $(MYVAR1)
# 修改MYVAR1变量的值
MYVAR1 := bbb
all:
echo "MYVAR1: $(MYVAR1)"
echo "MYVAR2: $(MYVAR2)"
执行结果如下:
weimingze@mzstudio:~$ make
echo "MYVAR1: bbb"
MYVAR1: bbb
echo "MYVAR2: bbb"
MYVAR2: bbb
上述两个示例的差别在于 MYVAR2 := $(MYVAR1) 和 MYVAR2 = $(MYVAR1),但从结果上却有所不同。MYVAR2 := $(MYVAR1) 是立即算出 MYVAR2 的值。而 MYVAR2 = $(MYVAR1) 则是在 $(MYVAR2) 变量引用时才计算其值。
实验
尝试创建立即变量和延时变量,再尝试使用 ?= 和 += 修改变量的值,推断 Makefile 的执行过程。