使溢出¹或“如何覆盖目标?”

时间:2016-12-30 06:43:26

标签: makefile gnu-make

我有一系列(数十个)项目,包含git存储库中的大量内容。每个存储库都有一个通用工具包的git子模块。该工具包包含处理内容存储库和构建可发布结果所需的库和脚本。所有存储库都被推送到运行CI的主机并发布结果。我们的想法是将重复的代码保持在绝对最小值,并且主要在存储库中包含内容并依赖于工具包,并以相同的方式将它们放在一起用于每个项目。

每个项目都有一个顶级的Makefile,通常只有几行,例如:

STAGE = stage

include toolkit/Makefile

stage变量有一些关于这个特定阶段的信息,它确定构建哪些格式。几乎所有其他东西都由工具包中的600行Makefile处理。构建一些输出格式可能需要很长的依赖关系:源的进程可能触发目标规则,但是为了到达目标,可能存在8-10个中间依赖关系,其中在最终目标可以生成之前生成各种文件制成。

我遇到过几种情况,我想在一个项目中完全替换(而不仅仅是扩展)特定的目标规则。目标在一系列依赖关系中被触发,但我想为这一步做一些完全不同的事情。

我尝试过替换顶级Makefile中的目标:

STAGE = stage

%-target.fmt:
    commands

include toolkit/Makefile

这是特别记录的支持,但很有吸引力它在某个时间工作。我已经尝试更改声明自定义目标和包含的顺序,但这似乎并没有显着影响这一点。如果重要,是的,在目标中使用模式很重要。

  

有时使用一个makefile就像另一个makefile一样有用。您通常可以使用'include'指令将一个包含在另一个中,并添加更多目标或变量定义。但是,两个makefile无法为同一目标提供不同的配方。

有趣的是,如果我将自定义函数放在顶层Makefile 下面,那么我可以覆盖工具箱中的函数,以便$(call do_thing)将使用我的覆盖:

STAGE = stage

include toolkit/Makefile

define do_thing
    commands
endef

然而,目标似乎并非如此。我知道two colon syntax,但我不想只是扩展一个具有更多依赖关系的现有目标,我想用一种不同的生成相同文件的方式完全替换目标。

我已经考虑过使用递归调用来生成as suggested in the documentation,但是包含在工具包Makefile中广泛设置的辅助函数的环境将无法用于顶级Makefile中的任何目标。这将是一个节目塞子。

有没有办法让make成为我的例外?是否可以强制进入压倒一切的目标?我只使用最新版本的GNU-Make,并不太关心可移植性。如果做不到的话还有另一种概念方法可以达到同样的目的吗?

¹我的大脑今天没有足够的咖啡。在尝试打开Stack Overflow来询问这个问题时,我在浏览器中键入了makeoverflow.com,并且对为什么自动完成没有开始感到困惑。

2 个答案:

答案 0 :(得分:1)

更新回答: 如果您的配方具有依赖关系,则默认情况下不能覆盖这些依赖关系。然后$(eval)可能会像这样保存你:

在工具箱中,您的通用规则具有宏定义:

ifndef TARGET_FMT_COMMANDS
define TARGET_FMT_COMMANDS
    command1 # note this these commands should be prefixed with TAB character
    command2
endef
endif

define RULE_TEMPLATE
%-target.fmt: $(1)
    $$(call TARGET_FMT_COMMANDS)

endef

# define the default dependencies, notice the ?= assignment
TARGET_DEPS?=list dependencies here

# instantiate the template for the default case
$(eval $(call RULE_TEMPLATE,$(TARGET_DEPS)))

然后进入调用代码,在包含工具包之前定义TARGET_FMT_COMMANDS和TARGET_DEPS,这应该可以解决问题。

(请原谅define / variables的名称,它们只是一个例子)

初步回答: 好吧,我在工具箱中写这个:

define TARGET_FMT_COMMANDS
    command1 # note this these commands should be prefixed with TAB character
    command2
endef

%-target.fmt:
    $(call TARGET_FMT_COMMANDS)

您可以在include toolkit/Makefile

之后重新定义TARGET_FMT_COMMANDS

诀窍是系统地让TAB字符在定义中包含命令,如果没有你得到奇怪的错误。

您也可以像往常一样为定义提供参数。

答案 1 :(得分:0)

我遇到了同样的问题,我最终解决了覆盖目标没有覆盖先决条件的问题,即覆盖先决条件'规则以及强制其中一些是空命令。

工具箱/ Makefile中的

test: depend depend1 depend2
   @echo test toolkit
...

在Makefile中:

include toolkit/Makefile

depend1 depend2: ;

test: depend
   @echo test

注意depend1和depend2现在如何具有空目标,因此覆盖了测试目标的命令,并且有效地覆盖了依赖关系。