在 makefile 中指定组合目标
Specifiy a combined target in a makefile
使用 GNU Make,如何确保在最终任务运行之前建立其他目标依赖项?
(我知道这有点滥用make,但是可以吗?)
假设我有 2 个目标 a 和 b。仅构建 a 或仅构建 b 很容易,但如果同时针对 a 和 b,我想触发一种特殊类型的构建。
例如我的Makefile(由一个真实问题简化而来)
a_prereq:
@echo "making a"
b_prereq:
@echo "making b"
a: a_prereq default
b: b_prereq default
default:
@echo "made!"
调用 make a
打印 making a; made!
。这是正确的。
调用 make b
打印 making b; made!
。这是正确的。
调用 make a b
打印 making a; made!; making b
。不是我想要的!
如果我只能更改 makefile 而不能更改调用 make a b
.
,我如何让 make a b
打印 making a; making b; made!;
(我知道我可以引入 c: a_prereq b_prereq default
并调用 make c
但是如果没有新目标可以完成吗?)
这看起来像一个 XY 问题。您显然想要的(不是 100% 确定)是强制 default
在 a_prereq
和 b_prereq
之后构建,当且仅当 a
和 b
目标在命令行上传递。这很奇怪,并不是 make 的真正用途,但让我们试一试。
强制 default
在 a_prereq
和 b_prereq
之后构建,即使使用并行 make,也很简单:将它们声明为 default
的先决条件(事实上,我这样做不知道另一种方法):
default: a_prereq b_prereq
@echo "made!"
或者,如果您希望将先决条件声明与配方声明分开:
default: a_prereq b_prereq
default:
@echo "made!"
但正如您所希望的那样,仅当 a
和 b
目标在命令行上传递时,我们才需要检测这种情况。幸运的是 MAKECMDGOALS
GNU make 变量列出了在命令行上指定的目标。所以一点 filter
应用到它应该成功。
当且仅当 a
和 b
目标在命令行上传递时,我们可以将 make 变量 MATCH
设置为字符串 ab
。我们可以使用 make 条件语句 (ifeq
) 声明 a_prereq
和 b_prereq
作为 default
的先决条件当且仅当 $(MATCH)
等于 ab
。只需将以下 4 行添加到您的 Makefile 中:
MATCH := $(filter a,$(MAKECMDGOALS))$(filter b,$(MAKECMDGOALS))
ifeq ($(MATCH),ab)
default: a_prereq b_prereq
endif
注意:如果真正的 default
配方使用作为先决条件扩展的自动变量($<
、$^
、...),您必须记住它们的值make a
和 make a b
...
不同
注意:如果目标 a
和 b
必须重建但未作为目标传递到命令行,则此操作将无效。例如,如果 a
和 b
是另一个请求目标的先决条件。这是您要求的内容看起来很奇怪的主要原因之一。
注意:如果您还需要在 a_prereq
之后构建 default
当 运行 宁 make a
(与 b
相同)时,一个更简单的解决方案是是:
default: $(patsubst %,%_prereq,$(filter a b,$(MAKECMDGOALS)))
这样,如果您 运行 make a
,a_prereq
被声明为 default
的先决条件,如果您 运行 make b
, b_prereq
被声明为 default
的先决条件,你 运行 make a b
a_prereq
和 b_prereq
都被声明为 default
的先决条件,如果你 运行 make foo
,default
根本没有先决条件。
使用 GNU Make,如何确保在最终任务运行之前建立其他目标依赖项?
(我知道这有点滥用make,但是可以吗?)
假设我有 2 个目标 a 和 b。仅构建 a 或仅构建 b 很容易,但如果同时针对 a 和 b,我想触发一种特殊类型的构建。
例如我的Makefile(由一个真实问题简化而来)
a_prereq:
@echo "making a"
b_prereq:
@echo "making b"
a: a_prereq default
b: b_prereq default
default:
@echo "made!"
调用 make a
打印 making a; made!
。这是正确的。
调用 make b
打印 making b; made!
。这是正确的。
调用 make a b
打印 making a; made!; making b
。不是我想要的!
如果我只能更改 makefile 而不能更改调用 make a b
.
make a b
打印 making a; making b; made!;
(我知道我可以引入 c: a_prereq b_prereq default
并调用 make c
但是如果没有新目标可以完成吗?)
这看起来像一个 XY 问题。您显然想要的(不是 100% 确定)是强制 default
在 a_prereq
和 b_prereq
之后构建,当且仅当 a
和 b
目标在命令行上传递。这很奇怪,并不是 make 的真正用途,但让我们试一试。
强制 default
在 a_prereq
和 b_prereq
之后构建,即使使用并行 make,也很简单:将它们声明为 default
的先决条件(事实上,我这样做不知道另一种方法):
default: a_prereq b_prereq
@echo "made!"
或者,如果您希望将先决条件声明与配方声明分开:
default: a_prereq b_prereq
default:
@echo "made!"
但正如您所希望的那样,仅当 a
和 b
目标在命令行上传递时,我们才需要检测这种情况。幸运的是 MAKECMDGOALS
GNU make 变量列出了在命令行上指定的目标。所以一点 filter
应用到它应该成功。
当且仅当 a
和 b
目标在命令行上传递时,我们可以将 make 变量 MATCH
设置为字符串 ab
。我们可以使用 make 条件语句 (ifeq
) 声明 a_prereq
和 b_prereq
作为 default
的先决条件当且仅当 $(MATCH)
等于 ab
。只需将以下 4 行添加到您的 Makefile 中:
MATCH := $(filter a,$(MAKECMDGOALS))$(filter b,$(MAKECMDGOALS))
ifeq ($(MATCH),ab)
default: a_prereq b_prereq
endif
注意:如果真正的 default
配方使用作为先决条件扩展的自动变量($<
、$^
、...),您必须记住它们的值make a
和 make a b
...
注意:如果目标 a
和 b
必须重建但未作为目标传递到命令行,则此操作将无效。例如,如果 a
和 b
是另一个请求目标的先决条件。这是您要求的内容看起来很奇怪的主要原因之一。
注意:如果您还需要在 a_prereq
之后构建 default
当 运行 宁 make a
(与 b
相同)时,一个更简单的解决方案是是:
default: $(patsubst %,%_prereq,$(filter a b,$(MAKECMDGOALS)))
这样,如果您 运行 make a
,a_prereq
被声明为 default
的先决条件,如果您 运行 make b
, b_prereq
被声明为 default
的先决条件,你 运行 make a b
a_prereq
和 b_prereq
都被声明为 default
的先决条件,如果你 运行 make foo
,default
根本没有先决条件。