在makefile目标中重复百分比字符串



我想以以下形式表示目标和依赖项:

dir_MODULE/target_MODULE: dep_MODULE

然而,直观的解决方案不起作用:

dir_%/target_%: dep_%
    @echo 1
dir_%/target_$*: dep_%
    @echo 2
> make: *** No rule to make target `dir_test/target_test'. Stop.

是否有一种不依赖于预先拥有MODULE可能值列表的解决方案?

(这不是我可以在一个makefile目标中有多个%符号吗?,因为他们想为所有可能的(STR1,STR2)元组的集合生成形式为dir_STR1/target_STR2的目标;由于STR1 = STR2的约束,我的情况更简单。

这是可能的,并且原则上很简单,但是由于Make缺乏正则表达式能力,唯一的解决方案(我可以看到)是丑陋的。

您可以使用"匹配任何东西"规则捕获目标,将该目标的新规则写入单独的文件(special.mk),然后使用该规则重新运行Make:

-include special.mk
special.mk: # not really necessary, but it soothes Make
    @:
ruler = dir_$(1)/target_$(1): dep_$(1)
%:
    @echo $(call ruler,$(subst target_,,$(notdir $@))) > special.mk
    @echo 't'@echo now building '$@' somehow from $$^ >> special.mk
    @$(MAKE) $@

您可能想尝试将eval函数与配方模板一起使用

MODULES = mod1 mod2
define MODULE_RULE
dir_$(1)/target_$(1):dep_$(1)
    touch $$@
endef
$(foreach mod,$(MODULES),$(eval $(call MODULE_RULE,$(mod))))

对于MODULES中的每个条目,将生成一个遵循模式dir_MODULE/target_MODULE: dep_MODULE的显式规则。这是一种非常方便的方式来构造遵循特定模式的多个规则,但不容易用简单的%规则来解决。

编辑:

如果模块列表以前不知道,应该通过扫描所有dep名称来确定,那么只需使用:

MODULES=$(patsubst dep_%,%,$(wildcard dep_*))

获取所有模块名

同样,如果您想让所有dir_XXX/target_XXX目标成为另一个目标的先决条件,例如all,您可以从模块名称中重建所有dir_XXX/target_XXX名称,如下所示:

DIR_NAMES = $(patsubst %,dir_%/,$(MODULES))
TARGET_NAMES = $(patsubst %,target_%,$(MODULES))
FULLPATH_TARGETS = $(join $(DIR_NAMES),$(TARGET_NAMES))
all: $(FULLPATH_TARGETS)

同样,如果以前不存在dir_XXX,您可以创建另一个规则来创建它们。完整的makefile可能如下所示:

MODULES = $(patsubst dep_%,%,$(wildcard dep_*))
DIR_NAMES = $(patsubst %,dir_%/,$(MODULES))
TARGET_NAMES = $(patsubst %,target_%,$(MODULES))
FULLPATH_TARGETS = $(join $(DIR_NAMES), $(TARGET_NAMES))
dir_%:
    mkdir -p $@
define MODULE_RULE
dir_$(1)/target_$(1):dep_$(1) dir_$(1)
    touch $$@
endef 
$(foreach mod,$(MODULES),$(eval $(call MODULE_RULE,$(mod))))
all: $(FULLPATH_TARGETS)

最新更新