GNU Make pattern rule depending on non-pattern file - makefile

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

Related

Makefile: Pattern rule that can ignore directories

I am trying to have a Makefile rule that can generate an object file from a source file in a directory that is specified explicitly.
exe: foo.o bar.o
foo.o: path/to/foo.c
%.o: %.c
echo Making $# from $<
This example will find it needs to make "exe", then search to make "foo.o". The "foo.o" search will try pattern rules with stem "foo" and fail to use the rule because "foo.c" doesn't exist. I want to find a way to have it see that "foo.o" can be compiled from "path/to/foo.c" using the pattern rule.
In my case it doesn't make sense for me to have the rule be "%.o: path/to/%.c" because the path should be specified for each target that needs the source to be located in another directory.
The pattern rule works for "bar.o" being made from "bar.c" within the same directory and I want to keep that working.
The solution I am going with for now is:
define c-to-o-command
echo Making $# from $<
endef
exe: foo.o bar.o
foo.o: path/to/foo.c
$(c-to-o-command)
%.o: %.c
$(c-to-o-command)
This has a drawback that the command for the pattern rule is not visible in the Makefile at the same place. It also will need to be expanded for other pattern rules that may need to have this "out of path" dependency.

How to set a Makefile target depend on pattern prerequisites?

I have a chain of pattern dependencies in a makefile, and in the end they should come together in one file, e.g.: *.x -> *.y -> onefile.z
So I made the files like this:
$ touch a.x b.x
and the rules:
%.y: %.x some-other-script
touch $#
onefile.z: %.y second-other-script
touch $#
This rule does not work:
$ make onefile.z
make: *** No rule to make target '%.y', needed by 'onefile.z'. Stop.
Using a wildcard:
%.y: %.x some-other-script
touch $#
z: $(wildcard *.y) second-other-script
touch $#
This does not work either: it sees there are no *.y files and proceeds making onefile.z skipping the first rule.
$ make onefile.z
touch onefile.z
$ ls
a.x b.x onefile.z Makefile
I probably could merge two rules into one, but in the real application, there are more steps, and some are making requests over HTTP and take much time, and in fact should not be repeated without a reason.
Is there a way to make such a dependency?
onefile.z: %.y second-other-script is a regular rule, not a pattern rule or a static pattern rule, so the % is interpreted literally. Even if it were a pattern rule, how is make supposed to infer what the stem is supposed to match?
$(wildcard *.y) tells make to find all the files that match *.y, but of course there are none yet so it returns an empty string.
The following should work, if I've understood your question correctly:
xfiles := $(wildcard *.x)
yfiles := $(xfiles:.x=.y)
%.y: %.x some-other-script
touch $#
onefile.z: $(yfiles) second-other-script
touch $#
See the Gnu Make documentation on
Wildcard functions $(wildcard ...)
Substitution functions $(foo:from=to)

Why GNU Make's secondary expansion does not work with pattern rules for dependencies?

Consider this makefile:
%: %.c
#echo making $#
#touch $#
.SECONDEXPANSION:
%.pid: $$(basename $$#)
$(<D)/$(<F) --pidfile=$<.pid
Here, the first rule builds a program and second rule starts it, producing a pid-file. Note: I know that secondary expansion is unnecessary in this example; the real makefile is more complex and I really need secondary expansion there.
So, typing make foo.pid, I expect Make to build foo from foo.c by the first rule and then run ./foo --pidfile=foo.pid by the second one.
However, it does not seem to work:
$ make -f Makefile.test foo.pid
make: *** No rule to make target 'foo.pid'. Stop.
This somehow relates to secondary-expanded dependencies which are provided by pattern rules. If I write either
%.pid: % in the second rule (i. e. get rid of secondary-expansion), or
foo: %: %.c in the first rule (i. e. write an explicit static pattern rule),
it all suddenly works. Why? Is this a limitation of GNU Make? In my case, I'd like to avoid pre-listing all possible programs in the first rule.
I think your situation is described in section 10.5.5 Match-Anything Pattern Rules. Whay you have here is a non-terminal match-anything rule, which is not allowed to match a file name that indicates a specific type of data.
If you had let's say
%:: %.c
#echo making $#
#touch $#
it would work.

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.

Why does Make ignore my wildcard rule?

Why doesn't Make link to foo.o?
$ ls
foo.c foo_test.c Makefile
$ cat Makefile
.PHONY: test
test: foo_test
%_test: %_test.o foo.o
$ make
cc foo_test.c -o foo_test
Pattern rules MUST have a recipe associated with them. Any pattern rule without a recipe tells GNU make to delete that pattern rule. So, your line:
%_test: %_test.o foo.o
does nothing except delete the non-existent pattern rule to build %_test from %_test.o. You need to create a recipe if you want it to take effect:
%_test: %_test.o foo.o
$(CC) -o $# $(LIBS) $^
or whatever. However, this is completely not necessary for your example. You don't need any rule at all for that, just write:
foo_test: foo_test.o foo.o
and let make's built-in rules handle it.

Resources