使用 m4 构建 Dockerfiles 的 Makefile 未重建

Makefile using m4 to build Dockerfiles is not rebuilding

我有 6 个不同的 Dockerfile,它们看起来非常相似,所以我使用 m4 和 include 从片段构建它们。

我不太了解将 Makefile 用于 C++ 以外的目的,并且我遇到了一个问题,即当 m4 文件更改时 make 不会重建,除非目标更改,否则不会 运行 迭代复制操作。

请提供一些关于更好做法的意见和帮助?

参见:https://github.com/ptr727/NxWitness/tree/master/Make

.DEFAULT_GOAL := check

# Even if the m4 files changed make still reports up to date?
INPUTS = $(wildcard ${CURDIR}/*.m4)
OUTPUTS = $(addsuffix .dockerfile, $(basename $(INPUTS)))
# Why does the output look funky?
TARGETS = $(abspath ${CURDIR}/..)/$(basename $(notdir $(INPUTS)))/Dockerfile

%.dockerfile : %.m4
    m4 $< > $@

check:
    @echo "INPUTS = $(INPUTS)"
    @echo "OUTPUTS = $(OUTPUTS)"
    @echo "TARGETS = $(TARGETS)"

create: $(OUTPUTS)

clean:
    -rm *.dockerfile $(OUTPUTS)

# Why does make report up to date even after clean?
# $(foreach file, $(OUTPUTS), $(cp $(file) $(abspath ${CURDIR}/..)/$(basename $(notdir $(file)))/Dockerfile))
replace:
    cp DWSpectrum.dockerfile ../DWSpectrum/Dockerfile
    cp DWSpectrum-LSIO.dockerfile ../DWSpectrum-LSIO/Dockerfile
    cp NxWitness.dockerfile ../NxWitness/Dockerfile
    cp NxWitness-LSIO.dockerfile ../NxWitness-LSIO/Dockerfile
    cp NxMeta.dockerfile ../NxMeta/Dockerfile
    cp NxMeta-LSIO.dockerfile ../NxMeta-LSIO/Dockerfile

build:
    docker build -f ../DWSpectrum/Dockerfile ../DWSpectrum
    docker build -f ../DWSpectrum-LSIO/Dockerfile ../DWSpectrum-LSIO
    docker build -f ../NxWitness/Dockerfile ../NxWitness
    docker build -f ../NxWitness-LSIO/Dockerfile ../NxWitness-LSIO
    docker build -f ../NxMeta/Dockerfile ../NxMeta
    docker build -f ../NxMeta-LSIO/Dockerfile ../NxMeta-LSIO

在您的 Docker 文件中,您有 buildreplace 等与真实文件不对应的 Make 目标。那些将始终被认为是过时的并且需要重建,即使他们的输入没有改变。 (在 GNU Make 中,将它们标记为 .PHONY: 是一种很好的做法。)

如果你有一些任务,比如构建一个 Docker 图像,它不会直接自己生成一个文件,一个有用的技术是放置某种 "marker" 文件来记录它完成了。完成任务后,touch 标记文件。如果它的输入之一发生变化,它将比标记文件更新,并导致 Docker 重建文件。

%/.docker-build: %/Dockerfile
        docker build $(dir $@)
        touch "$@"

您可以使用类似的模式语法从 m4 文件生成 Docker 文件。 (这几乎与您上面的规则完全相同,但目标不同。)

%/Dockerfile: %.m4
        m4 $< >$@

如果您有目录列表

DIRS := DWSpectrum DWSpectrum-LSIO NxWitness NxWitness-LSIO NxMeta NxMeta-LSIO

那么你可以让 "build" 目标只依赖于标记文件

.PHONY: build
build: $(DIRS:%=%/.docker-build)

和 "clean" 规则应该清除我们生成的所有内容

.PHONY: clean
clean:
        rm -f $(DIRS:%=%/.docker-build)
        rm -f $(DIRS:%=%/Dockerfile)

我在这里使用了两种语法来替换您的函数调用和 foreach 循环。构建规则时,如果%在规则的两边,可以用相同的字符串代替,组成pattern rule; Make knows that DWSpectrum/.docker-build can be built from DWSpectrum/Dockerfile via this rule. $(DIRS:%=%/Dockerfile) is a substitution reference;对于 $(DIRS) 中与模式 % 匹配的每个项目(即每个项目),将其替换为匹配的字符串加上 /Dockerfile 后缀。