Makefile with multiples rules sharing same recipe - makefile

I'd like to know if it's possible to write a Makefile with several rules, each one defining its own prerequisites and executing all of them the same recipe without duplicating the recipe. Example:
TARGETS= file1 file2 file3
all: $(TARGETS)
file1: dep1 dep2
file2: dep2 dep3 dep4
file3: dep2 dep1
cat $^ > $#
Thanks!

Yes, it is written in a rather obvious way:
TARGETS= file1 file2 file3
all: $(TARGETS)
file1: dep1 dep2
file2: dep2 dep3 dep4
file3: dep2 dep1
$(TARGETS):
cat $^ > $#
UPD.
Just to clarify.
Generic make rule looks like this:
targets... : prerequisites...
recipe
...
Any part of the rule can be omitted. Without the recipe, one can populate the list of prerequisites anywhere in the makefile, a target can occur in the left hand side of multiple rule statements.
For example, the following is equivalent to the example above (well, assuming that the Makefile is properly designed so that the order of prerequisites does not matter):
file1 file3 : dep1
file1 file2 file3 : dep2
file2 : dep3 dep4
Unlike listing prerequisites, there can be at most one explicit recipe for each target. Inside the recipe you can use automatic variables to get the target name, the list of prerequisites, etc.
UPD. 2
As #Calmarius mentions in comments this doesn't apply to pattern rules, like %.txt: %.foo.
Multiple patterns within targets mean that the rule produces all these targets at once.
This pattern rule has two targets:
%.tab.c %.tab.h: %.y
bison -d $<
This tells make that the recipe bison -d x.y will make both x.tab.c and x.tab.h.
If the file foo depends on
the files parse.tab.o and scan.o and the file scan.o depends on the
file parse.tab.h, when parse.y is changed, the recipe bison -d parse.y
will be executed only once, and the prerequisites of both
parse.tab.o and scan.o will be satisfied.
One may define multiple prerequisites in a pattern rule though (that is, provided that its targets contain a % stem, otherwise it would be a regular rule).

Related

GNU Make pattern rule depending on non-pattern file

In GNU Make, what exactly are the semantics of a pattern rule that depends on a non-pattern file?
I have the following snippet in a Makefile. When foo.a exists, GNU Make doesn't seem to create foo.b when make foo.b is called.
.SUFFIXES:
%.b: move_a_to_b.artifact
move_a_to_b.artifact:
mv foo.a foo.b
touch move_a_to_b.artifact
The following, however, works fine and moves the file from foo.a to foo.b.
.SUFFXIES:
%.b: %.a
mv $< $#
As does this, with a pattern rule depending on a pattern rule
.SUFFIXES:
%.b: %.intermediate
mv $< $#
%.intermediate: %.a
mv $< $#
It doesn't have anything to do with pattern rules depending on non-patterns. That's fine and it has the expected semantics: for any file ending in .b if it's out of date with respect to the file move_a_to_b.artifact then the recipe will be run.
Your issue is that you're not defining a pattern rule, you're deleting a pattern rule. A pattern rule must always have a recipe. A pattern rule without a recipe deletes the pattern rule. See Canceling Pattern Rules.
You have to add a recipe, then it will do something:
%.b : move_a_to_b.artifact
#echo do something to create $#

Mutex in GNU Make?

Two targets are satisfied by one rule like this:
foo.o foo.h :
build_foo # this makes both foo.o and foo.h
Later, some targets need one, others need both:
bar : foo.o
build_bar
baz : foo.h
build_baz
qux : bar baz
build qux
How do I prevent the recipe from running twice when make is invoked with -jN?
I avoid pattern rules when I can. In your case you will find that after the recipe is run, one of foo.o and foo.h is newer than the other (just use $ ls --full-time on them).
Let's assume your recipe creates foo.h and then goes on to create foo.o. That suggests:
foo.o: foo.h ; # Empty recipe
foo.h: prereq1 prereq2 ...
build_foo
So now if foo.o is a prequisite in another rule, make will build foo.h first, creating foo.o as a side-effect. Then it will run foo.o's recipe. Job done.
If you feel uneasy,
you could add a simple assert that foo.o is indeed newer than foo.h
foo.o: foo.h
test $# -nt $<
For more about this topic, check out the automake (not make) chapter titled Handling Tools that Produce Many Outputs
You do that by teaching make that the recipe builds both targets at the same time.
Your target:
foo.o foo.h :
build_foo # this makes both foo.o and foo.h
is seen by make the same as these targets:
foo.o :
build_foo # this makes both foo.o and foo.h
foo.h :
build_foo # this makes both foo.o and foo.h
which is the problem.
What you need is a pattern rule that specifies both target files.
%.o %.h :
build_foo # this makes both foo.o and foo.h
which works for this (but you really want to give it sane prerequisites) because of how GNU make handles pattern rules when they specify multiple targets:
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. When searching for a pattern rule to match a target, the target patterns of a rule other than the one that matches the target in need of a rule are incidental: make worries only about giving a recipe and prerequisites to the file presently in question. However, when this file’s recipe is run, the other targets are marked as having been updated themselves.

GNU Makefile - Pattern rule with multiple targets with one dependency ignores all targets but the first

I want to make a language depend target. In Particular: I have one source-file and I want to create different Objects which where add to the corresponding language folder. That single source file will differ in the C-Flags, the compiler will get. As long as I used it in a static way, it works quite fine.
de/info.o en/info.o es/info.o : info.c
$(ECHO) (DEP) $< for $#
Now I thought, it would be great if it is a bit more dynamic, in case i'll add a new language depending file. So I used a wildcard as followed:
de/%.o en/%.o es/%.o : %.c
$(ECHO) (DEP) $< for $#
But now it just make the first target and ignores the rest. The Make-Debug prints the following thing:
Successfully remade target file `de/info.o'.
Considering target file `en/info.o'.
File `en/info.o' was considered already.
Just in case: No, the objects do not exist. So there is no target, but an existing dependencie, so make should execute the rules.
EDIT: Found a solution for that Problem.
define FOO
$(1)/%.o : %.c
$(ECHO) $$< for $(1)
endef
$(foreach lang,$(LANGUAGE_LIST), $(eval $(call FOO,$(lang))))
Inspired by: http://www.gnu.org/software/make/manual/make.html#Eval-Function
Pattern rules work differently than implicit rules. While an implicit rule such as
a b c: d
command
is equivalent to the longer notation
a: d
command
b: d
command
c: d
command
this does NOT hold for pattern rules. Pattern rules with multiple targets are explicitly required to build all of their targets in a single invocation of command. Thus you would have to write
$ cat GNUmakefile
all: de/x.o en/x.o es/x.o
de/%.o: %.c
#echo $# from $<
en/%.o: %.c
#echo $# from $<
es/%.o: %.c
#echo $# from $<
$ gmake
de/x.o from x.c
en/x.o from x.c
es/x.o from x.c
The relevant documentation is found in 10.5.1 Introduction to Pattern Rules of the GNU make manual:
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. When searching for a pattern rule to match a target, the target patterns of a rule other than the one that matches the target in need of a rule are incidental: make worries only about giving a recipe and prerequisites to the file presently in question. However, when this file’s recipe is run, the other targets are marked as having been updated themselves.

Simple inference rule in makefile

I'm currently learning how to use makefiles. But I'm struggling with % pattern rules. I've boiled down my failing makefile to this very simple example:
I fill an empty directory with:
echo aaa > a.in && echo bbb > b.in
A first makefile like this works very well:
a.out : a.in
cat $< > $#
as
make && echo *.out && cat *.out
returns
cat a.in > a.out
a.out
aaa
but when I try to use a pattern rule modifying the makefile as follows:
%.out : %.in
cat $< > $#
make then returns me:
make: *** No targets. Stop.
It seems like a very simple problem but I can't get to what I am missing...
If you have a makefile with no targets lists (only patterns), and you just type make, then you haven't told make that it should build anything specific, so it won't do anything.
A pattern rule doesn't mean "go find all the files that match this pattern and build them". A pattern rule tells make "if you need to find a way to build a file that matches this target pattern, then here's how you do it".
If you type make a.out so make knows that you want to build a target a.out, then make will use your pattern rule to build it.
Alternatively, you can add the target to your makefile, something like this:
.PHONY: all
all: a.out
%.out : %.in
cat $< > $#

How does % in Makefiles work?

I am trying to understand how makefiles work. If I try the following
1.out : 1.inp
cat 1.inp
it, works as expected (if 1.inp is newer as 1.out or if 1.out does not exist, the content of 1.inp is printed).
Then I need to do the following:
cat 1.inp
cat 2.inp
cat 3.inp
I thought that for that I can use
%.out : %.inp
cat $<
but it does not work. Can anybody please explain to me the use of %?
In your first makefile:
1.out: 1.inp
cat 1.inp
1.out is a target with a prerequisite 1.inp and a command cat 1.inp. This constitutes a rule for
making 1.out and if you run the makefile, specifying either no explicit target or the target 1.out, the
rule will be executed.
In your second makefile:
%.out: %.inp
cat $<
you have only expressed a pattern rule for making a target of the form something.out from a prerequisite of the form something.inp You have not specified any actual targets that the makefile can make.
You can specify 1.out as a target with a makefile like this:
%.out: %.inp
cat $<
1.out:
In that case 1.inp will be cat-ed when 1.inp is newer that 1.out
Or you can specify a phony target, e.g. all, that has prerequisite targets 1.out, 2.out, 3.out in a makefile like this:
.PHONY: all
%.out: %.inp
cat $<
all: 1.out 2.out 3.out
In this case each of 1.inp, 2.inp and 3.inp will be cat-ed when it is newer than the corresponding .out file.
Whenever make discovers that it has to make a target of the form something.out, it will recognize that the pattern rule is applicable and will execute the matching instance of the pattern rule.

Resources