调用父目录的Makefile

10

我有一个项目,其目录结构如下:

foo/
foo/Makefile
foo/bar/

我的目标是添加一个文件foo/bar/Makefile,这样如果我在foo/bar中调用make,就会使用父目录的Makefile。这是一种倒置的递归Makefile结构(我希望每个Makefile都调用父目录,直到达到项目根目录)。
由于从错误的目录调用符号链接会破坏所有相对路径,因此符号链接失败:
$ ln -s ../Makefile foo/bar/Makefile
$ make -C foo/bar
[error]

我找到的唯一解决方案是编写一个 Makefile,其中包含我感兴趣的所有目标,并使用该目标调用父目录:
$ cat foo/bar/Makefile
all clean:
    $(MAKE) -C .. $@

这种方法很繁琐且容易出问题。是否有更加优雅的解决方案呢?

原因

该项目是一个包含多个子目录的大型LaTeX文档,其中包括章节、图片等.tex文件。我想能够在任何一个子目录中调用make来构建文档。


1
如果你觉得你的解决方案“费力且容易出错”,为什么不使用$(MAKE) -C /path/to/project/root $@呢?这样,你只需要一个递归调用Make而不是多个,而且一个破损的makefile不会影响到树下面的所有文件。 - Beta
1
你不需要手动指定你想要的目标,可以使用匹配任何规则这篇文章讨论了如何做到这一点(以及其他很多事情)。 - Etan Reisner
感谢@EtanReisner! - Chris Cummins
4个回答

7
感谢Etan Reisner指出了匹配任何规则。这个Makefile将捕获所有目标并将它们传递给父Makefile:
all:
    @make -C .. $@
%:
    @make -C .. $@

请注意,除了匹配任何规则外,还需要提供一个默认的all规则,否则如果不带参数调用make,它会抱怨:make: *** No targets. Stop.

all %: ; @make -C .. $@ - Etan Reisner
@EtanReisner 你不能混合使用隐式规则和普通规则,因此会出现重复。 - Chris Cummins
好的,它可以在GNU Make 3.81中工作,但在更新的版本中会出错。 - Etan Reisner

5

在@chris-cummins之前的回答的基础上,最好使用$(MAKE)代替@make

这将保留诸如并行构建(-j XX)等内容,否则你将失去很多性能优势。

最终版本为(已在GNU Make 4.2.1上测试):

all:
    $(MAKE) -C .. $@
%:
    $(MAKE) -C .. $@

关于此问题的解释,请见此答案


2
注意:如果您复制粘贴此示例,请将$(MAKE)之前的空格更改为制表符! - Ott Toomet

2
您可以创建一个自定义函数来在正确的文件夹中运行make
make-foo() {
    make -C /absolute/path/to/foo "$@"
}

这个可行,谢谢。不过我更希望有一个仅限于 make 的解决方案,因为我不想为了一个项目而修改我的 shell 环境。这也可以通过别名实现:alias make-foo='make -C /abs/path/to/foo' - Chris Cummins

1
您不需要多个 Makefile 和递归调用 Make。 递归的 Make 本身就有问题,除非您确切地了解它的限制,否则不应使用。GNU Make 的功能取决于其环境。 因此,在严肃的系统中(而不是玩具系统),人们应始终控制环境并在包装器 shell 脚本中设置环境,然后从顶层调用 Make(仅一次)。 您对“仅限 make”的需求是错误的。在您的情况下,包装器脚本进入一个循环,寻找名为 Makefile 的文件,如果找不到,则 cd 到父目录并重复。 找到后,使用给定的参数执行 Make。在我的实践中,我还使用了上述更精细的版本,其中包装器脚本研究了给定的参数,并为那些目标加上了它开始的子目录的路径。
subdir>make foobar

等同于

>make subdir/foobar

1
嗨,马克,感谢你的回答,但我不同意递归make的观点。递归make本身并不是坏的,在这种简单情况下,它的任何常见批评都不适用。除了顶层之外的所有Makefile都是简单的包装器,并且不会向环境中注入任何内容。 - Chris Cummins
@ChrisCummins 没必要反对,听起来你理解了递归Make的限制,就像我说的,如果你更喜欢使用它而不是包装脚本,那么可以使用。 - Mark Galeck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接