动态生成Makefile规则

动态生成Makefile规则,makefile,Makefile,我有一个Makefile,用来调用不同的子Makefile 我有几条规则: 全部 干净的 fclean 再 我已经可以使用这些规则了,它们将使用相同的规则调用每个子makefile 我有几个项目,我想用这种格式生成规则: $(项目名称)-(规则) 因此,我希望每个项目都有以下规则: project1-all project1-clean ... project2-all project2-clean ... 这样,我就可以为特定的项目调用特定的规则,比如project1fclea

我有一个Makefile,用来调用不同的子Makefile

我有几条规则:

  • 全部
  • 干净的
  • fclean
我已经可以使用这些规则了,它们将使用相同的规则调用每个子makefile

我有几个项目,我想用这种格式生成规则:

$(项目名称)-(规则)

因此,我希望每个项目都有以下规则:

project1-all

project1-clean

...

project2-all

project2-clean

...
这样,我就可以为特定的项目调用特定的规则,比如
project1fclean

我试过:

RULES=    all clean fclean re

PROJECTS= project1 project2

define NEWLINE

endef

$(foreach _rule, $(RULES),                                              \
    $(foreach _proj, $(PROJECTS),                                           \
$(_proj)-$(_rule):                                           $(NEWLINE) \
            $(MAKE) $(ARGS) $(PROJECT_DIR)$(_proj) $(_rule) $(NEWLINE)  \
    )                                                                     \
)

但它似乎不起作用。我已经搜索过了,但还没有找到实现这一点的高级makefile技术。Plz帮助。

问题是,当您将行与这样的行连续体组合在一起时,它会压缩掉所有的换行符和其他无关的空格(包括您试图用
$(换行符)
插入的换行符),从而导致单行上出现巨大的混乱,而不是使用多个模式的多行。要正确执行此操作,您需要将规则编写为带有参数的宏,然后调用它:

define PROJ_RULE
$(1)-$(2):
        $(MAKE) $(ARGS) $(PROJECT_DIR)$(1) $(2)
endef

$(foreach _rule, $(RULES),
    $(foreach _proj, $(PROJECTS),
        $(eval $(call PROJ_RULE, $(_proj), $(_rule)))))

请注意,GNU中所有这些
定义
foreach
东西都是make-specific的——其他make风格不支持它。

好的,所以我最终设法这样做:

$(foreach _rule, $(RULES), $(addsuffix -$(_rule),$(PROJECTS))):
            $(eval _rule := $(lastword $(subst -, ,$@)))
            $(eval _proj := $(@:%-$(_rule)=%))
            @$(MAKE) $(ARGS) $(PROJECT_DIR)$(_proj) $(_rule)
为了更好地解释,我将对其进行分解:

$(foreach _rule, $(RULES), ...)):
我们循环每个规则并将其存储在_rule中

$(addsuffix -$(_rule),$(PROJECTS))
我们将该规则作为前缀添加到每个项目中。该部分使用每个“组合规则”生成一个规则。对于
projet1
project2
,应导致:

project1-all project2-all project1-clean project2-clean project1-fclean project2-fclean project1-re project2-re:
这样,对于这些规则名称中的任何一个,都将执行相同的规则

$(eval _rule := $(lastword $(subst -, ,$@)))
在这里,我们将目标(如果我将project2称为clean,
$@
成为
),我们将
-
替换为一个空格,以获得
project2 clean
,并将最后一个工作,它将是
clean
。然后我们对其进行评估,将其存储到
\u rule

$(eval _proj := $(@:%-$(_rule)=%))
我们使用相同的技术将项目名称存储到
\u proj
中。我们只是使用一个模式替换来删除规则名和破折号

@$(MAKE) $(ARGS) $(PROJECT_DIR)$(_proj) $(_rule)

最后,我们称我们的子基文件为正确路径和正确规则

它似乎对我不起作用,它告诉我多目标模式。我知道不能将多个模式组合为目标模式(如
%.o
),在这里,这取决于
$(1)-(2)
是否为模式。我想是的。我现在已经找到了一个“丑陋”的解决方案,但你的解决方案似乎更美观。是的,如果在
$(项目)
$(规则)
中有任何
%%
,这将不起作用,但你的示例似乎不需要
%
,所以我不确定它们来自何处。这个答案几乎是正确的,但它没有接到eval的电话,所以它不起作用。用$(eval)包装顶级foreach,它就工作了。我回到这里是因为我仍然有问题。看来克里斯搞定了。为什么不在每个顶层添加$(eval)呢?但是,像Chris在这里所做的那样,将其放在内部确实有效。由于
$(foreach
开始于第一列(没有前面的选项卡或空格),在始终展开之后,它应该作为makefile语法进行计算,因此显式
$(eval不应该是必需的,但它似乎只在GNUmake的某些版本中起作用。在其他版本中,eval是必需的;我不确定是哪一个版本。显然,您有一个版本不仅需要eval,而且必须在foreach中。
$(call
line可能是问题的原因;显式的
$(调用前后立即eval
可以避免这种情况。与其递归调用
make
,我建议您看看非递归的
makefile
方法。有一篇文章介绍了递归make的缺点:。您可以尝试使用我的模板库获取非递归的makefile: