Suppose, I have 2 files, dependent upon each other:
./pictures/1_data.tex
|
V
./data/1.pl
So, 1_data.tex is generated from the Perl file. To do it I have the following rule in the makefile:
./pictures/1_data.tex: ./data/1.pl
perl given.pl 1 > $#
If I have multiple files with this pattern:
./data/1.pl
./data/2.pl
...
./data/n.pl
I'd like to use wildcards to process them. I tried this:
./pictures/*_data.tex: ./data/*.pl
perl given.pl $* > $#
But it generates incorrect command:
perl given.pl pictures/1_data > pictures/1_data.tex
Is it possible to have a backreference only to 1, and not to the whole target? As $* does.
Use pattern rules:
all: $(patsubst ./data/%.pl,./pictures/%_data.tex,$(wildcard ./data/*.pl))
./pictures/%_data.tex : ./data/%.pl
perl given.pl $* > $#
Related
as i am currently working on my makefile i encountered another problem. I am using this rule as part of my building process which transforms .mid files into .s files.
$(MIDAS): $(BLDPATH)/%.s: %.mid
$(shell mkdir -p $(dir $#))
#test $($< | sed "*")
$(MID2AGB) $(MIDFLAGS) -G$($< | sed ".*mus/vcg([0-9]{3})/.*\.mid") $< $#
All .mid input files follow the same format: .mus/vcg[0-9]{3}/..mid, meaning they are stored in different directories following the naming convention vcgXXX where X can be any digit from 0-9. (Maybe my regex is even wrong for this).
When i am calling $(MID2AGB) i want to use a compiler flag -GXXX. However the XXX of this flag has to match the XXX from the input file path.
My makefile code does not work. Any idea how to fix this problem?
There is a crude but effective way to do this using Make's string manipulation tools:
# suppose the source is .mus/vcg456/Z.mid
$(MIDAS): $(BLDPATH)/%.s: %.mid
#echo $* # this gives .mus/vcg456/Z
#echo $(subst /, ,$*) # this gives .mus vcg456 Z
#echo $(word 2,$(subst /, ,$*) # this gives vcg456
#echo $(subst vcg,,$(word 2,$(subst /, ,$*)) # this gives 456
I have a list of files contained in another file. I want to use this list as prerequisite for some target and for doing so I use a function that reads the list from file.
The problem is that I have different lists for different targets so I need to pass the target as argument to the function that reads the list. Something like that (that does not work):
getlist = $(shell cat $1)
tmp%: $(call getlist, %)
#cat file1 > $#
#cat file2 >> $#
file%:
#touch $#
#echo "$#" > $#
clean:
#rm file1 file2 tmp
where the list for building the tmp1 file is in the 1 file, the one for building the tmp2 file is in the 2 file and so on and so forth.
If I have instead tmp1: $(call figlist, 1) all works, but I need something capable of treating different file names.
If needed for the solution I can also change the way I named the files.
I am trying to do second expansion in a makefile with substitution.
A sample makefile:
# We have src{0..3}.md documents. Generate them with
#
# for i in src{0..3}.md; do echo "Hello in $i" > $i; done
#
# doc0.txt and doc2.txt are capitalized and doc1.txt and doc3b.txt are
# lowercased.
CAP_DOCS := doc0.txt doc2.txt
LOW_DOCS := doc1.txt doc3.txt
DOCS := $(CAP_DOCS) $(LOW_DOCS)
all: $(DOCS)
.SECONDEXPANSION:
$(CAP_DOCS): $$(#:doc%.txt=src%.md)
tr '[a-z]' '[A-Z]' < $< > $#
.SECONDEXPANSION:
$(LOW_DOCS): $$(#:doc%.txt=src%.md)
tr '[A-Z]' '[a-z]' < $< > $#
And the error I get is
$ make
Makefile:15: *** target pattern contains no `%'. Stop.
I also tried setting perc=% and replacing the % characters with $(perc) and even $$(perc) as I figured it was trying to expand them before the second expansion and failed. It didn't help.
I also couldn't get hiding the % from make with variables to work though that was also my first thought.
I was able to get $(CAP_DOCS): $$(patsubst doc%.txt,src%.md,$$#) and $(LOW_DOCS): $$(patsubst doc%.txt,src%.md,$$# working though.
I haven't tried it, but I wonder if you could just hide the substitution ref in a define or something and achieve the same effect.
I am trying to write a makefile that does something like the following:
%-foo-(k).out : %-foo-(k-1).out
# do something, e.g.
cat $< $#
i.e. there are files with arbitrary stems, then -foo-, then an integer, followed by .out. Each file depends on the one with the same name, with integer one smaller.
For instance, if the file blah/bleh-foo-1.out exists, then
make blah/bleh-foo-2.out
would work.
I could do this with multiple stems if there were such a thing... what's another way to do this sort of thing in (gnu) make?
There is no easy way to do something like this. You basically have two options: you can use auto-generated makefiles, or you can use $(eval ...). To me auto-generated makefiles are easier, so here's a solution:
SOURCELIST = blah/bleh-foo-1.out
all:
-include generated.mk
generated.mk: Makefile
for f in $(SOURCELIST); do \
n=`echo "$$f" | sed -n 's/.*-\([0-9]*\)\.out$/\1/p'`; \
echo "$${f%-foo-[0-9]*.out}-foo-`expr $$n + 1`.out: $$f ; cat $$< > $$#"; \
done > $#
I've got this makefile:
ALL = ../lib/Mo.pm \
../lib/Mo/builder.pm \
../lib/Mo/default.pm \
../lib/Mo/has.pm \
all: $(ALL)
$(ALL): Mo.pm compress.pl Makefile
perl compress.pl $(#:../lib/%=%) > $#
What it's meant to do is something like this:
$ make -n
perl compress.pl Mo.pm > ../lib/Mo.pm
perl compress.pl Mo/builder.pm > ../lib/Mo/builder.pm
perl compress.pl Mo/default.pm > ../lib/Mo/default.pm
perl compress.pl Mo/has.pm > ../lib/Mo/has.pm
However with dmake on Windows this happens:
d:\mo-pm\src>dmake -n
perl compress.pl ..\lib\Mo.pm > ..\lib\Mo.pm
perl compress.pl ..\lib\Mo\builder.pm > ..\lib\Mo\builder.pm
perl compress.pl ..\lib\Mo\default.pm > ..\lib\Mo\default.pm
perl compress.pl ..\lib\Mo\has.pm > ..\lib\Mo\has.pm
I've been trying out various combinations of s/// and subst to make it work in dmake, and found out that it wants the path to have \s, which means a double substitution against both variants of the path (../lib/ and ..\lib) could work, but i can't figure out how to make it work for both make variants.
Any ideas or other ways to do this?
It's not only that the dir separator chars are different for both versions, moreover the dmake syntax seems to be deliberately designed to be incompatible with GNU make. The only part of the syntax that is actually compatible is pattern substitution, so this is the way to go:
all: $(ALL)
$(ALL) : Makefile compress.pl
../lib/%.pm : %.pm
perl compress.pl $< > $#
dmake actually substitutes the / for directory separator chars for you here. I've tested this Makefile with an echo instead, and it writes to the right directory.
Explanation: The pattern rules define rules for a particular file to be re-made when it matches a regular expression (the ../lib/%.pm part) and a prerequisite of a similar name is found (%.pm). The % in the prerequisite is replaced by the matching part of the % in the target. The extra rule with Makefile and compress.pl is needed because dmake doesn't like extra prerequisites in a pattern rule. As usual, $< and $# are make's special variables for source and target file.
So, the core difference is that your original rule said "the files named in this list can be made with the following rule), while the pattern rule says "any file looking like ../lib/%.pm can be made from a matching file in the current directory" and then gives a list of pm files to make.
Pattern rules are actually quite powerful, useful to know. Unfortunately, some makes don't know them, only the older suffix rules.
Further details of what's going on can be obtained by running
make -rdn