在Makefile

时间:2019-01-17 10:09:01

标签: makefile

我试图在Makefile中使用.DELETE_ON_ERROR目标,以同时删除两个$(OBJ)executable文件(如果配方失败,则无效)。如果在编译模式规则时在任何目标文件中放入错误,则会发生错误并停止。旧的目标文件仍在其位置,但我希望.DELETE_ON_ERROR删除它。

任何人都可以测试代码吗? -include $(DEP)或标志-DDBG会产生影响吗?目标是同时删除失败的.o文件和executable

OUTPUT = executable
CPP := $(shell find $(SRC) -type f -name "*.cpp")
OBJ := $(CPP:.cpp=.o)
DEP := $(OBJ:.o=.d)

CXX := g++
CXXFLAGS =-MMD -MP -DDBG
INCLUDES = -I.

.DELETE_ON_ERROR :

$(OUTPUT): $(OBJ)
    $(CXX) $^ -o $@

%.o: %.cpp
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

-include $(DEP)

.PHONY : clean
clean:
    rm -rf $(OBJ) $(DEP) 

编辑:根据要解决此问题的Ondrej K.解决方案,您需要在编译器前添加@touch命令,以使目标文件发生更改(文档读取为“删除规则的目标如果已更改”。。因此,代码应如下所示:

%.o: %.cpp
    @touch $@
    $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

2 个答案:

答案 0 :(得分:1)

不确定您遇到的失败是什么,但是恐怕确实没有一个好的方法来做到这一点。 .o文件和可执行文件($(OUTPUT))是单独的规则。如果后者失败,则前者已经不在考虑之列。参见documentation

  

.DELETE_ON_ERROR:      如果在制作文件中的任何位置提到.DELETE_ON_ERROR作为目标,那么make将删除规则的目标(如果它已更改且其配方以非零退出状态退出),就像接收时一样一个信号。参见Errors in Recipes

换句话说,如果.o目标本身更新后,生成二进制对象的目标失败,则make将修剪已更改的文件。但是,如果您的可执行文件未链接,它将不会返回并删除目标文件。

不确定会不会很好,但是如果您确实需要,可以通过重构makefile使其基本上具有来自源先决条件规则的直接exec + objs和单个配方来实现。明显的缺点是,这样的规则意味着单个.c文件更改会导致重新编译所有文件(基本上抵消了使用make的巨大好处)。


编辑:我将在评论中进行扩展以澄清。您似乎想要的是:万一.c文件损坏而编译失败,请删除旧的.o文件。这显然不是.DELETE_ON_ERROR的工作方式。如果.o文件已经更新,然后规则失败,它将删除该文件(“如果规则已更改,则删除规则的目标” ),但是在提到的情况下语法上的问题,编译器将在生成.o文件之前失败。

因此,例如,如果您更新了要编译的(模式)规则,以使其首先touch.o文件上{有效地更新了时间戳},然后尝试进行编译。在编译器调用和规则失败后,make会考虑更新失败的根目录目标并将其删除。另外,您也可以更改规则,首先尝试rm预期的'.o'文件,在这种情况下,您实际上不需要使用.DELETE_ON_ERROR(并且如果相关来源没有任何变化) ,该规则不会被使用,因此它实际上并不像听起来那样可怕。两种方法都不是很干净,但是会导致我理解您正在描述的行为。

答案 1 :(得分:0)

写入输出文件时,编译器可能会崩溃。在这种情况下,有一个损坏的输出文件,它比源文件要新。 Make会由于该错误而停止,但是在下一次运行时,它不会重新编译输出文件,因为它比ist来源要新-并且make将在构建步骤中一次又一次地失败。 使用.DELETE_ON_ERROR规则,如果在接触(破坏)输出文件后编译器(或任何构建步骤失败)退出并出错,则make将删除输出文件,因此它将在下次运行时重新编译。 (如果编译器在未触及旧输出文件的情况下发生故障,则无论如何,它将始终在下次运行时重新编译)