首页 > 解决方案 > 通过静态库检查 make 依赖项

问题描述

我在 linux 上使用 make 构建多个可执行文件。每个可执行文件都有自己的文件夹自己的小makefile,其中包括共享的makefile.rules。因此,为了构建项目,我使用父 makefile 单独调用每个 makefile。

像这样:

# Find Makefiles
MKFLS += $(subst Makefile,,$(shell find */ -name Makefile ))

# Standard build rules, pass down to subordinate make files
all debug install: tags
    @$(foreach folder,$(MKFLS), $(MAKE) -C $(folder) $@ || exit;)

我将共享代码放在静态库中。每个也有它自己的文件夹和makefile。在为 exe 或 lib 构建可执行库和静态库时,我正在建立依赖关系:

$(CC) $(CFLAGS) -c -MMD -MP -o $@ $<

然后包括生成的文件(仅用于该 exe 或 lib):

-include $(OBJECTS:.o=.d)

现在,如果库的源文件或内部头文件之一发生更改,我想确保生成可执行文件。我尝试包含库生成的 .d 文件,但这不起作用。

首先,每个可执行文件都定义了静态库及其构建位置:

# My Libraries
LOCALLIBS += $(UTILSLIB)/libone.a
LIBSRC += $(UTILSDIR)/onelib
LOCALLIBS += $(UTILSLIB)/libtwo.a
LIBSRC += $(UTILSDIR)/twolib

然后在包含的全局规则 Makefile 中:

# Rules For Library Dependencies
# Include library dependencies if they exist
-include $(shell find $(LIBSRC) -name \*.d )

# Rule to make libraries that are part of this source tree
$(LOCALLIBS):
    $(foreach folder,$(LIBSRC), $(MAKE)-C $(folder) $(MAKECMDGOALS) || exit;)
    @touch $(LOCALLIBS)

我不认为依赖关系贯穿静态库。因此,即使构建了 libone.a,可执行文件也不会。将需要第二次运行。我可以尝试让我的可执行文件依赖于我的 libone.a 中的对象,但现在我的 makefile 变得混乱和复杂。

所以....有没有办法解决这个问题?这样做的正确方法是什么?

标签: makefilegnu-make

解决方案


要获得您要求的结果,您必须为目标文件、库和可执行文件提供生成先决条件列表。

您已经有了对象文件的方法。您生成依赖项列表文件:

$(CC) $(CFLAGS) -c -MMD -MP -o $@ $<

然后包括它们:

-include $(OBJECTS:.o=.d)

到目前为止,一切都很好。(我假设这已经正常工作了——你没有给我们足够的 makefile 来测试它。)

这种方法不适用于图书馆。它适用于目标文件,因为源文件包含头文件列表(作为#include指令)并且编译器($(CC))知道如何将它们转换为先决条件列表。库构建工具($(AR)或您正在使用的任何工具)没有要读取的此类文件,也无法构建此类列表。但是不要紧; 对于每个库,您必须以某种方式指定所需内容的列表,因此您的库规则应该如下所示:

libone.a: alpha.o beta.o
    $(AR) -cvq $@ $^.    # or whatever you use

这会照顾图书馆。现在是可执行文件。假设您有一个prime需要来自alpha和的代码的可执行文件gamma。规则将如下所示:

prime: gamma.o libone.a
    $(CXX) -o $@ $^.    # or whatever you use

而已。可执行文件prime不依赖于gamma.h; 如果您更改gamma.h,Make 会注意到它gamma.o已过时,因此prime. 并且prime不依赖于alpha.h; 如果你改变了alpha.h,Make 会注意到它alpha.o已经过时了,因此 so is libone.a,因此 so is prime

(一旦你完成了这么多工作,可能会有进一步的改进。)


推荐阅读