如何以编程方式在 GNU Make 中定义目标?
How to programmatically define targets in GNU Make?
我不知道有什么方法可以在 GNU Make 中以编程方式定义目标。这怎么可能?
有时候一个人可以走开with alternate methods. The ability to define programatically targets in Makefiles is however a very important to write and organise complex production rules with make
. Examples of complex production rules are found in the build system of FreeBSD or in Makefile libraries such as BSD Owl
shell 脚本和 Makefile 之间的 main differences 是:
在 Makefile 中,程序的状态由命令行和文件系统给出,因此可以在任务中断后继续执行任务。当然,这需要正确编写 Makefile,但即使这相当困难,也比使用 shell 脚本实现类似效果要容易得多。
在 Makefile 中,用 advises 或 hooks 修饰一个过程非常容易,而这在 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 的该片段的翻译是什么?
首先,如果你想支持并行构建,这个结构是无效的;如果您使用 -j
选项调用 make,它将同时 运行 所有三个先决条件规则,因为虽然所有这些都必须在 build
之前完成,但其中的 none相互依赖,所以没有定义顺序(也就是说,你不说 pre-build
必须在 do-build
可以 运行 之前完成)。
其次,GNU make 有许多 programmatically defining rules 的功能。 GNU make 目前没有的一件事是搜索已经定义的目标的能力,所以没有直接类比 .if !target(...)
.
但是,您可以使用 .VARIABLES
变量来搜索变量是否已定义。因此,如果您想要自己的目标,一种解决方法是定义一个变量,然后让您的规则生成器检查它。
FWIW 是
的等效语法
.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
configure
、test
和 install
也类似。这表明在某处带有 eval
的循环:
define makerule =
: pre-
: do-
: post-
endef
targets := configure build test install
$(foreach _,${targets},$(eval $(call makerule,$_)))
(要玩这个,将 eval
更改为 info
)。小心那些闭包!
FWIW,这是 foreach
的扩展:
- make 扩展要迭代的列表
${targets}
变为 configure
、build
、test
和 install
- 我们有
$(foreach _,configure build test install,$(eval $(call makerule,$_)))
_
设置为第一个值,configure
.
- make 展开
$(eval $(call makerule,configure))
- 评估
eval
,make扩展$(call makerule,configure)
- 它通过将
1
设置为 configure
并展开 ${makerule}
来实现此目的,它会生成 3 行文本:
configure: pre-configure
configure: do-configure
configure: post-configure
$(eval)
开始工作,将此文本阅读为 make syntax
- 注意
$(eval)
的展开是空的!它的所有工作都是作为副作用完成的。
清洗、起泡沫、漂洗、重复。
请注意:我必须同意所有其他评论者的观点:您的模式不好。如果您的 makefile 不 -j
安全,那么它 已损坏 (缺少依赖项)。
我不知道有什么方法可以在 GNU Make 中以编程方式定义目标。这怎么可能?
有时候一个人可以走开with alternate methods. The ability to define programatically targets in Makefiles is however a very important to write and organise complex production rules with make
. Examples of complex production rules are found in the build system of FreeBSD or in Makefile libraries such as BSD Owl
shell 脚本和 Makefile 之间的 main differences 是:
在 Makefile 中,程序的状态由命令行和文件系统给出,因此可以在任务中断后继续执行任务。当然,这需要正确编写 Makefile,但即使这相当困难,也比使用 shell 脚本实现类似效果要容易得多。
在 Makefile 中,用 advises 或 hooks 修饰一个过程非常容易,而这在 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 的该片段的翻译是什么?
首先,如果你想支持并行构建,这个结构是无效的;如果您使用 -j
选项调用 make,它将同时 运行 所有三个先决条件规则,因为虽然所有这些都必须在 build
之前完成,但其中的 none相互依赖,所以没有定义顺序(也就是说,你不说 pre-build
必须在 do-build
可以 运行 之前完成)。
其次,GNU make 有许多 programmatically defining rules 的功能。 GNU make 目前没有的一件事是搜索已经定义的目标的能力,所以没有直接类比 .if !target(...)
.
但是,您可以使用 .VARIABLES
变量来搜索变量是否已定义。因此,如果您想要自己的目标,一种解决方法是定义一个变量,然后让您的规则生成器检查它。
FWIW 是
的等效语法.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
configure
、test
和 install
也类似。这表明在某处带有 eval
的循环:
define makerule =
: pre-
: do-
: post-
endef
targets := configure build test install
$(foreach _,${targets},$(eval $(call makerule,$_)))
(要玩这个,将 eval
更改为 info
)。小心那些闭包!
FWIW,这是 foreach
的扩展:
- make 扩展要迭代的列表
${targets}
变为configure
、build
、test
和install
- 我们有
$(foreach _,configure build test install,$(eval $(call makerule,$_)))
_
设置为第一个值,configure
.- make 展开
$(eval $(call makerule,configure))
- 评估
eval
,make扩展$(call makerule,configure)
- 它通过将
1
设置为configure
并展开${makerule}
来实现此目的,它会生成 3 行文本:
configure: pre-configure
configure: do-configure
configure: post-configure
- 它通过将
$(eval)
开始工作,将此文本阅读为 make syntax- 注意
$(eval)
的展开是空的!它的所有工作都是作为副作用完成的。 清洗、起泡沫、漂洗、重复。
请注意:我必须同意所有其他评论者的观点:您的模式不好。如果您的 makefile 不 -j
安全,那么它 已损坏 (缺少依赖项)。