我在为非递归 make 系统定义通用规则时遇到了困难。
背景
为了进一步阅读,而不是我复制太多现有材料,请参阅这个较早的问题,它很好地涵盖了基础,并且在构建这个系统时帮助了我。
对于我正在构建的make系统,我想定义系统组件之间的依赖关系-例如组件A依赖于组件B-然后离开make系统以确保构建B构建过程的任何产品之前构建需要它们A 的步骤。由于粒度的原因,这有点浪费(可能会构建一些不需要的中间体),但对于我的用例来说,它满足了易用性和构建性能之间的舒适平衡点。
系统必须处理的一个困难是无法控制 makefile 加载的顺序 - 实际上,这应该无关紧要。然而,正因为如此,在早期加载的 makefile 中定义的组件可能依赖于在尚未读取的 makefile 中定义的组件。
为了允许在所有定义组件的 makefile 中应用通用模式,每个组件都使用变量,例如:$(component_name)_SRC
. 这是非递归(但递归包含)make 系统的常见解决方案。
有关 GNU make 不同类型变量的信息,请参阅手册。总而言之:简单扩展变量(SEV)随着生成文件的读取而扩展,表现出类似于命令式编程语言的行为;在读取所有 makefile 之后,递归扩展变量 (REV) 在 make 的第二阶段进行扩展。
问题
尝试将依赖组件列表转换为这些组件所代表的文件列表时会出现特定问题。
我已经将我的代码提炼成这个可运行的示例,它遗漏了真实系统的许多细节。我认为这很简单,可以在不失去其实质的情况下证明问题。
规则.mk:
$(c)_src := $(src)
$(c)_dependencies := $(dependencies)
### This is the interesting line:
$(c)_dependencies_src := $(foreach dep, $($(c)_dependencies), $($(dep)_src))
$(c) : $($(c)_src) $($(c)_dependencies_src)
@echo $^
生成文件:
.PHONY: foo_a.txt foo_b.txt bar_a.txt hoge_a.txt
### Bar
c := bar
src := bar_a.txt
dependencies :=
include rules.mk
### Foo
c := foo
src := foo_a.txt foo_b.txt
dependencies := bar hoge
include rules.mk
### Hoge
c := hoge
src := hoge_a.txt
dependencies := bar
include rules.mk
这些将运行以提供:
$ make foo
foo_a.txt foo_b.txt bar_a.txt
$
hoge_a.txt 不包含在输出中,因为在foo_dependencies
定义为 SEV 的hoge_src
时候还不存在。
读取所有 makefile 后进行扩展是 REV 应该能够解决的问题,我之前曾尝试将其定义$(c)_dependencies_src
为 REV,但这也不起作用,因为$(c)
然后在替换时间而不是定义时间进行扩展,所以它不再保持正确的值。
如果有人想知道我为什么不使用特定于目标的变量,我担心将变量应用于手册中描述的目标的所有先决条件会导致不同组件的规则之间发生不必要的交互。
我想知道:
- 这个具体问题有解决方案吗?(即有没有一种简单的方法可以使那条线达到我想要的效果?)
- 有没有更典型的方式来构建这样的 make 系统?(即单个 make 实例,从多个 makefile 加载组件并定义这些组件之间的依赖关系。)
- 如果有多种解决方案,它们之间的取舍是什么?
最后的评论:当我写下我的问题时,我已经开始意识到可能有一个解决方案可以使用 eval 来构造 REV 定义,但是因为我在 SO 上的其他任何地方都找不到这个问题,所以我认为值得为了未来的搜索者,无论如何都要问这个问题,另外我想听听更有经验的用户对此或任何其他方法的想法。