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
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 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 came across a makefile which contained the below code. However i am not able to understand the first line $(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp, what are the dependencies exactly?
$(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
#$(PRINTF) "$(MESG_COLOR)Compiling: $(NO_COLOR) $(FILE_COLOR) %25s$(NO_COLOR)" "$(notdir $<)"
#$(CC) $(CPPFLAGS) -c $< -o $# -MD 2> temp.log || touch temp.err
#if test -e temp.err; \
then $(PRINTF) $(ERR_FMT) $(ERR_STRING) && $(CAT) temp.log; \
elif test -s temp.log; \
then $(PRINTF) $(WARN_FMT) $(WARN_STRING) && $(CAT) temp.log; \
else printf "${OK_COLOR}%30s\n${NO_COLOR}" "[OK]"; \
fi;
#$(RM) -f temp.log temp.err
This is a static pattern rule. It can be used to build any of the targets in $(OBJS), and constructs the names of the prerequisite(s) accordingly.
SRCDIR = sources
OBJDIR = objects
OBJS = objects/foo.o objects/bar.o objects/baz.o
$(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
#echo the target is $#, the prereq is $<
If you call this rule with "make objects/foo.o", Make will 1) recognize that this rule applies, since the desired target is a member of the rule's list of targets, 2) match the target name "objects/foo.o" against the target pattern "objects/%.o" to obtain the stem "foo", 3) put that stem into the prereq pattern "sources/%.cpp" to obtain the name of the prereq, "sources/foo.cpp".
This is a static pattern rule. Basically it means "for each word in $(OBJS), define an explicit rule where the target pattern $(OBJDIR)/%.o matches the word and the prerequisite is the expansion of the pattern $(SRCDIR)/%.cpp".
So if OBJS is equal to $(OBJDIR)/foo.o $(OBJDIR)/bar.o $(OBJDIR)/baz.o, then the static pattern rule is equivalent to writing this:
$(OBJDIR)/foo.o : $(SRCDIR)/foo.cpp
#$(PRINTF) ...
...
$(OBJDIR)/bar.o : $(SRCDIR)/bar.cpp
#$(PRINTF) ...
...
$(OBJDIR)/baz.o : $(SRCDIR)/baz.cpp
#$(PRINTF) ...
...
Have problem in dynamically "create" target name with .SECONDEXPANSION:
Small Makefile to reproduce problem:
CONFIGS = test1 test2 test3
.SECONDEXPANSION:
all: $(CONFIGS)
OBJECTS=$$(CFG_NAME)_OBJECTS
$(CONFIGS) : CFG_NAME=$#
$(CONFIGS) : $(OBJECTS)
#echo $(CFG_NAME) $# from $^
$(OBJECTS):
#echo OBJECTS $# from $^
#echo DO IT
It says: "No rule to make target 'test1_OBJECTS'.
How can I solve this problem?
EDIT: CHANGE OF THE ANSWER
Thank you much for the answer. It was the simple variant for my task.
So I try to answer in another way.
CONFIGS = test1 test2 test3
PLATFORMS = x86 ppc arm
#will be test1x86 test2x86 ... test1ppc ... test3arm,
#so it is long way to enumarate all variants
VARIANTS = $(foreach c, $(CONFIGS), $(foreach p, $(PLATFORMS), $(c)$(p)))
#C FILE LIST
CFILES:=$(shell /bin/find -name "*.c")
.SECONDEXPANSION:
all: $(VARIANTS)
#More Comlex Rule
#Want to corresponding objects be in bins/test1x86/
OBJECTS:=$(CFILES:%.c=bins/$$(CFGNAME)%.o)
$(CONFIGS) : CFG_NAME=$#
$(CONFIGS) : $(OBJECTS)
#echo $(CFG_NAME) $# from $^
#More complex prerequisites
#I understand that $$(CFGNAME) will be resolve incorrect.
#For each *.c file in subdir I would have object in corresponding path.
#For example, '1/2/3/test.c' will use for generate
#object file 'bins/test1x86/1/2/3/test.o',
#when I call 'make testx86' or 'make all' (it will build all VARIANTS),
#in 'bins/test1x86/1/2/3/'.
#So what have I do?
$(OBJECTS): bins/$$(CFGNAME)_OBJECTS/%o : %.c
#echo OBJECTS $# from $^
#echo DO IT
So, I would like to avoid recursive make calls. Can you help me?
Thank you.
You have a rule for $(OBJECTS), but that target expands to $(CFG_NAME)_OBJECTS, which is not expanded again (ever), so it can't match anything. Try this instead:
test1_OBJECTS test2_OBJECTS test3_OBJECTS:
#echo OBJECTS $# from $^
#echo DO IT
Or better:
OBJECT_SETS = $(addsuffix _OBJECTS, $(CONFIGS))
$(OBJECT_SETS):
#echo OBJECTS $# from $^
#echo DO IT
(And I'm sure you realize your example doesn't really need SECONDEXPANSION at all.)
EDIT:
That should be a separate question, but I'll try to answer it here. (And please use punctuation in the comments in your makefile; they are very difficult to understand.)
There is more than one solution to your problem. Here is one:
vpath %.c $(dir $(CFILES))
CFILES := $(notdir $(CFILES))
I've gotcha it.
CONFIGS = test1 test2 test3
PLATFORMS = p1 p2
#Will be testp1 test1p2 .. test3p2
VARIANTS = $(foreach c, $(CONFIGS), $(foreach p, $(PLATFORMS), $(c)$(p)))
.SECONDEXPANSION:
#.c files list in all subfolders
cfiles = $(shell /bin/find -name "*.c")
#objects for these .c files for custom VARIANT
objects = $(patsubst %.c,%.o,$(addprefix bins/$1/,$(cfiles)))
#Get .c source for object (e.g. bins/test1p1/tests/main_test.o => tests/main_test.c)
get_src=$(shell echo $1 | sed 's/[^\/]*\/[^\/]*\/\(.*\)/\1.c/')
#Build All Variants
all: $(VARIANTS)
#Build objects. Target list contains all objects for all variants.
#Prerequisites get .c sources from the pattern rule for targets
$(foreach v, $(VARIANTS), $(call objects,$(v))) : %.o : $$(call get_src,$$*)
#echo OBJECTS $# FROM $^
#Variants rule, depends on objects
$(VARIANTS): $(call objects,$$#)
#echo $# from $^
Thank you, Beta. You only have tried. :)
Maybe anyone have style or efficiency suggestions.
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 $^ > $#