0

所以我正在编写一个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),它将为所有五个文件运行该块。仍然不知道为什么它以这种方式工作,但不是以前的方式。

4

1 回答 1

1

首先,我不明白怎么TESTIN可能是正确的。这一行:

TESTIN = tests/*.in

在 Make 中不是有效的通配符语句;它应该给变量TESTIN赋值tests/*.in。但是让我们假设它的值是t01.in t02.in t03.in t04.in t05.inor 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.int04.in。但是 的时间戳t02.out早于 的t02.in,所以 Make 不会尝试“重建” t02.in;同样t05.in。和的时间戳分别晚于t02.err和的时间戳,因此当您添加先决条件时,Make 会运行所有测试。您可以通过检查时间戳和试验来测试这个理论。t05.errt02.int05.in%.errtouch

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

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 开头。)

于 2013-08-11T01:20:50.033 回答