Make 删除中间文件

Make removes files as intermediate

尝试将编译输出组织到构建目录时,make 不断删除目标文件。 Makefile 是:

MPI_INSTALLATION=/home/gkaf/Software/MPI
IDIR=$(MPI_INSTALLATION)/include
LDIR=$(MPI_INSTALLATION)/lib

CC=gcc
CFLAGS=-I$(IDIR)
LDFLAGS=-L$(LDIR) -Wl,-rpath=$(LDIR)

BUILD_DIR=build
OBJ_DIR=$(BUILD_DIR)/obj
BIN_DIR=$(BUILD_DIR)/bin

SRC_DIR=src

LIBS=-lmpi

.PHONY: all
all: test-mpi

.PHONY: test-mpi
test-mpi: prepare $(BIN_DIR)/test-mpi

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
        $(CC) -c -o $@ $< $(CFLAGS)

$(BIN_DIR)/%: $(OBJ_DIR)/%.o
        $(CC) -o $@ $^ $(LDFLAGS) $(LIBS)

prepare: $(BUILD_DIR) $(OBJ_DIR) $(BIN_DIR)

$(BUILD_DIR):
        mkdir -p $(BUILD_DIR)
$(OBJ_DIR):
        mkdir -p $(OBJ_DIR)
$(BIN_DIR):
        mkdir -p $(BIN_DIR)

.PHONY: clean
clean:
        rm -rf $(BUILD_DIR)

编译过程中生成的目标文件build/obj/test-mpi.o在创建可执行文件build/bin/test-mpi后删除。

我认为 makebuild/obj/test-mpi.o 视为 intermediate file。但是,我期望 build/obj/test-mpi.o 不会被视为中间文件,因为它明确出现在目标 $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c 中并且 gnu make 文档指出“通常,如果文件在将 makefile 作为目标或先决条件。

这种行为 has been reported 在一个类似的问题中,但我认为在这两种情况下,文件不应被视为中间文件,因为它们出现在目标中。我错过了什么吗?

I believe that make treats build/obj/test-mpi.o as an intermediate file.

是的,看起来不错。

However, I was expecting that build/obj/test-mpi.o would not be treated as an intermediate file since it appears explicitly in the target $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c [...]

鉴于 $(OBJ_DIR) 扩展为 build/obj 模式 $(OBJ_DIR)/%.o 匹配 build/obj/test-mpi.o。这与明确出现的 build/obj/test-mpi.o 相反。

即便如此,您已正确阅读 GNU make 文档:如果 make 被提及为某些目标或先决条件,则 make 不会将 build/obj/test-mpi.o 视为中间文件其他规则。但事实并非如此。如果 make 完全构建该文件,那完全是 make 的想法,尽管事实上您为其做出该决定奠定了基础。这正是中间文件的含义。

Am I missing something?

显然,正如 GNU 文档所说,您没有理解文件在 makefile 中“提及”的含义。这意味着文件名在宏扩展后作为规则的目标或先决条件出现在 makefile 文本中。示例:

$(BIN_DIR)/test-mpi: $(OBJ_DIR)/test-mpi.o

$(OBJ_DIR)/test-mpi.o: $(SRC_DIR)/test-mpi.c

匹配隐式(“模式”)规则的目标或先决条件模式是不够的。事实上,正是 make 旨在删除的隐式规则链中作为中间体生成的文件。在这方面,makefile 中定义的隐式规则与 make 的内置隐式规则没有区别。

但是,尽管像您询问的文件这样的文件肯定是中间文件,因为 GNU make 定义了该术语,make 在这里还有一项额外的功能可能会满足您的目的。如果要使用模式指定要保留的中间目标,则可以通过将模式指定为特殊目标的先决条件来实现 .PRECIOUS,如下所示:

.PRECIOUS: $(OBJ_DIR)/%.o

匹配这种模式的中间文件将免于自动删除,否则它们将受到自动删除。