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

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

Related

Makefile don't check dependency timestamps

I am writing a makefile like this
foo: bar
touch foo
but I want foo to be built only if it's missing, regardless of whether bar is newer than foo. Is that possible with make?
but I want foo to be built only if it's missing, regardless of whether bar is newer than foo
In this case use an order-only dependency:
foo: | bar
touch foo
To make a target if it does not exist:
foo:
touch foo
To make bar if it's out of date and then make foo if it does not exist:
foo: | bar
touch foo
Note that in the example in the GNU Make documentation that $(OBJDIR) does not depend on anything and only will be made if it does not exist.
PS: Some additional information on how order-only prerequisites work.
$ ls
Makefile
$ cat Makefile
foo1: bar
touch foo1
foo2: | bar
touch foo2
foo3:
touch foo3
$ make foo1 foo2 foo3
make: *** No rule to make target `bar', needed by `foo1'. Stop.
$ touch bar
$ make foo1 foo2 foo3
touch foo1
touch foo2
touch foo3
$ make foo1 foo2 foo3
make: `foo1' is up to date.
make: `foo2' is up to date.
make: `foo3' is up to date.
$ touch bar
$ make foo1 foo2 foo3
touch foo1
make: `foo2' is up to date.
make: `foo3' is up to date.
$ make foo1 foo2 foo3
make: `foo1' is up to date.
make: `foo2' is up to date.
make: `foo3' is up to date.

Preventing variable overwriting in recursive Makefiles

I have the following project structure:
project/
- Makefile
- foo/
- foo.mk
- bar/
- bar.mk
Contents of Makefile:
.PHONY: all foo bar
all: foo bar
include foo/foo.mk
include bar/bar.mk
Contents of foo/foo.mk:
SOME_VAR=foo
foo:
#echo $(SOME_VAR)
Contents of bar/bar.mk:
SOME_VAR=bar
bar:
#echo $(SOME_VAR)
Running the command make in yields the output
bar
bar
The observed output is easy to explain: variables in recipes are expanded only when the rule is executed, so when SOME_VAR is overwritten in bar.mk the rule for foo prints bar. Is there any way of preventing this behaviour?
One way is to use target-specific variable values.
Change your sub-makefiles to
bar: SOME_VAR=bar
bar:
#echo $(SOME_VAR)
foo: SOME_VAR=foo
foo:
#echo $(SOME_VAR)
Recursive make will also work
all:
$(MAKE) -C foo -f foo.mk
$(MAKE) -C bar -f bar.mk

Is this a make bug?

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.

How to avoid duplication in Makefile targets with similar recipes?

I have a Makefile which has a lot of targets and the recipe for each target is quite similar.
foo:
gcc foo.c -o foo
mv foo ~/bin
bar:
gcc bar.c -o bar
mv bar ~/bin
baz:
gcc baz.c -o baz
mv baz ~/bin
I would like to avoid all this duplication. I would like to have something like below (this is not valid syntax; this only expresses my intention).
TARGET_NAME:
gcc $(TARGET_NAME).c -o $(TARGET_NAME)
mv $(TARGET_NAME) ~/bin
Is it possible to do something like this? If not, what is the best Makefile I can write that can minimize duplication in recipes?
Your makefile is wrong because your targets (foo, bar, etc.) don't depend on their source files (foo doesn't depend on foo.c, etc.) So, changing the source code won't cause the target to be rebuilt.
Also, your makefile says you're creating a file foo, but your recipe actually creates a file ~/bin/foo, which is not the same thing.
Anyway, this is exactly what pattern rules are for:
EXES = foo bar baz
all: $(addprefix $(HOME)/bin/,$(EXES))
$(HOME)/bin/%:: %.c
gcc $< -o $#
(Thanks to Beta for pointing out my think-o in the original)
A make rule can actually match multiple targets:
foo bar baz:
gcc $#.c -o $#
mv $# ~/bin
However, you should make the dependencies explicit in the rules:
foo: foo.c
bar: bar.c
baz: baz.c
foo bar baz:
gcc $< -o $#
mv $# ~/bin
The first three lines only specifiy the dependencies without any actions to actually build them. You can generate these with the help of gcc: gcc -MM foo.c will print a rule for foo.c.

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