我想构建以下依赖关系图,但是pre
和post
没有伪像:
在创建/更新a
,b
或c
中的任何一个之前,命令pre
应该运行一次,然后post
应该运行一次。两者均不且最好不产生伪像。当然,如果a b c
中的任何一个已更改,则应该仅运行。这应该全部由虚假的all
目标触发,即a
永远不会独立运行。
使用仅订购先决条件a: | pre
无济于事,因为这些先后总是运行。使post
依赖于a b c
是行不通的,因为这样post
并不会一直运行,因为pre
不会创建工件。
如果这是不可能的,并且毕竟需要工件,那么a
(两者中比较有趣的)如何仅在依赖于它的目标发生变化的情况下运行?
注意: a: a.in a.dependency
@echo Creating a
@mkabc a.in > a
等是正常的makefile目标(可以独立调用),例如:
<TargetFramework>netstandard2.0</TargetFramework>
答案 0 :(得分:2)
只有一种方法可以强制在构建目标X之前执行命令,但是仅在需要构建目标X的情况下,才将命令作为目标X的配方中的第一件事。一种在GNU make中操作依赖关系图的方法,这样make可以确定是否需要构建目标,如果需要,可以在配方运行之前首先构建其他目标。
因此,您肯定在这里必须使用递归make,将用于构建pre
目标的命令放入其他目标的配方中。但是,这当然会导致您不希望多次构建它。
解决该问题的一种方法是使用eval
来耍花招。试试这个(未试用):
BUILD_PRE = $(shell $(MAKE) -j1 pre >/dev/null)
post: a b c
echo $@
pre:
echo $@
a b c:
$(BUILD_PRE)$(eval BUILD_PRE =)
touch $@
.PHONY: pre post
在a
,b
和c
的规则中,我们首先扩展BUILD_PRE
变量,该变量通过shell
调用进行递归生成调用。然后eval
扩展将重置BUILD_PRE
的值,使其为空;这意味着在b
和c
的后续规则中,第一行将扩展为空字符串,并且pre
将不再运行。
您可能会问,为什么我们在这里需要使用shell
?我们不能只使用:
BUILD_PRE = $(MAKE) -j1 pre
使第一个配方包含递归标记吗?问题是它不能与并行make一起使用。假设要构建的第一个目标尝试是a
(当然,它将始终如此)。该配方将包含一个递归的make调用,make将启动它。但是,如果您使用的是-j
,make不会等待该配方完成:它将尝试尝试启动b
和c
。由于BUILD_PRE
现在为空,您只能获得pre
的一个内部版本,但是b
和c
并不等待pre
完成。
通过使用shell
函数,在展开任何其他配方之前,展开配方时将强制完成递归调用。
我应该说,我怀疑这可能有一些奇怪的事情。特别是当make 通常调用递归构建时,它会进行一些设置等操作,而通过shell
调用递归构建时不会发生。但是,它应该可以工作。
编辑:带有“ +”前缀的最终Makefile,用于标记递归调用:
all: allabc
BUILD_PRE = $(shell $(MAKE) pre)
BUILD_POST =
pre:
@echo PRE abc >&2
post:
@echo POST abc >&2
allabc: a b c
@+$(BUILD_POST) > /dev/null
a:
+$(BUILD_PRE)$(eval BUILD_PRE = )
touch "$@"
$(eval BUILD_POST = $$(MAKE) post)
b:
+$(BUILD_PRE)$(eval BUILD_PRE = )
touch "$@"
$(eval BUILD_POST = $$(MAKE) post)
c:
+$(BUILD_PRE)$(eval BUILD_PRE = )
touch "$@"
$(eval BUILD_POST = $$(MAKE) post)
clean:
rm -f a b c
答案 1 :(得分:1)
不确定我是否了解所有详细信息,但是假设您想在调用make all
时构建5个目标,并显示所显示的依赖关系(也许还有a
,b
和{{1 }}),例如:
c