我有一个Makefile来执行一个大致如下的测试套件:
%.diff.png: %.test.png echo '$*: Comparing with good PNG.' %.test.png: %.pdf echo '$*: Converting PDF to PNG.' %.pdf: %.tex echo '$*: Generating PDF output.'
所有echo
语句都补充了真实Makefile中的实际测试。
当我使用make test
执行所有这些测试时(上面没有显示test
目标),我显然得到线性输出:
... umtest200b: Generating PDF output. umtest200b: Converting PDF to PNG. umtest200b: Comparing with good PNG. ...
当我使用多作业make(make -j2 test
,例如)运行这些测试时,测试以“线程”顺序执行:
... umtest202a: Generating PDF output. umtest202b: Generating PDF output. ... umtest202a: Converting PDF to PNG. umtest202b: Converting PDF to PNG. ... umtest202a: Comparing with good PNG. umtest202b: Comparing with good PNG. ...
也许你可以看到问题;在发现测试是否失败之前,它已经通过所有的PDF生成和每次其他测试的PNG转换。
是否有办法组织测试,以便即使在运行多个作业时,测试也会在完成下一次测试之前完成测试?或者这是一个更好make
的任务?
答案 0 :(得分:1)
我在-j
标志上做了一些阅读,我认为问题是这会为独立规则开始新的工作。每个图像的作业都是独立的,因此每个目标的第一个依赖关系将像您所看到的那样运行。
我认为这里的主要问题是这个任务本质上是串行的,也就是说每个目标的依赖关系必须按顺序运行,一个接一个。因此,在每个目标中,您无法利用多级编程,在此粒度级别。
由于make
似乎没有按照您想要的顺序处理依赖项,因此支持并行测试的单元测试框架可能更适合。我通过一些谷歌搜索了解了其中几个出口,但我不能推荐我什么时候没有使用过,而且我不确定你使用的是哪种语言。
答案 1 :(得分:1)
除非明确指定了目标的执行顺序,否则make
将以任意顺序执行它们 - 无论是并行还是非并行模式。此订单经历make
的内部算法,在您的情况下会产生令人不快的结果。
解决方案是推动对测试的明确排序。
从你的makefile部分,我假设存在一个未公开的“源”变量,其中包含要测试的目标列表(在这些目标上隐式的依赖)。此变量的立即扩展也会产生正确的结果。
假设变量是这样的:
list=file1 file2 file3 ... fileN
然后,要解决问题,只需生成以下依赖项即可:
file2: file1
file3: file2
...
fileN: fileN-1
run_tests: fileN
我们应该如何生成它?让我们在list
变量得到其值后编写一个foreach-eval循环:
len=$(words $(list))
$(foreach t, \
$(join \
$(addsuffix : ,$(wordlist 2,$(len),$(list)) run_tests), \
$(list) \
) \
, $(eval $(t)) \
)
这将生成一部分makefile,就像C预处理器一样(或者更确切地说,就是LISP宏)。它将如下工作:对于由t
形成的列表中的每个项join
(将第一个列表的每个元素与第二个列表的对应元素连接起来)列表file2 file3 ... fileN run_tests
到每个元素其中添加了后缀:
(因此形成file2: file3: ... fileN: run_tests:
),其中包含源列表file1 file2 ... fileN
; - 对于列表中包含连接元素的每个此类项t
,将其作为makefile源的一部分进行评估,因此按照上面所示的规则进行处理。
现在你只需要调用run_tests目标,它将逐一进行。
答案 2 :(得分:1)
突然间,我想到了另一个想法!
%.diff.png:
$(MAKE) $*.test.png
echo '$*: Comparing with good PNG.'
这解决了所有问题,除了测试可能没有按正确的顺序调用(但实际上它们很可能会很顺利)。