2015-03-02 94 views
1

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

有时候可以走开with alternate methods。然而,在Makefiles中定义编程目标的能力对编写和组织复杂的生产规则非常重要,其中make。的复杂的生产规则的例子是在FreeBSD中的构建系统或在生成文件库如BSD Owl

壳脚本和Makefiles之间的main differences发现是:

  • 在生成文件时,程序的状态是由命令行和文件系统给出,因此可以在作业中断后重新开始工作。当然,这需要正确编写Makefiles,但即使这很困难,也比使用shell脚本实现类似效果要容易得多。

  • 在Makefile中,用建议来装饰过程或使用钩子来装饰过程是很荒唐的,而在shell脚本中这实际上是不可能的。

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

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

这呈现的build目标作为三个目标包含实际指令do-build和两个其它,它们是复合材料,一个挂钩,在do-build之前和之后执行。此模式是由为BSD作,这亦允许的目标编程定义写入许多构建系统使用的,这样一方面可以在分批写:

.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片段的翻译是什么?

+0

需要注意的是,在GNU中,你不需要**在目标先决条件之间得到一个有序保证(尽管没有'-j'我认为假设你通常是安全的),所以你的“钩子“不一定做你想做的事。 – 2015-03-02 16:53:59

+0

@EtanReisner当然,但这与问题没有直接关系,我忽略了这一点,以保持简单。例如,在BSD Make中,有人说''。ORDER:预编译do-build post-build'来执行所提及目标的串行处理。 – 2015-03-02 16:55:41

+0

使用或不使用'-j',make将始终以相同的顺序走先决条件列表。只是''j''''''''''''''''''''''''''''''''''''''''''''''''''''不会等待以前的(非相关的)先决条件完成,然后再开始新的先决条件没有'-j' make _does_保证按顺序构建。 – MadScientist 2015-03-02 16:57:18

回答

2

FWIW这里是

.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 

,类似的还有configuretestinstall。这表明与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的扩展:

  • 使扩展将遍历
    • ${targets}变得configurebuildtestinstall
    • 我们有$(foreach _,configure build test install,$(eval $(call makerule,$_)))
    • 列表
  • _设置为第一个值,configure
  • 使扩展$(eval $(call makerule,configure))
  • 为了评估eval使扩展$(call makerule,configure)
    • 它通过设置1configure,扩大${makerule}产生3行文本的做到这一点:
      configure: pre-configure
      configure: do-configure
      configure: post-configure
  • $(eval)上班,阅读本书为使语法
  • 注意,$(eval)的扩张是空的!其所有工作都是作为副作用完成的。 清洗,起泡,冲洗,重复。

请注意:我已经与所有其他评论者同意:你的模式是化妆。如果你的makefile不是-j安全,那么它是(缺少依赖关系)。

+0

谢谢你的有用答案!正如我在其他一些评论中指出的那样,我很清楚并行性问题,并将其从我的问题中省略,因为我只对程序方面感兴趣。但初学者阅读你的平行横幅是很好的! :d – 2015-03-09 22:59:43

2

如果您想要支持并行构建,首先此结构无效;如果您使用-j选项调用make,它将同时运行所有三项先决条件规则,因为尽管所有这些规则必须在build之前完成,但它们都不依赖于对方,因此没有订购定义(也就是说, t说必须在do-build可以运行之前完成)。

其次,GNU make有一些programmatically defining rules的设施。目前,GNU make目前没有能力搜索已经定义的目标,因此与.if !target(...)没有直接的类比。

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

+0

谢谢@MadScientist,这是一个有用的答案,尤其是解决方法。定义多行宏的能力似乎特别重要。 – 2015-03-02 17:04:16