如何从一组模板中为源设置多个目标?

时间:2018-10-11 18:59:26

标签: makefile

我有由版本号(7.0 7.1 7.2)标识的目标

我有一些模板,每个模板都需要替换一个占位符,这样我最终得到每个版本的目录,并且每个目录中的所有文件都有适当的替换。

因此,如果模板目录为:

template\Dockerfile

我想结束:

7.0\Dockerfile
7.1\Dockerfile
7.2\Dockerfile

,其中template\Dockerfile中的标签已替换为版本号。

这是一个简化的示例。模板文件夹中实际上有4个文件(其中2个在子目录中)。

管道将运行make build-targets,然后运行适当的docker命令来构建容器并将其推送到存储库-这就是目标。

虽然对所有这些问题都有一个答案是很高兴的,但我想学习,但是我找不到关于如何处理源和目标集的任何信息。

任何建议将不胜感激。

更多关于评论的详细信息

当前版本只有Makefile中的1行:VERSIONS := 7.0 7.1 7.2 latest

要运行的代码将是一系列sed命令,以获取模板并将文件中的#version#标记替换为版本号(latest除外)只会删除标签。

模板源全部位于templates目录中。作为sed命令的一部分,生成的文件名将templates部分替换为版本(包括latest)。

开始...(不知道这是否好-还在学习)

VERSIONS  := 7.0 7.1 7.2 latest
SOURCEDIR := ./templates
DESTDIR   := ./
TEMPLATES := $(shell find $(SOURCEDIR) -type f)

# For each file in $(TEMPLATES) for each version in $(VERSIONS), create a corresponding file in $(DEST_DIR)/$(VERSION)
# Replace `#version#` with $(VERSION) in each file, except for the `latest` target where the `#version#` removed.

基于下面提供的解决方案,我的最终代码是:

VERSIONS := 7.0 7.1 7.2 latest
SOURCE_DIR := ./templates
TEMPLATES := $(shell find $(SOURCE_DIR) -type f)
TEMPLATES := $(patsubst $(SOURCE_DIR)/%,%,$(TEMPLATES))
DEST_DIR := ./

.DEFAULT_GOAL := all
.PHONY: all

# $(1): version
# $(2): template file (without the $(SOURCE_DIR)/ stem)
define generate_target_file
$(DEST_DIR)/$(1)/$(2): $(SOURCE_DIR)/$(2)
    @echo "Making $$@"
    @mkdir -p $$(dir $$@)
    @if [ "$(1)" == "latest" ]; then \
        sed 's/#version#//g' $$< > $$@; \
    else \
        sed 's/#version#/$(1)-/g' $$< > $$@; \
    fi

all: $(DEST_DIR)/$(1)/$(2)
endef

$(foreach version,$(VERSIONS),$(foreach template,$(TEMPLATES),$(eval $(call generate_target_file,$(version),$(template)))))

list:
    @echo 'The following targets are available :'
    @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | \
        awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | \
        sort | \
        egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | \
        xargs -0

1 个答案:

答案 0 :(得分:0)

如果使用的是GNU-make,则可以使用make的foreach函数轻松地创建循环。您可以嵌套它们。 eval函数可用于以编程方式实例化make构造,而call函数可让您创建某种宏:

V := 7.0 7.1 7.2 latest
S := ./templates
T := $(shell find $(S) -type f)
T := $(patsubst $(S)/%,%,$(T))
D := ./destdir

.DEFAULT_GOAL := all
.PHONY: all

# $(1): version
# $(2): template file (without the $(S)/ stem)
# $(3): replacement string
define MY_rule
$(D)/$(1)/$(2): $(S)/$(2)
    mkdir -p $$(dir $$@)
    sed 's/#version#/$(3)/g' $$< > $$@

all: $(D)/$(1)/$(2)
endef

$(foreach v,$(V),\
  $(foreach t,$(T),\
    $(eval $(call MY_rule,$(v),$(t),$(patsubst latest,,$(v))))))

GNU make manual解释了它是如何工作的。请注意MY_rule宏的双重扩展,因此必须将某些$符号加倍。