In Make it's possible to compute variable names in runtime using double-evaluation, like $($(var)).
I'm interested if it's possible somehow to make this work:
one.js_DEPS=a b
two.js_DEPS=c b
all: one.js two.js
%.js: $(%.js_DEPS)
cat $^ > $#
I can make this work by declaring two rules with explicit dependencies, like this:
one.js: $(one.js_DEPS)
But this seems a bit anti-DRY. So I'm wondering if I miss something because make doesn't seem to understand me. I use GNU Make 3.81.
% and implicit rules are somewhat second-class citizens in make, since variable expansion seems to happen before implicit rule expansion. So, in your above Makefile, $(%.js_DEPS) is expanded to the empty string before % is substituted.
Alternative:
%.js: %.js_DEPS
cat $^ > $#
%.js_DEPS :
cat $^ > $#
.INTERMEDIATE: one.js_DEPS two.js_DEPS
or simply:
one.js : a b
two.js : c d
%.js :
cat $^ > $#
This could be done using Secondary Expansion.
JS := one.js two.js
all: $(JS)
.SECONDEXPANSION:
one.js_DEPS := a b
two.js_DEPS := c b
$(JS) : $$($$(#F)_DEPS)
cat $^ > $#
But in fact, the goal can be achieved much simply, without using any GNU Make extensions, as thiton has suggested in his answer:
all: one.js two.js
one.js : a b
two.js : c b
%.js :
cat $^ > $#
Related
We are supporting 32 bit and 64 bit build in our workflow.For that We have multiple rules in makefiles which are separate for 32-bit and 64-bit. Let me show pair of rules which are same except for the string “32” vs “64” .
Makefile Snippet:-
$(TGTDIR32)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
$(TGTDIR64)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
If you notice, We have targets with same except for the string “32” vs “64”, i want to replace them by single rule/definition. Because we have hundreds of rules like above in our infrastructure code.
Do we have any simplified way in GNUmake to do that?
Thanks in Advance!
Targets which have the same prerequisites and recipe can simply be combined, like so:
$(TGTDIR32)/logdir/set_user.c $(TGTDIR64)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
or more generally:
THESE_TARGETS := $(TGTDIR32)/logdir/set_user.c $(TGTDIR64)/logdir/set_user.c # More...?
...
$(THESE_TARGETS): $(CURDIR)/slv/set_user.c
$(file_transfer)
If Make decides that any member of $(THESE_TARGETS) is out-of-date with respect to the prerequisites, then it will run the recipe for that target.
This makefile:
.PHONY: all clean
all: a b c
a: d e
touch $#
b: d e
touch $#
c: d e
touch $#
d:
touch $#
e:
touch $#
clean:
$(RM) a b c d e
is equivalent to this one:
.PHONY: all clean
all: a b c
a b c: d e
touch $#
d e:
touch $#
clean:
$(RM) a b c d e
Later
There are some static pattern rules...
The same applies. This makefile with static pattern rules:
.PHONY: default clean
default: a.k b.k
a.k: %.k: %.j
cp -f $< $#
b.k: %.k: %.j
cp -f $< $#
a.j:
touch $#
b.j:
touch $#
clean:
$(RM) a.k b.k a.j b.j
is equivalent to this one:
.PHONY: default clean
JS := a.j b.j
KS := $(JS:.j=.k)
default: $(KS)
$(KS): %.k: %.j
cp -f $< $#
$(JS):
touch $#
clean:
$(RM) $(JS) $(KS)
In my opinion this is an appropriate place to use recursive make, at least for the top-level build.
In this situation you could do something like this:
TGTDIR64 = ...
TGTDIR32 = ...
.PHONY: all all32 all64 build
all: all32 all64
all32:
$(MAKE) TGTDIR=$(TGTDIR32) build
all64:
$(MAKE) TGTDIR=$(TGTDIR64) build
# Things below here should just use TGTDIR
build: $(TGTDIR)/b1 $(TGTDIR)/b2
$(TGTDIR)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
$(HEADERGEN_NOTSPLIT_H_COPY): $(TGTDIR)/%.h: %.h $(copy_file)
...
The two rules are semantically identical, they only use a different way to refer to a "parameterized" target. Why you don't just use one target for this
$(TGTDIR)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
and use a properly configured TGTDIR (I suspect this would be something like "xxxx_32" vs "xxxx_64")?
You could achieve this in several ways; one typical would be
ifdef choose32
TGTDIR=xxxx_32
else
TGTDIR=xxxx_64
endif
I'm writing a Makefile using static pattern rules and I want for each element of TARGETS a variable assigned to the current target name (here the stem '%').
TARGETS = a b c d
all : $(TARGETS)
$(TARGETS) : % : DIR = %
$(TARGETS) : % : %_setup build
a_setup :
code for a
b_setup :
code for b
...
build
code using "DIR = XX" previously configured
but gnumake complains about the target-specific variable DIR:
make: *** No rule to make target 'DIR', needed by 'a'
Is it possible to mix static pattern rules and variable assignation? Thanks!
According to the GNU make manual you can't do it like that. However, you can use $#. In you example you can directly assign DIR=$# but more generally you can use $# in combination with patsubst:
TARGETS = a b c d
all : $(TARGETS)
$(TARGETS) : DIR = $(patsubst %,%,$#)
$(TARGETS) : % : %_setup build
echo $#: DIR:$(DIR)
%_setup :
echo $#
build:
echo $#
I need to write a pattern rule for the following case:
There are 2 folders: A and B
Running the command python gen.py --a=A/file1.foo --b=file2.bar --c=file3.bar generates B/file1.foo
file1, file2 and file3 are different strings
Is there a way to group those filenames in some kind of a multidimensional array, so that all files are written exactly once (I'll use python syntax):
files = [["a1.foo", "a2.bar", "a3.bar"],
#...200 other groups...
["b1.foo", "b2.bar", "b3.bar"]]
and then the rule looks like this:
$(files): B/{reference 1 elem}: A/{1 elem} {2 elem} {3 elem}
python gen.py --a=A/{1 elem} --b={2 elem} --c={3 elem}
Any ideas how to archive it?
You can use standard make syntax for that:
all :
targets :=
define add_target
B/${1}: A/${1} ${2} ${3}
targets += B/${1}
endef
# Build dependencies.
$(eval $(call add_target,a1.foo,a2.bar,a3.bar))
# ...
$(eval $(call add_target,b1.foo,b2.bar,b3.bar))
# One generic rule for all ${targets}
${targets} : % :
#echo Making $# from $^
all : ${targets}
.PHONY: all
Note that these $(eval $(call add_target,...) are white-space sensitive, do not insert spaces in there.
If you would like make to create the directory for outputs automatically do:
${targets} : % : | B
B :
mkdir $#
Sometimes a little repetition isn't so bad really
targets := B/a1.foo B/b1.foo
.PHONY: all
all: $(targets)
$(targets): B/%: A/%
python gen.py --a=$< --b=$(word 2,$^) --c=$(word 3,$^)
B/a1.foo: a2.bar a3.bar
B/b1.foo: b2.bar b3.bar
I am new to make. I have a very basic Make question and have searched in vain about it.I have different arguments to be given to different prerequisites.
a b:c d
prog -i c -j d -out1 a -out2 b
I know that that $+ will list all preqs but how do I supply the arguments. I could retype a b c and d in the recipe and not use automatic variables at all but then typing needs to be done twice. A pattern rule could be made where a and b could be linked to c and d respectively but still how do I supply the arguments?
A Million Thanks
Let's try some simpler rules first:
a b c:
#echo the target is $#
(Test this with "make a" or "make b c".)
a: c d
#echo the prerequisites are $^
#echo the first prerequisite is $<
a: c d
#echo the second prerequisite is $(word 2,$^)
(Crude but effective.)
Your rule:
a b : c d
prog -i c -j d -out1 a -out2 b
is a little odd in that it can be invoked with either target (a or b) and it will do exactly the same thing. This is perfectly legal, but although Make has access to the target name with $#, it cannot easily scan the names of targets it isn't trying to build. But there's a way you can reduce the redundant typing:
TARG_1 := a
TARG_2 := b
TARGS := $(TARG_1) $(TARG_2)
$(TARGS) : c d
prog -i $< -j $(word 2,$^) -out1 $(TARG_1) -out2 $(TARG_2)
My Makefile contains the following rules:
result-n1 : inputs
foo $^
result-n2 : result-n1
hashandmash $^ > $#
result-n3 : result-n2
hashandmash $^ > $#
# ... [~ 50 more lines omitted for clarity]
result-n20 : result-n19
hashandmash $^ > $#
I would love having just one pattern rule. This would be much clearer and would avoid the hard-coded limit at 20.
But how would you do this? How do you say that result-nx depends on result-nx-1? I only see inelegant solutions (like naming my files in base 1, e.g., result-nIIIIIIII).
PS&FWIW, I use GNU Make 3.81
You cannot do that, directly. You can create a pattern rule for result-% that has no prerequisites, then you can declare the prerequisites separately:
result-n1: inputs
foo $^
result-%:
hashandmash $^ > $#
result-n2: result-n1
result-n3: result-n2
...
result-n20: result-n19