I have a project with the following directory structure:
$tests/ $doc/ | |-makefile +------+-------+ | | | | tests/ test1/ test2/ test3/ | | | | test1.rst, test2.rst, test3.rst test1.e test2.e test3.e
A file in the $doc/tests
directory e.g test1.rst
is created from $tests/test1/test1.e
. I’m having problems with the makefile specifying that the source files are in $tests/*/*.e
and the destination files are in $doc/tests/*.rst
.
I’ve seen several similar questions but haven’t been able to workout the correct makefile syntax.
This makefile works for a single file example
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
I’m having trouble when using the full list of objects i.e.
all: $(OBJECTS) $(OBJECTS): $(SOURCES) $(scripts)/wr_rst.py --infile $<
test1.rst
is generated 3 times and test2,3.rst
are ignored. The $(SOURCES)
and $(OBJECTS)
are correct. I suspect that $<
does not iterate over the (SOURCES)
Here is some of the output from 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'.
Advertisement
Answer
(This question looks very familiar– I’d almost swear that one essentially the same has been asked and answered.)
Let’s take this in stages. We could write the rules one at a time:
$(doc)/tests/test1.rst: $(tests)/test1/test1.e ...
but that’s tedious. It’s the kind of situation that cries out for a wildcard solution, such as a pattern rule, but one of Make’s serious shortcomings is its crude handling of wildcards. A pattern rule in which the wildcard is repeated:
$(doc)/tests/%.rst: $(tests)/%/%.e ...
is not allowed. But we could write the rules using 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)) ...
Then instead of writing all of those eval
statements, we can delegate that job to foreach
:
TESTS := test1 test2 ... $(foreach TEST,$(TESTS),$(eval $(call template,$(TEST)))
Then instead of writing that list of tests, we can delegate that to wildcard
, and use the same list to construct a list of target files:
TESTS := $(notdir $(wildcard $(tests)/*)) TARGETS := $(patsubst %,$(doc)/tests/%.rst,$(TESTS)) all: $(TARGETS)
Putting all of these together is straightforward, but this answer is getting long.