如何强制 make 重新启动并重新加载生成的 makefile?
How to force make to restart and reload generated makefiles?
手头的任务如下:在配方中调用的外部工具生成一个 makefile,该 makefile 应立即包含在 make 中。然后,另一个规则,使用包含的数据生成进一步的包含文件。 Make 应该重新启动,然后才处理进一步的规则。考虑以下示例:
$(info ------- Restart $(MAKE_RESTARTS))
all :
include a
include b
a : p
touch a
b : a
touch b
像这样工作:
touch p
make
------- Restart
touch a
touch b
------- Restart 1
make: Nothing to be done for 'all'.
我的问题是规则 b 需要 a 中包含的数据,但 b 是在包含 a 的更新版本之前执行的。
在执行 b 之前应该重新启动 Make。如何实现?我想看这个:
touch p
make
------- Restart
touch a
------- Restart 1
touch b
------- Restart 2
make: Nothing to be done for 'all'.
很容易检测是否包含a,当a不包含时可以隐藏b的规则。这适用于干净的构建,但当 a 已经存在于先前构建的磁盘上并且由于 p 已更新而触发规则时则无效。
只有 make 知道,规则 a:p 是否是最新的,无法用条件表达式检查。
有解决办法吗?
更新:根据@MadScientist 的建议,我是这样工作的:
$(info ------- Restart $(MAKE_RESTARTS))
all :
include b
include a
a : p
@echo rule A
touch a
$(eval upd=1)
b : a
@echo rule B
$(if $(upd),@echo b skipped,touch b)
并且输出:
touch p
make
------- Restart
rule A
touch a
rule B
b skipped
------- Restart 1
rule B
touch b
------- Restart 2
完美!谢谢大家,大家圣诞快乐。
有不止一种方法可以做到这一点(通常使用 Make)。
我会这样做:将 include b
语句放入 a
。
$(info ------- Restart $(MAKE_RESTARTS))
all :
-include a
a : p
touch a
@echo -include b >> a
b : a
touch b
一个解决方案是调用子 make 来构建 b
。该子品牌将包括较新的 a
,因此是正确的。我相信这样的事情会起作用(未经测试):
$(info ------- Restart $(MAKE_RESTARTS))
all :
include a
include b
a : p
touch a
ifeq ($(filter real_b,$(MAKECMDGOALS)),)
b : a
$(MAKE) real_b
endif
.PHONY: real_b
real_b:
touch b
另一个解决方案是确保 b
在 a
更新时 不 更新。也许是这样的(同样,未经测试):
$(info ------- Restart $(MAKE_RESTARTS))
all :
include a
include b
BUILT_A =
a : p
touch a
$(eval BUILT_A = true)
b : a
$(if $(BUILT_A),,touch b)
(在配方中罕见地合法使用 eval
!)在此版本中,如果构建了 a
,则不会触及 b
。这样在 make re-execs 本身之后它将包括 a
和包括 b
,然后看到 a
是最新的但看到 b
是过时的(因为我们第一次跳过构建步骤)并重建 b
:这次 b
将被更新,因为 a
在上一次传递中被更新,然后 make 将再次重新执行。
手头的任务如下:在配方中调用的外部工具生成一个 makefile,该 makefile 应立即包含在 make 中。然后,另一个规则,使用包含的数据生成进一步的包含文件。 Make 应该重新启动,然后才处理进一步的规则。考虑以下示例:
$(info ------- Restart $(MAKE_RESTARTS))
all :
include a
include b
a : p
touch a
b : a
touch b
像这样工作:
touch p
make
------- Restart
touch a
touch b
------- Restart 1
make: Nothing to be done for 'all'.
我的问题是规则 b 需要 a 中包含的数据,但 b 是在包含 a 的更新版本之前执行的。 在执行 b 之前应该重新启动 Make。如何实现?我想看这个:
touch p
make
------- Restart
touch a
------- Restart 1
touch b
------- Restart 2
make: Nothing to be done for 'all'.
很容易检测是否包含a,当a不包含时可以隐藏b的规则。这适用于干净的构建,但当 a 已经存在于先前构建的磁盘上并且由于 p 已更新而触发规则时则无效。 只有 make 知道,规则 a:p 是否是最新的,无法用条件表达式检查。
有解决办法吗?
更新:根据@MadScientist 的建议,我是这样工作的:
$(info ------- Restart $(MAKE_RESTARTS))
all :
include b
include a
a : p
@echo rule A
touch a
$(eval upd=1)
b : a
@echo rule B
$(if $(upd),@echo b skipped,touch b)
并且输出:
touch p
make
------- Restart
rule A
touch a
rule B
b skipped
------- Restart 1
rule B
touch b
------- Restart 2
完美!谢谢大家,大家圣诞快乐。
有不止一种方法可以做到这一点(通常使用 Make)。
我会这样做:将 include b
语句放入 a
。
$(info ------- Restart $(MAKE_RESTARTS))
all :
-include a
a : p
touch a
@echo -include b >> a
b : a
touch b
一个解决方案是调用子 make 来构建 b
。该子品牌将包括较新的 a
,因此是正确的。我相信这样的事情会起作用(未经测试):
$(info ------- Restart $(MAKE_RESTARTS))
all :
include a
include b
a : p
touch a
ifeq ($(filter real_b,$(MAKECMDGOALS)),)
b : a
$(MAKE) real_b
endif
.PHONY: real_b
real_b:
touch b
另一个解决方案是确保 b
在 a
更新时 不 更新。也许是这样的(同样,未经测试):
$(info ------- Restart $(MAKE_RESTARTS))
all :
include a
include b
BUILT_A =
a : p
touch a
$(eval BUILT_A = true)
b : a
$(if $(BUILT_A),,touch b)
(在配方中罕见地合法使用 eval
!)在此版本中,如果构建了 a
,则不会触及 b
。这样在 make re-execs 本身之后它将包括 a
和包括 b
,然后看到 a
是最新的但看到 b
是过时的(因为我们第一次跳过构建步骤)并重建 b
:这次 b
将被更新,因为 a
在上一次传递中被更新,然后 make 将再次重新执行。