Is this a make bug? - makefile

Most likely it is not but I've been struggling with this one for an hour now:
$ cat Makefile
${FILE1}:
touch $#
a: ${FILE1}
${FILE2}: a
touch $#
$ make FILE1=foo FILE2=bar bar
touch foo
touch bar
$ ls
bar foo Makefile
$ make FILE1=foo FILE2=bar bar
touch bar
Why is the bar rule still activated?
If I change Makefile to:
${FILE1}:
touch $#
${FILE2}: ${FILE1}
touch $#
Everything works, i.e. bar is not touched again.

The target bar has a prerequisite, a. You have a rule for a, but it does not actually build a file named "a". So every time you ask Make to rebuild bar (if necessary), Make sees that the prerequisite a does not exist, and therefore it must attempt to rebuild both targets.

Related

Can a target's prerequisite without build rule have generated transitive prerequisites?

I have the following Makefile:
.PHONY: all
all: foo qux
foo: bar
cp bar foo
qux: bar
cp bar qux
-include bar.d
clean:
rm -f foo qux
which includes a generated bar.d file:
bar: baz
I'd like to be able to run the rules for foo and qux whenever bar or baz is changed.
Without surprise, it works well when I change bar, but when I change baz, I get the following message:
make: Nothing to be done for 'all'.
If I change the contents of bar.d to the following, I get the expected behaviour:
foo: baz
qux: baz
But it would be easier for me not to have to duplicate the $x: baz rule for every target that depends on bar.
Is there a solution that does not involves changing baz.d?
Since there is no recipe for bar, Make's actions are correct; yes, baz has changed, but there is no way to bring bar up to date, therefore no point in rebuilding the targets that depend on bar.
You can get the behavior you want by adding an "update" recipe to the rule:
bar: baz
#touch $#

Make extra newline in prerequisite in define recipe

I am trying to create a Makefile which uses a recipe created using the define syntax. However, I have run into a problem where Make believes that the last prerequisite has a newline appended to it, resulting in a "no rule found" error. A minimal working example is given below, the problem is triggered by trying to make the foo/bar target.
foo:
mkdir foo
define FIZZ
foo/bar: foo
touch foo/bar
endef
$(call FIZZ)
The exact error message is
make: *** No rule to make target 'foo
', needed by 'foo/bar'. Stop.
I have tried versions 4.1 and 4.2.1 of GNU Make.
Can anyone tell me what I am doing wrong (or is this a bug)?
What you are trying to do here is expand the variable FIZZ to inject the
definition of the target foo/bar (its prerequisites and recipe) into the
expanded makefile. $(call FIZZ) is not the tool for that:
$(call variable,param,param,...)
may behave surprisingly if the arguments contain embedded whitespace. You want
8.9 The eval Function,
as in:
Makefile
foo:
mkdir foo
define FIZZ
foo/bar: foo
touch foo/bar
endef
$(eval $(FIZZ))
Then you'll get:
$ make foo/bar
mkdir foo
touch foo/bar

Why does this Makefile fail to build make the final target, but all intermediate targets work fine?

Say we have the following Makefile:
.PHONY: build
build:
cd .. && make
%.hl.a.json: %.c
touch $#
%.hl.b.json: %.hl.a.json
touch $#
%.x.p.json: %.hl.b.json
touch $#
%.x.hl.a.json: %.x.p.json
touch $#
%.x.hl.b.json: %.x.hl.a.json
touch $#
.PHONY: clean
clean:
$(RM) *.json
Let us assume we have file called small.c, and that I want to build small.hl.b.json. However, running make small.hl.b.json (with GNU Make 3.81) gives me:
$ make small.x.hl.b.json
make: *** No rule to make target `small.x.hl.b.json'. Stop.
However, the Makefile works for building small.x.hl.a.json which produces
$ make small.x.hl.a.json
touch small.hl.a.json
touch small.hl.b.json
touch small.x.p.json
touch small.x.hl.a.json
rm small.x.p.json small.hl.a.json small.hl.b.json
Thus, if I run make small.x.hl.a.json first, and then make small.x.hl.b.json, then everything works.
And now it gets interesting. If I do the following:
$ make small.x.hl.a.json
touch small.hl.a.json
touch small.hl.b.json
touch small.x.p.json
touch small.x.hl.a.json
rm small.x.p.json small.hl.a.json small.hl.b.json
$ make clean
rm -f *.json
$ make small.x.hl.b.json
make: *** No rule to make target `small.x.hl.b.json'. Stop.
it does not work. But it does work if I do this:
$ make small.x.hl.a.json
touch small.hl.a.json
touch small.hl.b.json
touch small.x.p.json
touch small.x.hl.a.json
rm small.x.p.json small.hl.a.json small.hl.b.json
$ make clean small.x.hl.b.json
rm -f *.json
touch small.hl.a.json
touch small.hl.b.json
touch small.x.p.json
touch small.x.hl.a.json
touch small.x.hl.b.json
rm small.x.p.json small.hl.a.json small.hl.b.json
Can someone tell me what's going on? And why can't I build small.x.hl.b.json directly but instead must first build small.x.hl.a.json and then small.x.hl.b.json?
I may be wrong, and I'll delete this answer if anyone can provide a better one, but this looks to me like a bug in GNUMake 3.81:
Make first considers the target small.x.hl.b.json, and finds two pattern rules that match it:
%.hl.b.json: %.hl.a.json # call this rule 2
...
%.x.hl.b.json: %.x.hl.a.json # call this rule 5
...
Note that both of these rules have the same prerequisite, namely small.x.hl.a.json.
It looks as if Make then makes a mistake. (Here's where I go out on a limb.) It goes searching for a way to build small.x.hl.a.json, remembering that it has already used rules 2 and 5, but failing to remember that they are parallel alternatives, not sequential steps. Later on, when Make needs small.hl.b.json, the only rule that will serve is rule 2, which Make rejects on the grounds that it must not use the same pattern rule twice in a chain. Never mind that this invocation would use a shorter stem, never mind that the chain in question is actually two chains, one of which has not yet used Rule 2, Make considers this a dead end.
This fits the results of the other experiments as well. Make can build small.x.hl.b.json without this self-collision, and once that target is built, Make can then build small.x.hl.b.json in a single step without a troublesome chain.
I found a tutorial saying that:
The rule with the shorted stem will be tried first, and if there is a tie the rule that appears first will be selected.
So I tried swapping the order of the rules so that .x. targets appear first, and then everything works!

Makefile target dependency to generated files

I have a question regarding the behavior of Make when running targets that are dependent on generated files.
Given the source tree and Makefile below, when I run this it takes two runs to complete the "build" even though everything was generated on the first run.
$ ls -R
.:
bar foo Makefile
Makefile
all: foobar
work:
mkdir -p work
work/foo: work foo
cp foo work/foo
work/bar: work bar
cp bar work/bar
foobar: work/foo work/bar
make
$ make
mkdir -p work
cp foo work/foo
cp bar work/bar
$ ls -R
.:
work/ bar CMakeLists.txt foo Makefile
./work:
bar foo
$ make
cp foo work/foo
$ make
make: Nothing to be done for 'all'.
Why does this happen?
You need to make the directory an order-only prerequisite, otherwise the targets will be remade each time the directory changes; during the second invocation work is newer than work/foo because work/bar was created after work/foo, so work's timestamp is newer than work/foo.
work/foo: foo | work
cp foo work/foo
work/bar: bar | work
cp bar work/bar
Or more concisely
work/foo work/bar: work/%: % | work
cp $< $#

Rule for all targets in make - even if the file exists

I want to create a Makefile that outputs foo no matter what target name is given to make.
So all of these should work:
$ make
foo
$ make a
foo
$ make foobar
foo
The following Makefile does almost what I want:
all %:
#echo foo
.PHONY: all
However it fails if there exists a file with the same name as the target:
$ touch abc
$ make abc
make: `abc' is up to date.
As .PHONY doesn't accept pattern rules, I don't know how I can get make to ignore every file.
How about:
all $(MAKECMDGOALS): ; #echo foo
.PHONY: all $(MAKECMDGOALS)

Resources