--always-make 可以不影响子品牌吗?
Can --always-make not affect a sub-make?
使用 GNU Make 4.1
总结
我正在从 makefile a.mk
调用子 make b.mk
。
调用 b.mk
以确保构建子系统。
有时我想强制重新制作 a.mk
的目标:
make -f a.mk <target> --always-make
当我这样做时,b.mk
也认为所有目标都已过时,但我不希望这样。
补救失败
我已经按照手册中的建议尝试使用 make -f b.mk MAKEFLAGS=
5.7.3 Communicating Options to a Sub-make,但没有运气。
这里是 a.mk
的要点:
.PHONY: all
$(info ===> a.mk MAKEFLAGS: $(MAKEFLAGS))
all:
$(MAKE) -f b.mk y MAKEFLAGS=
和b.mk
:
$(info ===> b.mk MAKEFLAGS: $(MAKEFLAGS))
y: x
cp $< $@
现在,即使 b.mk
通常认为 y
是最新的:
$ make -f b.mk y
===> b.mk MAKEFLAGS:
make: 'y' is up to date.
... y
当 a.mk
被调用 --always-make (-B)
:
时被重制
$ make -f a.mk --always-make
===> a.mk MAKEFLAGS: B
make -f b.mk y MAKEFLAGS=
make[1]: Entering directory '/home/matt/junk/make-b'
===> b.mk MAKEFLAGS:
cp x y
make[1]: Leaving directory '/home/matt/junk/make-b'
如您所见,B
标志出现在 a.mk
的 MAKEFLAGS 中,但未出现在 b.mk
的 MAKEFLAGS 中。
然而,y
被 b.mk
重制了。
问题
- 为什么?
- 有办法解决这个问题吗?
- 对于 GNU make,我希望这种行为有很好的理由。这是什么原因?
更新时间:2020-08-05
我(到底)为什么要这样做?
在回答 中,有人请求查看想要强制重制特定目标但又不想强制子制作的示例。
这里不是发明一些东西,而是引出我的问题的实际 makefile 的摘录:
WWW_SVG := score.svg
%Score.app/$(WWW_SVG): %Score.svg | %Score.app/
cd $(MUSIC_SCORE_PLAYER) && $(MAKE) -f $(MUSIC_SCORE_PLAYER_MAKEFILE) $(MUSIC_SCORE_PLAYER_TGT) MAKEFLAGS=
cp $< $(MUSIC_SCORE_PLAYER_DIR)$(WWW_SVG)
node $(MUSIC_SCORE_PLAYER_SVG_CONVERTER) > $@
该规则的目的是从另一个创建一个 SVG。
在 Web 应用程序加载和修改原始 SVG 之后,新的镜像 DOM 的 SVG 部分的状态。
- 秘诀的第一行使用 sub-make 来确保 web 应用程序是最新的,它可能不是我当前正在开发的。 Web 应用程序是一个单独的项目,与从中提取上述代码段的 makefile 的项目不同。
- 第二行将原始SVG复制到web应用的部署目录中,以便web应用加载它
- 第三行调用节点脚本来启动网络应用程序,从其 DOM 中提取 SVG,并将其写入标准输出。然后将其重定向以更新 SVG 目标。
在测试时,我希望能够强制重新制作具有匹配 %FooScore/score.svg
先决条件的目标,但不重建 Web 应用程序,除非 它已经过时了。
当然,我可以移动调用 sub-make 的行,这样它只会被调用一次,而不是为每个匹配规则的目标调用一次。但这是一种优化,而不是解决方案。
“始终构建”的要点是调用构建的所有部分。 而不是 传递给 sub-makes 是没有意义的。事实上,许多 makefile 在顶层 makefile 几乎没有发生任何事情:它们只是调用一组 sub-makes。如果“始终构建”不被传承下去,它就没有什么用了。
不幸的是,您的示例都基于以这种方式工作的事物,而事实并非如此。为了提出解决方案,我们需要看一个更现实的例子。特别是,你说你想强制重新制作一个特定的目标,但在上面的例子中你没有表现出来。重制的目标是什么?它如何与 b.mk
的 sub-make 调用交互?
请注意,您应该永远不要 使用make
来调用sub-makes。你应该总是使用$(MAKE)
(或者,等价地,${MAKE}
)。
这是基于 及其评论。
从原题看a.mk
,需要改一行:
.PHONY: all
$(info ===> a.mk MAKEFLAGS: $(MAKEFLAGS))
all:
MAKEFLAGS= $(MAKE) -f b.mk y # This line has changed
它现在使用 MAKEFLAGS
作为环境变量而不是命令行参数。请参阅 中的评论,了解为什么这会产生影响。
我们现在看到 -B
(--always-make
) 没有传递给 sub-make 和 那,不像 MAKEFLAGS
作为命令行变量传递,sub-make 不 "always-make":
$ make -B -f a.mk
===> a.mk MAKEFLAGS: B
MAKEFLAGS= make -f b.mk y
make[1]: Entering directory '/home/matt/junk/make-b'
===> b.mk MAKEFLAGS: w
make[1]: 'y' is up to date.
make[1]: Leaving directory '/home/matt/junk/make-b'
与原始问题中显示的输出相比,这里的另一个区别是 -w
(--print-directory
) 标志被传递给 sub-make,这很好。
使用 GNU Make 4.1
总结
我正在从 makefile a.mk
调用子 make b.mk
。
调用 b.mk
以确保构建子系统。
有时我想强制重新制作 a.mk
的目标:
make -f a.mk <target> --always-make
当我这样做时,b.mk
也认为所有目标都已过时,但我不希望这样。
补救失败
我已经按照手册中的建议尝试使用 make -f b.mk MAKEFLAGS=
5.7.3 Communicating Options to a Sub-make,但没有运气。
这里是 a.mk
的要点:
.PHONY: all
$(info ===> a.mk MAKEFLAGS: $(MAKEFLAGS))
all:
$(MAKE) -f b.mk y MAKEFLAGS=
和b.mk
:
$(info ===> b.mk MAKEFLAGS: $(MAKEFLAGS))
y: x
cp $< $@
现在,即使 b.mk
通常认为 y
是最新的:
$ make -f b.mk y
===> b.mk MAKEFLAGS:
make: 'y' is up to date.
... y
当 a.mk
被调用 --always-make (-B)
:
$ make -f a.mk --always-make
===> a.mk MAKEFLAGS: B
make -f b.mk y MAKEFLAGS=
make[1]: Entering directory '/home/matt/junk/make-b'
===> b.mk MAKEFLAGS:
cp x y
make[1]: Leaving directory '/home/matt/junk/make-b'
如您所见,B
标志出现在 a.mk
的 MAKEFLAGS 中,但未出现在 b.mk
的 MAKEFLAGS 中。
然而,y
被 b.mk
重制了。
问题
- 为什么?
- 有办法解决这个问题吗?
- 对于 GNU make,我希望这种行为有很好的理由。这是什么原因?
更新时间:2020-08-05
我(到底)为什么要这样做?
在回答
这里不是发明一些东西,而是引出我的问题的实际 makefile 的摘录:
WWW_SVG := score.svg
%Score.app/$(WWW_SVG): %Score.svg | %Score.app/
cd $(MUSIC_SCORE_PLAYER) && $(MAKE) -f $(MUSIC_SCORE_PLAYER_MAKEFILE) $(MUSIC_SCORE_PLAYER_TGT) MAKEFLAGS=
cp $< $(MUSIC_SCORE_PLAYER_DIR)$(WWW_SVG)
node $(MUSIC_SCORE_PLAYER_SVG_CONVERTER) > $@
该规则的目的是从另一个创建一个 SVG。 在 Web 应用程序加载和修改原始 SVG 之后,新的镜像 DOM 的 SVG 部分的状态。
- 秘诀的第一行使用 sub-make 来确保 web 应用程序是最新的,它可能不是我当前正在开发的。 Web 应用程序是一个单独的项目,与从中提取上述代码段的 makefile 的项目不同。
- 第二行将原始SVG复制到web应用的部署目录中,以便web应用加载它
- 第三行调用节点脚本来启动网络应用程序,从其 DOM 中提取 SVG,并将其写入标准输出。然后将其重定向以更新 SVG 目标。
在测试时,我希望能够强制重新制作具有匹配 %FooScore/score.svg
先决条件的目标,但不重建 Web 应用程序,除非 它已经过时了。
当然,我可以移动调用 sub-make 的行,这样它只会被调用一次,而不是为每个匹配规则的目标调用一次。但这是一种优化,而不是解决方案。
“始终构建”的要点是调用构建的所有部分。 而不是 传递给 sub-makes 是没有意义的。事实上,许多 makefile 在顶层 makefile 几乎没有发生任何事情:它们只是调用一组 sub-makes。如果“始终构建”不被传承下去,它就没有什么用了。
不幸的是,您的示例都基于以这种方式工作的事物,而事实并非如此。为了提出解决方案,我们需要看一个更现实的例子。特别是,你说你想强制重新制作一个特定的目标,但在上面的例子中你没有表现出来。重制的目标是什么?它如何与 b.mk
的 sub-make 调用交互?
请注意,您应该永远不要 使用make
来调用sub-makes。你应该总是使用$(MAKE)
(或者,等价地,${MAKE}
)。
这是基于
从原题看a.mk
,需要改一行:
.PHONY: all
$(info ===> a.mk MAKEFLAGS: $(MAKEFLAGS))
all:
MAKEFLAGS= $(MAKE) -f b.mk y # This line has changed
它现在使用 MAKEFLAGS
作为环境变量而不是命令行参数。请参阅
我们现在看到 -B
(--always-make
) 没有传递给 sub-make 和 那,不像 MAKEFLAGS
作为命令行变量传递,sub-make 不 "always-make":
$ make -B -f a.mk
===> a.mk MAKEFLAGS: B
MAKEFLAGS= make -f b.mk y
make[1]: Entering directory '/home/matt/junk/make-b'
===> b.mk MAKEFLAGS: w
make[1]: 'y' is up to date.
make[1]: Leaving directory '/home/matt/junk/make-b'
与原始问题中显示的输出相比,这里的另一个区别是 -w
(--print-directory
) 标志被传递给 sub-make,这很好。