如何以编程方式定义GNU Make中的目标?

时间:2015-03-02 16:44:52

标签: makefile gnu-make bsdmake

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

有时一个人可以离开with alternate methods。但是,在Makefile中定义编程目标的能力对于使用make编写和组织复杂的生产规则非常重要。复杂生产规则的示例可在FreeBSD的构建系统或Makefile库中找到,例如BSD Owl

shell脚本和Makefile之间的main differences是:

  • 在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块引入的条件使用户可以使用自己对${_target}的定义。

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

2 个答案:

答案 0 :(得分:3)

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

其次,GNU make为programmatically defining rules提供了许多功能。目前,GNU make还没有能够搜索已定义的目标,因此没有直接类比.if !target(...)

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

答案 1 :(得分:3)

这里的FWIW是

的make等效语法
.for _target in configure build test install
.if !target(${_target})
${_target}: pre-${_target}
${_target}: do-${_target}
${_target}: post-${_target}
.endif
.endfor

基本上,您希望 make 看到类似此片段的内容:

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

,同样适用于configuretestinstall。这表明在某处有eval的循环:

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

targets := configure build test install

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

(要使用此功能,请将eval更改为info)。小心那些关闭!

FWIW,这是foreach

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

请注意:我必须同意所有其他评论者:您的模式糟糕制作。如果您的makefile不是-j安全的,那么已损坏(缺少依赖项)。