共享的Makefile依赖项仅运行一次

问题描述 投票:0回答:2

TL; DR

由多个目标共享的依赖性仅被调用一次。

为什么?

摘要

在这个很小的Makefile示例中,我希望deploy-everywherestaging-repo代码部署到staging,并将prod-repo代码部署到prod

相反,stagingprod均获得staging-repo代码,这是公认的次优条件。

这似乎是因为clone-repo作为deploy-to-prod的一部分在第二次被检查时被跳过/修剪,所以似乎发生了(请参阅下面的-d日志输出)。

为什么会发生这种情况,我可以改变这种行为吗?

$ cat Makefile

.PHONY: deploy-everywhere deploy-to-prod deploy-to-staging clone-repo

deploy-everywhere: deploy-to-staging deploy-to-prod
    @echo "deployed everywhere"

deploy-to-prod: repo="prod-repo"
deploy-to-prod: clone-repo
    @echo "deployed to prod (from $(repo))"

deploy-to-staging: repo="staging-repo"
deploy-to-staging: clone-repo
    @echo "deployed to staging (from $(repo))"

clone-repo:
    @echo "clone-repo $(repo)"

更多详细信息(日志,版本)

这里是运行make的输出:

$ make deploy-everywhere
clone-repo staging-repo
deployed to staging (from staging-repo)
deployed to prod (from prod-repo) <<<<< THIS IS A LIE, WE NEVER CLONED THE PROD REPO!!
deployed everywhere <<<< RIIIIGHT.

额外日志:

$ make -d deploy-everywhere
...
  Successfully remade target file `deploy-to-staging'.
  Considering target file `deploy-to-prod'.
   File `deploy-to-prod' does not exist.
    Pruning file `clone-repo'.          <<<< WHY? WHY?!?!?!?! WHY.
   Finished prerequisites of target file `deploy-to-prod'.
  Must remake target `deploy-to-prod'.
...

我正在运行GNU Make 3.81:

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i386-apple-darwin11.3.0
makefile gnu-make
2个回答
1
投票

这是设计使然。 Makefile中的目标更像名词而不是动词。

您可以通过几种方法实现所需的目标。这是一个:

deploy-to-prod: clone-prod-repo
    @echo "deployed to prod (from prod-repo)"

deploy-to-staging: clone-staging-repo
    @echo "deployed to staging (from staging-repo)"

clone-%-repo:
    @echo "clone $*-repo"

EDIT:好,clone操作采用多个参数。这是一种方法:

deploy-to-prod: PARAM1=ProdOne
deploy-to-prod: PARAM2=ProdTwo
deploy-to-prod: clone-prod-repo
    @echo "deployed to prod (from prod-repo)"

deploy-to-staging: PARAM1=StagingFirst
deploy-to-staging: PARAM2=StagingSecond
deploy-to-staging: clone-staging-repo
    @echo "deployed to staging (from staging-repo)"

clone-%-repo:
    @echo clone $*-repo with $(PARAM1) and $(PARAM2)

这是另一个:

define clone-repo
@echo clone using $(1)
@echo and $(2) in some way
endef

deploy-to-prod:
    @echo $@
    $(call clone-repo, ProdOne, ProdTwo)

deploy-to-staging:
    @echo $@
    $(call clone-repo, StagingFirst, StagingSecond)

0
投票

[为Beta的解决方案增加一些解释:make规则的程序化契约是它是文件系统中永久实体的不透明更新,从而满足“小于”]](小于)在关联树中的关系。您的构造OTOH通过将其作为参数来从make中隐藏依赖项。您试图规避的问题是make中没有针对非文件系统存在的实体(在您的情况下是修订控制系统)的“小于”概念。我唯一的问题是,为什么您不简单地将clone调用添加到每个deploy目标-如果您确实想将其作为“小于”依赖项来解决(即,仅在本地存储库非-已存在或更旧),则需要进行一些make编程。

在您的第一个评论后编辑:如果我说对了,您对PHONY的想法就有点偏离了(不是全部,只是一点)。 PHONY并不是要在不同的make运行之间促进某些事情,它是在依赖关系树中产生短路的一种方法。给定一条链foo -> bar -> phony_baz(foo取决于bar取决于phony_baz),在make是主要目标的情况下,foo将首先查看bar以了解它是否比phony_baz早,而会是这种情况。这是因为phony_baz本身具有make隐式属性,当将其作为与目标的先决条件进行比较时,始终会产生“ younger_than”(现在是重要部分:) 依赖树。在树的其他分支中所有后续的phony_baz遇到都将完全相反,从而在假目标处终止评估。这与依存关系图中任何其他节点的行为没有什么不同-make假定我上面提到的合同已得到履行,并且没有采取重复行动的理由。这是clone-repo虽不是.PHONY,但第二次不触发的原因-您的设置实际上是有向无环图,其中两个边在同一节点处接合(这很好,只是值得注意),而不是树。 Beta的第一个解决方案是通过参数化规则动态创建两个完全不相关的节点,从而将形状返回到树中。

© www.soinside.com 2019 - 2024. All rights reserved.