GNU Make: phony target doesn't seem to be matching pattern - makefile

I have this minimal Makefile:
.PHONY: foo.bar
%.bar:
echo $*
I run $ make foo.bar and I expect it to match the %.bar pattern, populate the stem $* with "foo", and echo "foo" all the time because foo.bar is a phony target. However, the output I get is
make: Nothing to be done for 'foo.bar'.
Am I missing something here?
EDIT:
I forgot to mention that removing the .PHONY line performs the expected behavior where it echo's "foo", and also making it an explicit target "foo.bar" without the pattern matching. Both of which make perfect sense since in the former, the file, foo.bar, doesn't exist and in the latter, well, it's just explicit.
EDIT:
This might be a duplicate of this actually: When declaring the pattern rule as PHONY, it is not triggered. Here is something that works:
.PHONY: foo.bar
foo.bar: %.bar:
echo $*
For whatever reason the target/dependency line is more like target/(dependency|target)/dependency. Can someone explain this or point me to the documentation?

From the make manual section on .PHONY targets:
The implicit rule search (see Implicit Rules) is skipped for .PHONY targets.
meaning your rule for %.bar: is simply ignored.
Getting rid of .PHONY of course works as expected; using the rule foo.bar: %.bar: works because static pattern rules are not implicit rules and so won't be ignored for .PHONY targets.

Related

Patterns in makefile targets

Makefile:
%_file:
touch $#
foo_%: %_file
bar: foo_bar
Results:
>make foo_bar
make: *** No rule to make target 'foo_bar'. Stop.
>make bar
make: *** No rule to make target 'foo_bar', needed by 'bar'. Stop.
I have intentionally omitted adding .PHONY rules because I know the prerequisites of phony rules are always interpreted as literals. I do not see any reason that make foo_bar or make bar should not run without error. What am I missing?
You have a dependency between foo_% and %_file, but you have defined any rules on how to build foo_%. So when you run:
make foo_bar
Make figures out it first needs to build bar_file, but can't find any rules for building foo_bar. If you were to write instead:
%_file:
touch $#
foo_%: %_file
cp $< $#
bar: foo_bar
Then running make foo_bar would result in:
touch bar_file
cp bar_file foo_bar
rm bar_file
To clarify #larsks answer, the GNU make manual says:
You can cancel a built-in implicit rule by defining a pattern rule with the same target and prerequisites, but no recipe.
So your pattern rule:
foo_%: %_file
does not create a pattern rule, it deletes a (non-existent anyway) pattern rule.
If you want a pattern rule it must have a recipe.

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.

Match anything pattern rule with dependency

File Name: Makefile.mk
%: foo
#echo %: $# with foo
foo:
#echo foo
Run
$ make -f Makefile.mk test
Output:
foo
%: Makefile.mk with foo
%: test with foo
I am running this in GNU Make 3.81 version.
I Don't understand, why file name also printed(%: Makefile.mk with foo).
Can some one please explain me?
This is because of how makefiles are remade. That is to say that
Sometimes makefiles can be remade from other files
and
If a makefile can be remade from other files, you probably want make to get an up-to-date version of the makefile to read in
so
after reading in all makefiles, make will consider each as a goal target and attempt to update it.
Which then matches against your match-anything rule and triggers the way you see.
If you add an explicit Makefile.mk: ; target to your makefile it will override the match-anything target and prevent this.

Complex pattern rule in Makefile

I have the following makefile I use to generate files from some templates, the generated files have two possible extensions:
%.tex: %.tex*_tpl
./generate $#_tpl -o $#
%.xml: %.xml*_tpl
./generate $#_tpl -o $#
The dependency list will here match things like a.tex_tpl, a.tex-subpart1_tpl, a.tex-subpart2_tpl.
While this works, is there a way to avoid repetition? For example by matching *.{tex,xml} in the rule name and use the whole matched name in the dependency list? Something that would look like that:
%.{tex,xml}: $#_tpl
./generate $< -o $#
(Though I know %.{tex,xml} is not a valid rule name and you can't use $# in the dependency list)
Or any other (cleaner?) way.
Seems to me this does what you are looking for:
#
# I've assumed that files of the form:
#
# a.xml_tpl
# b.tex_tpl
#
# determine what targets you want to build
#
TARGETS:=$(patsubst %_tpl,%,$(wildcard *.xml_tpl *.tex_tpl))
.PHONY: all
all: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): %: $$(wildcard %*_tpl)
./generate $^ -o $#
The key is to use .SECONDEXPANSION to allow $$(wildcard %*_tpl) to be evaluated in a second expansion phase. The double $ is not a typo, by the way; it protects the expression from being evaluated at the time of the first expansion.
If I populate a directory with these files:
a.tex-subpart1_tpl
a.tex_tpl
a.xml-subpart1_tpl
a.xml-subpart2_tpl
a.xml_tpl
and run make -n, I get this on the console:
./generate a.xml_tpl a.xml-subpart1_tpl a.xml-subpart2_tpl -o a.xml
./generate a.tex_tpl a.tex-subpart1_tpl -o a.tex
Why the Second Expansion?
Without the second expansion, you'd have to have $(wildcard %*_tpl) in the dependency because with the $$ the wildcard function would never execute. Instead, make would treat $$(wildcard..) literally as the dependency, which is obviously wrong.
Ok, so $(wildcard %*_tpl) would be evaluated at the time make first runs across that line (this is the "first expansion"). At that time % has no value yet so wildcard would roughly be doing something like what would be ls %*_tpl at the command line.
For reasons of speed, make does not by default give you the opportunity to do any evaluation later than during the first expansion. If you want a later opportunity you have to specify .SECONDEXPANSION, which turns on the second expansion processing. Make still performs the firts expansion as usual. This is why you need to have $$(wildcard: it is transformed to $(wildcard during the first expansion. At the time of the second expansion make sees $(wildcard %*_tpl), replaces % with the actual stem and then executes the wildcard function with the actual stem rather than with a literal %.
Why $(TARGETS) in the Pattern Rule?
The pattern rule could be written:
%: $$(wildcard %*_tpl)
./generate $^ -o $#
without $(TARGETS). However, this rule would do nothing, as it would be a "match-anything rule". Basically, if make took such a rule at face value, then the computation cost would be significant, and most likely it is not the case that the author of the Makefile really means to apply this rule to any file whatsoever. So such a rule comes with restrictions, which in the Makefile here make it useless.
Adding $(TARGETS) makes it into a static pattern rule, which is not a match-anything rule. The addition of $(TARGETS) in front of the target pattern tells make that the rule applies only to these targets, and nothing else.

Resources