Makefile正在跳过某些依赖项

时间:2013-08-10 23:03:51

标签: makefile gnu-make

所以我正在编写一个makefile,它将把一些文件(* .in)作为我的C ++程序的输入,并将它们的输出(results.out)与给定的正确输出(* .out)进行比较。 具体来说,我有文件t01.in,t02.in,t03.in,t04.in和t05.in. 我已经验证了$ TESTIN = t01.in t02.in t03.in t04.in t05.in. 问题是它似乎只为这些文件中的三个,1,3和4运行%.in:%。out块。为什么要这样做?

OUTPUT = chart
COMPILER = g++
SOURCES = chart.cpp
HEADERS = 
OBJS = $(SOURCES:.cpp=.o)
TESTIN = tests/*.in


all: $(OUTPUT)

$(OUTPUT): $(OBJS)
    $(COMPILER) *.o -o $(OUTPUT)

%.o: %.cpp
    clear
    $(COMPILER) -c $< -o $@


test: $(TESTIN)

%.in: %.out
    ./$(OUTPUT) < $@ > tests/results.out
    printf "\n"
ifeq ($(diff $< tests/results.out), ) 
    printf "\tTest of "$@" succeeded for stdout.\n"
else
    printf "\tTest of "$@" FAILED for stdout!\n"
endif

此外,如果有更好的方法来完成我想要做的事情,或者我可以对这个makefile做出的任何其他改进(因为我对此很新),建议将不胜感激。

编辑:如果我向块添加第二个依赖项(%。in:%。out%.err),它会运行所有五个文件的块。仍然不知道为什么它以这种方式工作,但不是之前的方式。

1 个答案:

答案 0 :(得分:1)

首先,我看不出TESTIN如何正确。这一行:

TESTIN = tests/*.in

不是Make中的有效通配符语句;它应该为变量TESTIN赋予值tests/*.in。但我们假设它具有值t01.in t02.in t03.in t04.in t05.intests/t01.in tests/t02.in tests/t03.in tests/t04.in tests/t05.in,或者这些文件实际存在的位置。

第二,正如@OliCharlesworth指出的那样,这条规则:

%.in: %.out
    ...

是用于构建* .in文件的规则,这不是您想要的。至于为什么它会运行一些测试而不是其他测试,这是我的理论

t01.out的时间戳晚于t01.in的时间戳,因此Make决定必须“重建”t01.in;同样t03.int04.in。但t02.out的时间戳早于t02.in的时间戳,因此Make不会尝试“重建”t02.in;同样t05.int02.errt05.err的时间戳分别晚于t02.int05.in的时间戳,因此当您添加%.err先决条件时,Make会运行所有测试。您可以通过检查时间戳并尝试touch来测试此理论。

无论如何,让我们改写它。我们需要新规则的新目标:

TESTS := $(patsubst %.in,test_%,$(TESTIN)) # test_t01 test_t02 ...

.PHONY: $(TESTS) # because there will be no files called test_t01, test_t02,...

$(TESTS): test_%: %.in %.out
    ./$(OUTPUT) < $< > tests/results.out

现在为条件。您尝试的条件是Make语法; Make会在执行任何规则之前对其进行评估,因此tests/result.out将不存在,而$<之类的变量尚未定义。我们必须将条件放在命令中,用shell语法:

$(TESTS): test_%: %.in %.out
    ./$(OUTPUT) < $< > tests/results.out
    if diff $*.out tests/results.out >/dev/null; then \
  echo Test of $* succeeded for stdout.; \
  else echo Test of $* FAILED for stdout!; \
  fi

(请注意,只有条件的第一行必须以TAB开头。)