我有一系列(数十个)项目,包含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
,并且对为什么自动完成没有开始感到困惑。
答案 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
诀窍是系统地让TAB字符在定义中包含命令,如果没有你得到奇怪的错误。
您也可以像往常一样为定义提供参数。
答案 1 :(得分:0)
我遇到了同样的问题,我最终解决了覆盖目标没有覆盖先决条件的问题,即覆盖先决条件'规则以及强制其中一些是空命令。
工具箱/ Makefile中的:
test: depend depend1 depend2
@echo test toolkit
...
在Makefile中:
include toolkit/Makefile
depend1 depend2: ;
test: depend
@echo test
注意depend1和depend2现在如何具有空目标,因此覆盖了测试目标的命令,并且有效地覆盖了依赖关系。