所以我正在编写一个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),它会运行所有五个文件的块。仍然不知道为什么它以这种方式工作,但不是之前的方式。
答案 0 :(得分:1)
首先,我看不出TESTIN
如何正确。这一行:
TESTIN = tests/*.in
不是Make中的有效通配符语句;它应该为变量TESTIN
赋予值tests/*.in
。但我们假设它具有值t01.in t02.in t03.in t04.in t05.in
或tests/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.in
和t04.in
。但t02.out
的时间戳早于t02.in
的时间戳,因此Make不会尝试“重建”t02.in
;同样t05.in
。 t02.err
和t05.err
的时间戳分别晚于t02.in
和t05.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开头。)