Skip to content

LV120-命令包

在 Makefile 中,如果出现一些重复的命令序列,我们可以将这些命令定义成一个可重用的命令包(也称为命令模板)。这样可以提高 Makefile 的可读性和维护性。

一、命令包简介

1. 命令包的定义

定义命令包的语法以 define 开始,以 endef 结束,如:

makefile
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

这里,run-yacc 是这个命令包的名字,不要与 Makefile 中的变量重名。在 defineendef 之间的多行内容就是命令序列。这个命令包中的第一个命令是运行 Yacc 程序,因为 Yacc 程序总是生成 y.tab.c 的文件,所以第二行的命令就是把这个文件重命名。

2. 命令包的使用

我们放到一个示例中来看看:

makefile
foo.c : foo.y
	$(run-yacc)

我们可以看到,要使用这个命令包,我们就像使用变量一样。在这个命令包的使用中,命令包 run-yacc 中的 $^ 就是 foo.y$@ 就是 foo.c。Make 在执行命令包时,命令包中的每个命令会被依次独立执行。

3. 命令包的特点

(1)变量替换:命令包中的变量在使用时会自动替换为实际值(如 $^$@ 等自动化变量)。

(2)命令独立执行:命令包中的每个命令都会被独立执行,就像写在目标规则中的命令一样。

(3)可重用性:可以多次在不同的规则中使用同一个命令包。

4. 注意事项

(1)变量名冲突:命令包名称不能与 Makefile 中的变量名重名。

(2)自动化变量:命令包中的自动化变量(如 $^$@)在使用时会被自动替换为对应的实际值。

(3)命令执行:命令包中的每个命令都会被独立执行,具有与规则中直接书写的命令相同的语义。

(4)缩进规则:命令包内部的命令必须按照 Makefile 的缩进规则进行缩进(使用 Tab 键)。

二、实际应用示例

下面是一个更复杂的命令包示例,展示了如何在多个规则中复用命令序列:

makefile
# 定义一个编译C文件的命令包
define compile-c
$(CC) $(CFLAGS) -c $< -o $@
endef

# 定义一个链接目标文件的命令包
define link-binary
$(CC) $(LDFLAGS) $^ -o $@
endef

# 使用命令包
main: main.o utils.o
	$(link-binary)

main.o: main.c
	$(compile-c)

utils.o: utils.c
	$(compile-c)

在这个例子中,我们定义了两个命令包:

  • compile-c:用于编译C源文件为目标文件
  • link-binary:用于链接目标文件生成可执行文件

这样可以避免重复书写相似的编译和链接命令。