'make' 每隔一次就会失败

时间:2021-07-07 10:17:03

标签: makefile

在以下情况下,什么可能导致 make 每隔一次失败(因此每隔一次成功)?

减少Makefile

helm/%: $(HELMFILE_DIR)/[0-9][0-9]_%.yaml
    @echo $@
$(HELMFILE_DIR)/[0-9][0-9]_%.yaml: services/helm/%/[0-9][0-9]_*.yaml | $(HELMFILE_DIR)
    cp $? $(HELMFILE_DIR)/
$(HELMFILE_DIR):
    mkdir -p $(HELMFILE_DIR)

来自 4 个连续 make clean helm/external_dns 调用的控制台输出:

# make clean helm/external_dns
rm -rf ./helm
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml ./helm/helmfile.d/
helm/external_dns


# make clean helm/external_dns
rm -rf ./helm
make: *** No rule to make target 'helm/helmfile.d/40_external_dns.yaml', needed by 'helm/external_dns'.  Stop.


# make clean helm/external_dns
rm -rf ./helm
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml ./helm/helmfile.d/
helm/external_dns


# make clean helm/external_dns
rm -rf ./helm
make: *** No rule to make target 'helm/helmfile.d/40_external_dns.yaml', needed by 'helm/external_dns'.  Stop.

编辑 - 更多信息:

  1. Makefile 的缺失部分:
HELM_DIR := ./helm
HELMFILE_DIR := $(HELM_DIR)/helmfile.d

.PHONY: build clean
.PRECIOUS: $(HELMFILE_DIR)/%.yaml $(HELMFILE_DIR)/%.values.yaml.gotmpl 

clean:
    rm -rf $(HELM_DIR)
  1. 有趣的是,虽然 make clean helm/external_dns 每隔一次失败,但 make clean; make helm/external_dns 每次都成功。
  2. Makefile 的上述部分中,我添加了对 helmfile 编号的支持(添加了前缀 NN_,其中 NN 是从 00 到 99 的 2 位数字,以按字母顺序对 helmfile 进行排序)。代码的原始部分,有效的是:
helm/%: $(HELMFILE_DIR)/%.yaml
    @echo $@
$(HELMFILE_DIR)/%.yaml: services/helm/%/*.yaml | $(HELMFILE_DIR)
    cp $? $@
$(HELMFILE_DIR):
    mkdir -p $(HELMFILE_DIR)
  1. 文件系统状态:
# make clean
rm -rf ./helm
# tree
.
├── Makefile
├── services
│         └── helm
│             └── external_dns
│                 └── 40_external_dns.yaml
# make clean helm/external_dns
rm -rf ./helm
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml ./helm/helmfile.d/
helm/external_dns
# tree
.
├── Makefile
├── helm
│         └── helmfile.d
│             └── 40_external_dns.yaml
├── services
│         └── helm
│             └── external_dns
│                 └── 40_external_dns.yaml
# make clean helm/external_dns
rm -rf ./helm
make: *** No rule to make target 'helm/helmfile.d/40_external_dns.yaml', needed by 'helm/external_dns'.  Stop.
# tree
.
├── Makefile
├── services
│         └── helm
│             └── external_dns
│                 └── 40_external_dns.yaml

我希望这些信息足以重新打开问题。

1 个答案:

答案 0 :(得分:0)

问题的根本原因是通配符匹配。第一次,当 ./helm/40_external_dns.yaml 不存在时,模式不匹配任何现有文件,因此保持完整:

$ make clean helm/external_dns -dpr
...
Considering target file 'helm/external_dns'.
 File 'helm/external_dns' does not exist.
 Looking for an implicit rule for 'helm/external_dns'.
 Trying pattern rule with stem 'external_dns'.
 Trying implicit prerequisite 'helm/helmfile.d/[0-9][0-9]_external_dns.yaml'.
 Trying pattern rule with stem 'external_dns'.
 Trying implicit prerequisite 'helm/helmfile.d/[0-9][0-9]_external_dns.yaml'.
 Looking for a rule with intermediate file 'helm/helmfile.d/[0-9][0-9]_external_dns.yaml'.
  Avoiding implicit rule recursion.
  Trying pattern rule with stem 'external_dns'.
  Trying implicit prerequisite 'services/helm/external_dns/40_external_dns.yaml'.
  Trying rule prerequisite 'helm/helmfile.d'.
 Found an implicit rule for 'helm/external_dns'.
...
helm/external_dns: helm/helmfile.d/[0-9][0-9]_external_dns.yaml
#  Command line target.
#  Implicit rule search has been done.
#  Implicit/static pattern stem: 'external_dns'
#  File does not exist.
#  File has been updated.
#  Successfully updated.
...
# automatic
# < := helm/helmfile.d/[0-9][0-9]_external_dns.yaml
...
#  recipe to execute (from 'Makefile', line 5):
        @echo $@

但是,在第二次调用时,文件 ./helm/40_external_dns.yaml 确实存在,因此它与通配符匹配并且正在解析。所以现在 helm/external_dns 不依赖于 helm/helmfile.d/[0-9][0-9]_external_dns.yaml,而是依赖于 helm/helmfile.d/40_external_dns.yaml。自己看看:

$ make clean helm/external_dns -dpr
...
Considering target file 'helm/external_dns'.
 File 'helm/external_dns' does not exist.
 Looking for an implicit rule for 'helm/external_dns'.
 Trying pattern rule with stem 'external_dns'.
 Trying implicit prerequisite 'helm/helmfile.d/40_external_dns.yaml'.
 Found an implicit rule for 'helm/external_dns'.
  Considering target file 'helm/helmfile.d/40_external_dns.yaml'.
   File 'helm/helmfile.d/40_external_dns.yaml' does not exist.
   Looking for an implicit rule for 'helm/helmfile.d/40_external_dns.yaml'.
   Trying pattern rule with stem 'helmfile.d/40_external_dns.yaml'.
   Trying implicit prerequisite 'helm/helmfile.d/[0-9][0-9]_helmfile.d/40_external_dns.yaml.yaml'.
   Trying pattern rule with stem 'helmfile.d/40_external_dns.yaml'.
   Trying implicit prerequisite 'helm/helmfile.d/[0-9][0-9]_helmfile.d/40_external_dns.yaml.yaml'.
   Looking for a rule with intermediate file 'helm/helmfile.d/[0-9][0-9]_helmfile.d/40_external_dns.yaml.yaml'.
    Avoiding implicit rule recursion.
    Trying pattern rule with stem 'helmfile.d/40_external_dns.yaml'.
    Trying implicit prerequisite 'services/helm/helmfile.d/40_external_dns.yaml/[0-9][0-9]_*.yaml'.
    Trying pattern rule with stem 'helmfile.d/40_external_dns.yaml'.
    Trying implicit prerequisite 'services/helm/helmfile.d/40_external_dns.yaml/[0-9][0-9]_*.yaml'.
    Looking for a rule with intermediate file 'services/helm/helmfile.d/40_external_dns.yaml/[0-9][0-9]_*.yaml'.
     Avoiding implicit rule recursion.
     Avoiding implicit rule recursion.
   No implicit rule found for 'helm/helmfile.d/40_external_dns.yaml'.
   Finished prerequisites of target file 'helm/helmfile.d/40_external_dns.yaml'.
  Must remake target 'helm/helmfile.d/40_external_dns.yaml'.
make: *** No rule to make target 'helm/helmfile.d/40_external_dns.yaml', needed by 'helm/external_dns'.  Stop.
...
helm/external_dns: helm/helmfile.d/40_external_dns.yaml
#  Command line target.
#  Implicit rule search has been done.
#  Implicit/static pattern stem: 'external_dns'
#  File does not exist.
#  File has not been updated.
#  recipe to execute (from 'Makefile', line 5):
        @echo $@
...
# Not a target:
helm/helmfile.d/40_external_dns.yaml:
#  Implicit rule search has been done.
#  File does not exist.
#  File has not been updated.

最重要的是 glob 模式不是常规的 make 特征,正如您所看到的,在扩展它们时有一些注意事项。顺便说一句,clean 并不是唯一失败的事情。在随后的调用中,如果源文件发生更改,您的文件也不会更新,原因与依赖项 40_external_dns.yaml 不是 [0-9][0-9]_external_dns.yaml 相同。参见示例:

$ make helm/external_dns
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml ./helm/helmfile.d/
helm/external_dns

# Edit the original file
$ touch services/helm/external_dns/40_external_dns.yaml

# Note that it is not copied
$ make helm/external_dns
helm/external_dns

这个文件结构通过将文件名的一部分作为源目录名增加了复杂性,但我还是会计算目标文件名以确切知道必须复制什么而不是随机全局扩展,例如:

$ cat Makefile
HELM_DIR := ./helm
HELMFILE_DIR := $(HELM_DIR)/helmfile.d

.SECONDEXPANSION:

.PHONY: helm/%
helm/%: $$(addprefix $(HELMFILE_DIR)/,$$(notdir $$(wildcard services/helm/$$*/[0-9][0-9]_$$*.yaml)))
        @echo $@

.PRECIOUS: $(HELMFILE_DIR)/%.yaml
$(HELMFILE_DIR)/%.yaml: $$(wildcard services/helm/$$(subst $$(firstword $$(subst _, ,$$*))_,,$$*)/$$*.yaml) | $(HELMFILE_DIR)
        cp $< $@

$(HELMFILE_DIR):
        mkdir -p $(HELMFILE_DIR)

.PHONY: clean
clean:
        rm -rf $(HELM_DIR)

输出:

$ make helm/external_dns
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml helm/helmfile.d/40_external_dns.yaml
helm/external_dns

# Nothing to do on next call
$ make helm/external_dns
helm/external_dns

# Update file if changed
$ touch services/helm/external_dns/40_external_dns.yaml
$ make helm/external_dns
cp services/helm/external_dns/40_external_dns.yaml helm/helmfile.d/40_external_dns.yaml
helm/external_dns

# And the clean is fixed
$ make clean helm/external_dns
rm -rf ./helm
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml helm/helmfile.d/40_external_dns.yaml
helm/external_dns

$ make clean helm/external_dns
rm -rf ./helm
mkdir -p ./helm/helmfile.d
cp services/helm/external_dns/40_external_dns.yaml helm/helmfile.d/40_external_dns.yaml
helm/external_dns
相关问题