我目前正试图编写一个Makefile,以正确构建一个包含git子模块的项目。这个子模块有自己的一组makefile,并同时生成多个目标,包括一些库。
此Makefile应具有以下属性。
- 即使使用并行构建,也不要两次重建子模块
- 当子模块代码发生变化时,更新子模块目标(可能因为我浏览了主存储库的修订版)
- 当子模块库发生更改时,重新链接主项目
- 不要在顶层项目中复制粘贴子模块的Makefiles(即保持Makefiles递归)
只是为了设定想法,这里有一些似乎有效的东西。
FOO_SUBDIR := $(CURDIR)/foo
LDFLAGS := -L$(FOO_SUBDIR)
FOO_LIBSFILES := $(FOO_SUBDIR)/libfoo.a $(FOO_SUBDIR)/libgnufoo.a
FOO_LDLIBS := -lfoo -lgnufoo
.PHONY: all
all: main
# There are theoretically 3 main binaries
main: main.c $(FOO_LIBSFILES)
gcc -o $@ $< $(LDFLAGS) $(FOO_LDLIBS)
$(FOO_LIBSFILES): libfoo
@# Do nothing
.PHONY: libfoo
libfoo:
$(MAKE) -C $(FOO_SUBDIR)
我加了一个空配方,似乎很管用,但我不明白为什么。
其思想是始终依赖子模块的Makefile来重建(或不重建)libfoo.a
和libgnufoo.a
,并让主Makefile决定是否需要重建main
。没有空的配方是行不通的。当修改foo/foo.c
时,则重建libfoo.a
,但make
不重建main
。
我有一种感觉,空配方强制检查目标文件的日期。但我找不到关于这种行为的文档。
这是正确的路吗?有什么我应该注意的陷阱吗?还有什么不那么晦涩的方法吗?或者关于这种行为的任何文档?
提前谢谢。
您的解决方案总体上是正确的-在顶层生成文件中,您添加了可用于子项目的目标。这是通过自己的makefile处理独立(子)项目的唯一正确方法。
您询问的具体问题与不终止依赖libfoo的规则有关,GNU make要求规则具有命令,即使它是no-op。改为:
$(FOO_LIBSFILES): libfoo ;
这实际上是相同的no-op,但更惯用。