我有一个具有以下目录结构的项目:
$tests/ $doc/
| |-makefile
+------+-------+ |
| | | tests/
test1/ test2/ test3/ |
| | | test1.rst, test2.rst, test3.rst
test1.e test2.e test3.e
$doc/tests
目录中的文件,例如test1.rst
,是$tests/test1/test1.e
创建的。我遇到makefile的问题,指定源文件在$tests/*/*.e
中,目标文件在$doc/tests/*.rst
中。
我已经看过几个类似的问题,但是无法使用正确的makefile语法。
此makefile适用于单个文件示例
SOURCES = $(wildcard $(tests)/*/*.e)
OBJECTS = $(addprefix $(doc)/tests/,$(notdir $(SOURCES:.e=.rst)))
# single file trial
SRC = $(tests)/test1/test1.e
OBJ = $(doc)/tests/test1.rst
$(OBJ): $(SRC)
debugvars:
@echo SOURCES=$(SOURCES)
@echo OBJECTS=$(OBJECTS)
# define how to create any RST file from a testcase
%.rst:
$(scripts)/wr_rst.py --infile $<
# define how to create an RST file from a testcase
%.rst: %.e
$(scripts)/wr_rst.py --infile $<
.e.rst:
$(scripts)/wr_rst.py --infile $<
.SUFFIXES: .e .rst
我在使用完整的对象列表时遇到了麻烦,例如
all: $(OBJECTS)
$(OBJECTS): $(SOURCES)
$(scripts)/wr_rst.py --infile $<
生成 test1.rst
3次,忽略test2,3.rst
。 $(SOURCES)
和$(OBJECTS)
是正确的。我怀疑$<
不会迭代(SOURCES)
以下是make -d
No implicit rule found for `$tests/test3/test3.e'.
Finished prerequisites of target file `$tests/test3/test3.e'.
No need to remake target `$tests/test3/test3.e'.
Considering target file `tests/test3.rst'.
File `tests/test3.rst' does not exist.
Pruning file `$tests/test1/test1.e'.
Pruning file `$tests/test2/test2.e'.
Pruning file `$tests/test3/test3.e'.
Finished prerequisites of target file `tests/test3.rst'.
Must remake target `tests/test3.rst'.
$scripts/wr_rst.py --inile $tests/test1/test1.e
Putting child 0x00ee6420 (tests/test3.rst) PID 11720 on the chain.
Live child 0x00ee6420 (tests/test3.rst) PID 11720
Writing RST file $doc/tests/test1.rst
Reaping winning child 0x00ee6420 PID 11720
Removing child 0x00ee6420 PID 11720 from chain.
Successfully remade target file `tests/test3.rst'.
答案 0 :(得分:3)
(这个问题看起来非常熟悉 - 我几乎发誓已经提出并回答了一个基本相同的问题。)
让我们分阶段进行。我们可以一次写一条规则:
$(doc)/tests/test1.rst: $(tests)/test1/test1.e
...
但这很乏味。正是这种情况迫切需要一个通配符解决方案,例如模式规则,但Make的一个严重缺点是它对通配符的粗略处理。重复使用通配符的模式规则:
$(doc)/tests/%.rst: $(tests)/%/%.e
...
是不允许的。但我们可以使用eval
编写规则:
define template
$(doc)/tests/$(1).rst: $(tests)/$(1)/$(1).e
use some tool to build $$@ from $$<
endef
$(eval $(call template,test1))
$(eval $(call template,test2))
...
然后,我们可以将该作业委托给eval
,而不是编写所有这些foreach
语句:
TESTS := test1 test2 ...
$(foreach TEST,$(TESTS),$(eval $(call template,$(TEST)))
然后我们可以将其委托给wildcard
,而不是编写测试列表,并使用相同的列表来构建目标文件列表:
TESTS := $(notdir $(wildcard $(tests)/*))
TARGETS := $(patsubst %,$(doc)/tests/%.rst,$(TESTS))
all: $(TARGETS)
将所有这些放在一起很简单,但这个答案很长。