Reputation: 43
My makefile failed. My idea was to extract files from a certain file and put them in a temporary directory. This is then rsync'ed to a source directory. Since rsync only updates when a file has changed, makefiles in the source directory do not remake unless necessary. I have isolated the problem below:
.PHONY: extract clean
FILES = filea1.cc filea2.cc filea3.cc \
filea1.hh filea2.hh filea3.hh \
filea1.py filea2.py filea3.py \
dir-cc/filea1.cc dir-cc/filea2.cc dir-cc/filea3.cc \
dir-cc/filea1.hh dir-cc/filea2.hh dir-cc/filea3.hh \
dir-py/filea1.py dir-py/filea2.py dir-py/filea3.py
PATTERN := $(sort $(addprefix build/%., $(patsubst .%,%,$(suffix $(FILES)))))
extract: $(addprefix build/, $(FILES))
$(PATTERN):
mkdir -p $(dir $@); echo "hello!" > $@
#build/%.cc:;mkdir -p $(dir $@); echo "hello!" > $@
#build/%.hh:;mkdir -p $(dir $@); echo "hello!" > $@
#build/%.py:;mkdir -p $(dir $@); echo "hello!" > $@
temp:
echo $(PATTERN)
clean:
rm -rf build
Doing make temp gets 'build/%.cc build/%.hh build/%.py' but 'make extract' fails to make all the files:
build:
dir-cc dir-py filea1.cc filea2.cc filea3.cc
build/dir-cc:
filea1.cc filea2.cc filea3.cc
build/dir-py:
filea1.py filea2.py filea3.py
The hh files are missing. Unbelievably, in the actual work, the cc files are missing. Anyway, commenting out $(PATTERN), and removing the comments so that the targets in the code above are separate, does get all the files:
build:
dir-cc filea1.cc filea1.py filea2.hh filea3.cc filea3.py
dir-py filea1.hh filea2.cc filea2.py filea3.hh
build/dir-cc:
filea1.cc filea1.hh filea2.cc filea2.hh filea3.cc filea3.hh
build/dir-py:
filea1.py filea2.py filea3.py
Since everything has to be automatic in the actual work, and the rule is the same for all the targets (so I should not have to retype it), I vastly prefer the first version. I read the manual but I am perplexed as to why make does this. I am using GNU Make 4.1.
Upvotes: 2
Views: 737
Reputation: 43
There was a good resolution: use the ordinary (non pattern) multiple target
rule $(FILES):;rule
and define pattern specific variable values to adjust
the rule to the file extension.
Upvotes: 0
Reputation: 100836
It's explained in the last paragraph of the Pattern Intro section:
Pattern rules may have more than one target. Unlike normal rules, this does not act as many different rules with the same prerequisites and recipe. If a pattern rule has multiple targets, make knows that the rule’s recipe is responsible for making all of the targets. The recipe is executed only once to make all the targets.
You can't write a pattern rule with many different pattern targets, such that make will run the recipe once per individual target. That's not how it works.
You could do this, for your very simple case:
FILETYPES := $(sort $(suffix $(FILES)))
$(foreach T,$(FILETYPES),$(eval build/%$T: ; mkdir -p $$(@D); echo "hello!" > $$@))
Upvotes: 1