Preserving order of prerequisites in $^ in GNU make - makefile

Given this makefile
.SUFFIXES: .mmd .tmp .html
a.html : h.tmp a.tmp
b.html : h.tmp b.tmp
c.html : h.tmp c.tmp C.tmp
.tmp.html:
cat $^ > $#
.mmd.tmp:
Markdown.pl $< > $#
where h.mmd is a header to be inserted at the start of each html file.
The command make ?.html produces this
$ touch h.mmd
$ make ?.html
Markdown.pl h.mmd > h.tmp
cat a.tmp h.tmp > a.html
cat b.tmp h.tmp > b.html
cat c.tmp h.tmp C.tmp > c.html
The prerequisites have been sorted alphabetically. Can I preserve the order specified in the dependency lines so that the cat command includes each part in the specified order?

It doesn't have anything to do with alphabetical order or sorting. The prerequisites are not sorted and the value of $^ is not rearranged, with one exception:
In all implicit rules the implicit dependency is always the first element in the prerequisite list, regardless of whether you added it later as an explicit prerequisite in a different location.
It might be simpler to see if you convert your suffix rule into a pattern rule (but both work the same): A suffix rule like:
.tmp.html: ; cmd
is the same thing as a pattern rule like:
%.html: %.tmp ; cmd
So if you have:
%.html: %.tmp ; #echo $^
c.html : d.tmp b.tmp c.tmp a.tmp
because the pattern match for a target c.html is c, the matching prerequisite c.tmp will always be the first prerequisite even though they're listed in different order in the explicit prerequisites list. So the output of this will be:
c.tmp d.tmp b.dmp a.tmp
Note: not sorted, but the matching prerequisite appears first.
There is no way to "turn this off". The only solution, as suggested by #RedGrittyBrick, is to not list the prerequisite pattern at all. You can use their idea of:
%.html: ; #echo $^
c.html : d.tmp b.tmp c.tmp a.tmp
Or continue to use a suffix rule like:
.html: ; #echo $^
c.html : d.tmp b.tmp c.tmp a.tmp
and both will give the same result:
d.tmp b.tmp c.tmp a.tmp

I don't properly understand this but one way that worked for me was to make a one-line change to replace the suffix rule .tmp.html: with a pattern rule %.html:
.SUFFIXES: .mmd .tmp .html
a.html : h.tmp a.tmp
b.html : h.tmp b.tmp
c.html : h.tmp c.tmp C.tmp
%.html:
cat $^ > $#
.mmd.tmp:
Markdown.pl $< > $#
which preserves order
$ touch h.mmd
$ make ?.html
Markdown.pl h.mmd > h.tmp
cat h.tmp a.tmp > a.html
cat h.tmp b.tmp > b.html
cat h.tmp c.tmp C.tmp > c.html
So that is an answer, albeit incomplete because ...
What I understand:
A target can have multiple rules.
$^ is the combined set of all prerequisites from all rules for a target.
What I don't understand:
Why this affects the order of the elements of $^ in the same command.

Related

use a makefile for processing files according two Suffix Rules

I have a docroot folder containing source files that need to built
.usp -> .so
.htt -> .html
Currently my makefile has the following :
.SUFFIXES: .usp .htt
SOURCES = $(wildcard docroot/*.usp) $(wildcard docroot/*.htt)
OBJECTS = $(SOURCES:.usp=.so) $(SOURCES:.htt=.html)
all : ${OBJECTS}
.PHONY : all
%.usp: %.so
usp_compile_incl.sh -i ~/Projects/Concise-ILE/include $<
%.htt: %.html
gpp -I~/Projects/Concise-ILE/include -C $< -o $#
.PHONY: clean
clean:
rm -f docroot/*.so docroot/*.html
make: *** No rule to make target 'docroot/fortune.so', needed by 'all'. Stop.
SOLUTION as per sauerburger
.SUFFIXES: .usp .htt
SOURCES_USP = $(wildcard docroot/*.usp)
SOURCES_HTT = $(wildcard docroot/*.htt)
OBJECTS = $(SOURCES_USP:.usp=.so) $(SOURCES_HTT:.htt=.html)
all : ${OBJECTS}
.PHONY : all
%.so: %.usp
usp_compile_incl.sh -i ~/Projects/Concise-ILE/include $<
%.html: %.htt
gpp -I~/Projects/Concise-ILE/include -C $< -o $#
The build rules for .so and .html are the wrong way round. This should work:
%.so: %.usp
usp_compile_incl.sh -i ~/Projects/Concise-ILE/include $<
%.html: %.htt
gpp -I~/Projects/Concise-ILE/include -C $< -o $#
The syntax of rules is TARGET: DEPENDENCIES.
You should also split the sources variable
SOURCES_USP = $(wildcard docroot/*.usp)
SOURCES_HTT = $(wildcard docroot/*.htt)
OBJECTS = $(SOURCES_USP:.usp=.so) $(SOURCES_HTT:.htt=.html)
Otherwise you end up with a mixed objects list. The first replacement would also include all *.htt files, and the second would include all *.ups files.

How do you do pattern rules with arithmetic in Makefile?

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

Targets and dependencies in Makefiles compilation

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) ...
...

Make Target Name From Another

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.

Makefile: using variable with computed name as prerequisite

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 $^ > $#

Resources