首页 > 解决方案 > GNU 直接跳过链接

问题描述

我有一个makefile,由于各种原因,它每次都依赖于一个支持的python脚本来运行,并从几个外部位置获取文件,复制到工作目录中,并在编译之前通过一个单独的预处理器运行。

此 makefile 必须能够并行运行 (-j8),因此无法保证处理顺序。

在尝试显式指定先决条件时,我创建了一种情况,其中 make 会跳过所有目标文件,直接进行链接,并且由于必要的对象不存在而失败。在第二次运行时,所有对象都已经存在(预处理步骤跳过了已经存在的文件)并且所有文件都被正确编译和链接。

在没有 -j# 的情况下运行时一切正常,但在我添加 -j2 的那一刻,跳过开始。

以下是一个示例生成文件:

GEN_FILES := file1.cpp file2.cpp file3.cpp
CXX_FILES := bin_main.cpp $(GEN_FILES)
OBJ_FILES := $(patsubst %.cpp,%.o,$(CXX_FILES))

.PHONY : all clean prepare
all : bin_file

prepare :
# Copy and preprocess all source files
    [ -f file1.cpp ] || cp d1/file1.cpp .
    [ -f file2.cpp ] || cp d2/file2.cpp .
    [ -f file3.cpp ] || cp d3/file3.cpp .

$(OBJ_FILES) : prepare

bin_file : $(OBJ_FILES)
    [ -f file1.o ] && [ -f file2.o ] && [ -f file3.o ] && touch bin_file

%.o : %.cpp
    @echo "Compiling $<..."
    [ -f $< ] && touch $@

clean :
    $(RM) *.o
    $(RM) file*
    $(RM) bin_file

我怎样才能让它一口气构建,首先运行准备收集所有文件,然后根据需要进行编译和链接?

标签: makefileprerequisites

解决方案


正如 code_fodder 提到的那样,问题是源文件的创建。

基本上发生的情况是,您没有告诉 make 如何创建这些源文件,因此据 make 知道它们不存在并且没有办法创建它们。因此,例如,当 make 想要构建时,file1.o它会查看您的模式规则并发现它可以file1.ofile1.cpp. 因此,它寻找如何构建file1.cpp. 不file1.cpp存在,并且 make 知道没有规则会构建它,因此 make 忽略该模式规则不匹配。

然后 make 看到目标:

$(OBJ_FILES) : prepare

所以它认为创建目标文件不需要配方,只需运行链接行。下一次,make 会看到准备好的源文件(来自之前的构建),然后它可以使用您的模式规则。

如果您将模式规则更改为静态模式规则,您明确告诉 make 确切使用什么规则,而不是为它提供可能使用的规则,如果它不匹配它可以忽略(这就是模式规则),你会看到错误:

$(OBJ_FILES): %.o : %.cpp
        @echo "Compiling $<..."
        sleep 1
        [ -f $< ] && touch $@

会告诉你:

make: *** No rule to make target 'file1.cpp', needed by 'file1.o'.  Stop.

请记住,make 是在实际构建任何东西之前寻找匹配的模式规则:它不想构建每个可能的匹配模式规则的每个可能的先决条件,以决定在它的末尾是否可以使用该规则。该规则是根据文件系统的当前状态以及您给出的关于它可能进行的更改的规则进行匹配的。Make 不知道如果它要调用prepare目标,它正在寻找的源文件会神奇地出现。

你的基本问题是这个语句是错误的依赖关系:

$(OBJ_FILES) : prepare

目标文件依赖于的并不是真的prepare;真实的是,准备好的源文件依赖于prepare. 正如您的模式规则所示,目标文件仅依赖于“准备好的”源文件。应该写下这条规则,而不是:

$(GEN_FILES): prepare

如果你这样做,-j一切都会按照你的意愿等待。


推荐阅读