使用GNU Make构建分层Makefile

3

我有一个项目,分为多个模块,每个模块都在一个目录中托管,比如:

root
|_module_A
 |_module.cpp
 |_Makefile
|_module_B
 |_Makefile
|_main.c
|_Makefile

main.c 依赖于与 module_Amodule_B 相关的 Makefile 中定义的目标。

我希望编写我的 root/Makefile,以考虑两个模块的 Makefile 中定义的目标。

现在,我知道我可以使用 include 指令,但问题在于在 module_Amodule_B 中的目标和文件名未加上它们的目录,因此我会得到类似以下的内容:

make: *** No rule to make target `module.o', needed by `main.c'.  Stop.

有一个好的方法来解决这个问题吗?

谢谢。


你想把目标文件(例如:module.o)放在哪里? - Beta
在与相关源文件相同的(子)目录中。 - akappa
2个回答

3
有几种方法可以做到这一点,但没有一种是完美的。基本问题在于Make擅长使用这里的东西来制作那里的东西,但反过来却不行。
您没有说module_B中的目标是什么;我会持悲观态度,假设module_A和module_B都有名为module的目标(不同的源文件,不同的配方),因此您真的不能使用include。
你必须做出最大的选择是使用递归make:
如果不使用,则root/Makefile必须知道如何构建module_A/module和module_B/module,因此你只需要把这些规则放进去即可。然后你必须要么在子目录makefile中保留冗余规则(并冒着它们与主makefile失去一致性的风险),要么消除它们,要么让它们递归调用主makefile(虽然你不必经常这样做,但肯定看起来很傻)。
如果使用递归Make,则root/Makefile将如下所示:
main: main.o module_A/module.o Module_B/module.o
    ...

main.o: main.c
    ...

%/module.o:
    $(MAKE) -C $(@D) $(@F)

这样做已经足够好了,但它对子目录内的依赖项一无所知,因此有时会失败地重新构建过时的对象。您可以每次都(递归地)执行make clean以保险起见,虽然粗糙但有效。或者强制执行%/module.o规则,这样不会浪费太多,但有点复杂。或者在root/Makefile中重复依赖信息,这很繁琐而且不整洁。这只是关于您优先顺序的问题。

如果你一定要使用递归make,那么这是一个好的、全面的答案,尽管我认为在普通情况下这是一个不好的选择。 - Jack Kelly

1

我可以这样做,但是我已经继承了所有这些模块及其Makefile。由于我很懒,我想尽可能多地重用它们。Makepp有一个奇妙的功能(load_makefile),它会加载放置在给定子目录中的Makefile中的所有定义,并将子目录添加到其中定义的目标前缀中。我想知道是否有一种类似于Makepp的方法可以在Makefile中实现相似的功能,而不是手动复制和粘贴各种Makefile中的所有目标并手动添加子目录前缀。 - akappa
1
@akappa,简短回答:是的,但不可靠。一个简短的 sed 脚本可以在目标前面添加目录名,但如果 makefile 在任何地方使用了相对路径(而且有很多种方式可以这样做),脚本将无法纠正它们。 - Beta
@Beta:谢谢,我想我会写一个单一的Makefile,毕竟这样更容易(而且更清晰)。 - akappa

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