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

makefile目标中重复的百分比字符串,makefile,build,Makefile,Build,我希望以以下形式表示目标和依赖项: 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. 是否有一种不依赖于预先列出模块可能值的解决方法 (这不是的重复,因为他们想为所

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

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.
是否有一种不依赖于预先列出模块可能值的解决方法


(这不是的重复,因为他们想为所有可能的
(STR1,STR2)
元组集生成形式为
dir\u STR1/target\u 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) $@

这是可能的,原则上很简单,但由于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) $@

您可能希望尝试与配方模板一起使用

MODULES = mod1 mod2

define MODULE_RULE
dir_$(1)/target_$(1):dep_$(1)
    touch $$@
endef

$(foreach mod,$(MODULES),$(eval $(call MODULE_RULE,$(mod))))
对于
模块
中的每个项目,将按照模式
dir\u MODULE/target\u MODULE:dep\u MODULE
生成一条显式规则。这是一种非常方便的方法来构造遵循特定模式的多个规则,但不容易用简单的
%
-规则来解决

编辑:

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

MODULES=$(patsubst dep_%,%,$(wildcard dep_*))
获取所有模块名称的步骤

此外,如果您希望将所有
dir\u XXX/target\u XXX
目标作为另一个目标的先决条件,例如
all
,您可以从模块名称重构所有
dir\u XXX/target\u XXX
名称,如下所示:

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

all: $(FULLPATH_TARGETS)
此外,如果以前不存在
dir\u XXX
,您可以创建另一个规则来创建它们。完整的生成文件可能如下所示:

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)

您可能希望尝试与配方模板一起使用

MODULES = mod1 mod2

define MODULE_RULE
dir_$(1)/target_$(1):dep_$(1)
    touch $$@
endef

$(foreach mod,$(MODULES),$(eval $(call MODULE_RULE,$(mod))))
对于
模块
中的每个项目,将按照模式
dir\u MODULE/target\u MODULE:dep\u MODULE
生成一条显式规则。这是一种非常方便的方法来构造遵循特定模式的多个规则,但不容易用简单的
%
-规则来解决

编辑:

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

MODULES=$(patsubst dep_%,%,$(wildcard dep_*))
获取所有模块名称的步骤

此外,如果您希望将所有
dir\u XXX/target\u XXX
目标作为另一个目标的先决条件,例如
all
,您可以从模块名称重构所有
dir\u XXX/target\u XXX
名称,如下所示:

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

all: $(FULLPATH_TARGETS)
此外,如果以前不存在
dir\u XXX
,您可以创建另一个规则来创建它们。完整的生成文件可能如下所示:

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)

这是有用的信息,但我特别问是否有一个解决方案不涉及硬编码模块列表。这可以通过扩展此答案非常容易地完成。我还以为你在生成规则而不是生成模块名时遇到了麻烦。答案已编辑。您编辑的答案仍然需要一个模块名称列表,只是这次它们被记录在文件系统中。这是有用的信息,但我特别询问是否有一个解决方案不涉及对模块列表进行硬编码。通过扩展此答案,这可以非常容易地完成。我还以为你在生成规则而不是生成模块名时遇到了麻烦。答案已编辑。您编辑的答案仍然需要一个模块名称列表,只是这次它们被记录在文件系统中。