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

Mic*_*ald 4 makefile gnu-make bsdmake

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

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

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

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

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

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

build: pre-build
build: do-build
build: post-build
Run Code Online (Sandbox Code Playgroud)

这将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
Run Code Online (Sandbox Code Playgroud)

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

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

bob*_*ogo 5

FWIW 这里是 make 等效语法

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

基本上,你希望看到这样的片断:

build: pre-build
build: do-build
build: post-build
Run Code Online (Sandbox Code Playgroud)

对于configure,test和也类似install。这暗示了一个带有某个eval地方的循环:

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

targets := configure build test install

$(foreach _,${targets},$(eval $(call makerule,$_)))
Run Code Online (Sandbox Code Playgroud)

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

FWIW,这是扩展foreach

  • make扩展要迭代的列表
    • ${targets}变成configure, build,testinstall
    • 我们有 $(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)开始工作,阅读本文作为make语法
  • 注意扩展$(eval)为空!它的所有工作都是作为副作用完成的。清洗,起泡,冲洗,重复。

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