4

我不知道有任何方法可以在 GNU Make 中以编程方式定义目标。这怎么可能?

有时可以使用替代方法。然而,在 Makefile 中以编程方式定义目标的能力对于使用make. 在 FreeBSD 的构建系统或 Makefile 库(如BSD Owl )中可以找到复杂生产规则的示例

shell 脚本和 Makefile 之间的主要区别是:

  • 在 Makefile 中,程序的状态由命令行和文件系统给出,因此可以在作业中断后恢复作业。当然,这需要正确编写 Makefile,但即使这相当困难,也比使用 shell 脚本实现类似效果要容易得多。

  • 在 Makefile 中,用建议装饰过程或用钩子装饰过程非常容易,而这在 shell 脚本中基本上是不可能的。

例如,一个非常简单且有用的模式如下:

build: pre-build
build: do-build
build: post-build

这将目标呈现build为三个目标的组合,一个包含实际指令do-build,另外两个是钩子,在之前和之后执行do-build。许多为 BSD Make 编写的构建系统都使用这种模式,顺便说一句,它允许对目标进行编程定义,因此可以批量编写:

.for _target in configure build test install
.if !target(${_target})
${_target}: pre-${_target}
${_target}: do-${_target}
${_target}: post-${_target}
.endif
.endfor

块引入的条件.if/.endif使用户能够使用它自己的 any 定义${_target}

GNU Make 的那个片段的翻译是什么?

4

2 回答 2

5

FWIW 这里是 make 等效语法

.for _target in configure build test install
.if !target(${_target})
${_target}: pre-${_target}
${_target}: do-${_target}
${_target}: post-${_target}
.endif
.endfor

基本上,您希望看到类似以下代码段的内容:

build: pre-build
build: do-build
build: post-build

同样对于configure,testinstall. eval这表明在某处有一个循环:

define makerule =
  $1: pre-$1
  $1: do-$1
  $1: post-$1
endef

targets := configure build test install

$(foreach _,${targets},$(eval $(call makerule,$_)))

(要玩这个,请更改evalinfo)。小心那些关闭!

FWIW,这是扩展的foreach

  • make扩展要迭代的列表
    • ${targets}变成configure,和build_testinstall
    • 我们有$(foreach _,configure build test install,$(eval $(call makerule,$_)))
  • _设置为第一个值,configure
  • 使扩展$(eval $(call makerule,configure))
  • 为了评估eval, make展开$(call makerule,configure)
    • 它通过设置1configure, 并展开${makerule}生成 3 行文本来做到这一点:
      configure: pre-configure
      configure: do-configure
      configure: post-configure
  • $(eval)开始工作,将此文本作为make语法阅读
  • 注意扩展$(eval)是空的!它的所有工作都是作为副作用完成的。洗涤,起泡,冲洗,重复。

请注意:我必须同意所有其他评论者的观点:你的模式很糟糕。如果您的 makefile-j不安全,则它已损坏(缺少依赖项)。

于 2015-03-09T16:52:32.200 回答
3

首先,如果你想支持并行构建,这个结构是无效的;如果您使用该-j选项调用 make ,它将同时运行所有三个先决条件规则,因为虽然它们都必须在 before 完成build,但它们都不相互依赖,因此没有定义排序(也就是说,您没有说必须pre-build完成do-build才能运行)。

其次,GNU make 有许多以编程方式定义规则的工具。GNU make 目前没有的一件事是搜索已经定义的目标的能力,所以没有直接的类比.if !target(...)

但是,您可以使用变量搜索是否已定义.VARIABLES变量。因此,一种解决方法是如果您想要自己的目标,则定义一个变量,然后让您的规则生成器检查它。

于 2015-03-02T16:55:28.250 回答