Make 删除中间文件

问题描述 投票:0回答:2

尝试将编译输出组织到构建目录时,

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

我相信

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

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

makefile
2个回答
2
投票

我相信 make 将 build/obj/test-mpi.o 视为中间文件。

是的,看起来不错。

但是,我期望

build/obj/test-mpi.o
不会被视为中间文件,因为它明确出现在目标中
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
[...]

鉴于

$(OBJ_DIR)
扩展为
build/obj
pattern
$(OBJ_DIR)/%.o
matches
build/obj/test-mpi.o
。这与明确出现的
build/obj/test-mpi.o
相反。

即便如此,您已经正确阅读了 GNU

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

我错过了什么吗?

很明显,正如 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

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


0
投票

我遇到了与@gkaf 完全相同的问题,并且发现它很疯狂:

make
删除目标文件( 在 Makefile 中提到,尽管是隐含的)有效地违背了
make
的目的(避免重新编译).. . 感谢@John Bollinger 澄清隐式/显式的区别,这就是
make
.

的预期行为

.PRECIOUS
更好的解决方案可能是
.NOTINTERMEDIATE
,如

.NOTINTERMEDIATE: $(OBJS)

如记录here(您必须先构造变量

$(OBJS)
)。

另一种选择是完全避免模式规则(这会带来其他陷阱),转而使用静态模式规则。像这样的东西:

$(OBJS) : $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c ; ...

现在这是通过

$(OBJS)
对目标文件的显式引用(我希望!),因此它不受问题的影响。再次,价格是需要
$(OBJS)
的定义。

请注意,关于静态模式与模式的文档似乎没有提到这些要点(至少没有明确提及;))

© www.soinside.com 2019 - 2024. All rights reserved.