File targets to be prerequisites of PHONY targets order-only or not? - makefile

The Makefile style guide mentions that "No file targets should be prerequisites of .PHONY."
I assume you could reword that as "Don't declare file targets PHONY"?
To express dependencies, for the human reader as well as for Make, I guess you sometimes need file targets be prerequisites of PHONY targets.
Should those be order-only targets, then?
As far as I understand, in this case the only difference between order-only and not is if they appear in $^ or in $|, so it probably depends on what behavior you want in that matter, respectively which kind of dependency you want to express.
Am I correct here? (If there is no clear case for one or the other,) are there any reasons to choose one over the other (order-only or not)?

I guess you sometimes need file targets be prerequisites of PHONY targets
Most of the time, in fact. Consider that "standard" stuff:
.PHONY: all
all: myprog other_stuff
myprog: $(OBJECTS)
...
But "Don't declare file targets PHONY / No file targets should be prerequisites of .PHONY" is a totally different thing. It means .PHONY: myprog is bad and should be avoided. The reason is that (1) it unconditionally triggers rebuild of myprog which is abnormal; (2) it could fool a human into thinking that myprog is "not a file".
If you need to force rebuild of myprog once you do make -B myprog. If it really needs to be rebuilt every time make runs, then you can do:
myprog: $(OBJECTS) FORCE
...
FORCE:;
Or something like that.
As far as I understand, in this case the only difference between order-only and not is if they appear in $^ or in $|
The order-only prerequisites are rarely used GNU extension. There is no need to put them in just to show that "phony stuff" on the left side will be rebuilt anyway. So no one ever writes all: | myprog, although it would work as good as all: myprog.

Related

Missing dependency in Makefile

I have these recipes in my Makefile. They generate cross-compiled objects for ARM architecture and link them into an elf binary:
%.ao: %.c
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
%.elf: %.ao startup_stm32f0xx.ao system_stm32f0xx.ao
$(ARM_CC) $(ARM_FLAGS) $other_arguments -o $# $^
This works fine from a clean build.
Contrary to my expectation, if I then say touch foo.c; make foo.elf, gmake responds with
make: 'foo.elf' is up to date.
If I try to make foo.ao, gmake says that it, too , is up to date.
What am I missing?
Edit after reading the comments:
TLDR: I did have multiple rules matching the same target, as John Bollinger alluded and HardcoreHenry said specifically.
In addition to the rules above, there's a rule for assembly sources so I can use those vendor files:
%.ao: %.s
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
I had been debugging some macros, and used -save-temps to look at preprocessor output. This option also writes .s files. So after I'd run make foo.elf, I'd have the following in my directory:
foo.c
foo.i
foo.s
foo.ao
foo.elf
I can touch foo.c, but make sees that there's a foo.s which is older than foo.ao, and produces the output that it does. On a clean build, there is no foo.s, so make finds the %.c:%.ao rule and the build proceeds from foo.c.
(BTW, .ao stands for ARM object. In addition to cross-compiling for AMR, I compile many of the sources to run unit tests on the host, using the built-in .o:.c rule)
I'm not a fan of pattern rules.
Make can make very strange decisions on which rules apply depending on whatever is lying around on your hard disks.
It's all a bit arbitrary.
Much better IMHO to tell make exactly what files you need for a target.
It's pretty easy too.
Just prefix your pattern rule with the list of targets you actually want it to apply to.
This makes it a Static Pattern Rule.
objects := main.ao tools.ao devices.ao# etc
${objects}: %.ao: %.c
$(ARM_CC) $(ARM_CPPFLAGS) $(ARM_FLAGS) $(CFLAGS) -c -o $# $<
%.elf: ${objects} startup_stm32f0xx.ao system_stm32f0xx.ao
$(ARM_CC) $(ARM_FLAGS) $other_arguments -o $# $^
As an added bonus, make now won't try to create the pre-existing startup_stm32f0xx.ao and system_stm32f0xx.ao.
Usually I find it nicer to list the source files, but YMMV:
sources := main.c tools.c devices.c
objects := $(patsubst $.c,%.ao,${sources})
(P.S. Using a Static Pattern Rule doesn't really give you any advantage over a normal rule in this noddy case. I just wanted to show a small tweak that would make your makefiles much more consistent in their behaviour.)
I know it's bad form to use an answer to respond to another answer, but I ran out of space in a comment to #bobbogo's answer.
Sorry but I can't agree with your assessment of pattern rules. It's not true that you will get "strange decisions" based on "whatever is lying around on your harddisks", and it's certainly not arbitrary.
There is one advantage of static pattern rules over pattern rules, and that is also its downside: a static pattern rule is a shorthand for creating an explicit rule, so that rule will always be used to build that target. A pattern rule, on the other hand, is just one possible way to build a target: if the prerequisites of a pattern rule don't exist and can't be made, then make keeps going and looks for other pattern rules that might be able to build that target.
So if you have multiple possible ways you can build a target then an explicit rule cannot be used for that.
The problem with pattern rules is that if NO pattern rule applies then make just assumes there is no rule to build that target. If the target exists then make simply says "up to date" (as we see in the question) since there's no rule to build it. That can be confusing to users.
If you use an explicit rule (including a static pattern rule) and some prerequisite doesn't exist and can't be created, then make will exit with an error, which can make it easier to figure out what went wrong.

Why don't Phony pre-requisites appear in `$?`?

Example: let's say I have a bar.c and baz.c, I want to produce foo.a. So:
foo.a: bar.o baz.o
ar -rc $# $?
Now I decide I always want bar.o to be updated. I decide to make it a Phony target. This also requires an explicit recipe for it, since implicit rules don't get searched for Phony targets. So:
.PHONY: bar.o
bar.o: bar.c
cc -c -o $# $<
foo.a: bar.o baz.o
ar -rc $# $?
Now when I run make foo.a, bar.c always gets compiled. Since bar.o gets updated, foo.a's recipe always gets run.
But: $? has an empty value so foo.a doesn't get modified. Why?
Good question. I'm not sure exactly but I suspect it is because phony targets are exactly that "phony" as-in they are explicitly expected not to represent files and so having them in the list of prerequisites newer than the target doesn't really make all that much sense.
That said if you want to keep this behavior but handle things correctly you want to avoid a .PHONY target and instead use a forced target.
If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file, then make imagines this target to have been updated whenever its rule is run. This implies that all targets depending on this one will always have their recipe run.
An example will illustrate this:
clean: FORCE
rm $(objects)
FORCE:
Here the target ‘FORCE’ satisfies the special conditions, so the target clean that depends on it is forced to run its recipe. There is nothing special about the name ‘FORCE’, but that is one name commonly used this way.
As you can see, using ‘FORCE’ this way has the same results as using ‘.PHONY: clean’.
Using ‘.PHONY’ is more explicit and more efficient. However, other versions of make do not support ‘.PHONY’; thus ‘FORCE’ appears in many makefiles. See Phony Targets.

What is the behaviour of an order-only prerequisite where the prerequisite is a phony target?

I am wondering if the order-only prerequisite loses its order-only precedence if it is a phony target. Consider the following:
%.make: unpack_chroot
schroot $(CHROOT) make $*
%.copy: | unpack_chroot
rsync -a input/$*/ $(CHROOT)/input/$*/
unpack_chroot: input/chroot.tar.gz
mkdir -p $(CHROOT)
tar -C $(CHROOT) -zxf $<
.PHONY: unpack_chroot
All %.make and %.copy targets are .PHONY. Some of these targets depend on files being copied into the chroot, others do not. Those that do are defined with explicit dependencies:
a.make: a.copy
c.make: c.copy
However, if unpack_chroot is not an order-only prerequisite and was unpacked as part of the processing of prerequisites for another make target not in the same make process, unpack_chroot will be considered up-to-date when %.copy runs and will not remake %.copy; at least that is what I have seen. Currently, unpack_chroot is not phony and gets created. I want to make it phony, but want to clarify the behaviour.
According to this email ( http://kolpackov.net/pipermail/notes/2004-January/000001.html ) it seems that the only difference between normal and order only prerequisites is that the latter will not be included in automatic make variables such as $^.
From some tests I ran it seems that this is the only difference. In all other respects they are treated the same as normal prerequisites.

Make file possible accidental order-only dependency?

I am pulling out my hair trying to debug an issue with make. It seems like make is randomly treating certain prerequisites as order-only prerequisites, resulting in them being left out of the static library target that depends on them. Most of the time the build works find but occasionaly some .cpp files are built but not included in the .a. When i run Make with --debug I see the following output for the suspect prerequisites.
Prerequisite `blah.o' is newer than target `/path/to/foo.a`
Prerequisite `blah1.o' is newer than target `/path/to/foo.a`
Prerequisite `blah2.o' is newer than target `/path/to/foo.a`
No need to remake target `/path/to/foo.a'
For all of the prereqs that do make it into the .a the last line is "Must remate target /path/to/foo.a" as I would expect.
Because make is invoked in several subdirectories, target /path/to/foo.a is updated several times. We are not running make in parallel so I don't think updates to the file are stomping each other. It seems that make is deliberately not updating the .a file despite the fact that the .o's are newer. The recipe to make foo.a is as follows:
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $(OBJLIB) $?
Where ARFLAGS=rv and OBJLIB would be /path/to/foo.a.
Am i right in thinking that the .o files are being treated as order-only dependencies? Is there something else I'm missing here? I am using $(info) to output the contents of OBJLIB and OBJS and there are no errant pipe ('|') characters making their way into the variable contents that would induce order-only dependencies.
Unfortunately the answer had nothing to do with make. As far as I can tell the filesystem is the real culprit. Several people were experiencing success with the build but I was not. The difference between our systems which were using a common build environment was that I was building on an ext3 filesystem while they were using an ext4 filesystem.
Since ext3 does not support sub-1s timestamps (ext4 does) in some cases when the rule was invoked with only a few CPP files they were being compiled in the same second that the archive was updated by a previous invocation and everything was ending up with the same timestamps. Copying the directory over to an ext4 filesystem fixed the issue.
The real fix is to write a proper set of make rules but at least we have an answer as to why it was working for everyone but me.
You mentioned several updates to the .a file because make is invoked in different subdirectories. Probably the message
No need to remake target `/path/to/foo.a'
comes from one subdirectory, and is newer- from another. Consider building the lib out of all objects in one step.
Try this instead.
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $(OBJLIB) $^
Your problem is that the variable $? is a list of dependencies that are newer than the target, while $^ is a list of all dependencies.
Also, you can use $# for to be more idiomatic.
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $# $^

making all rules depend on the Makefile itself

When I change a Makefile, its rules may have changed, so they should be reevaluated, but make doesn't seem to think so.
Is there any way to say, in a Makefile, that all of its targets, no matter which, depend on the Makefile itself?
(Regardless of its name.)
I'm using GNU make.
This looks like one more simple, useful, logical thing that Make should be able to do, but isn't.
Here is a workaround. If the clean rule is set up correctly, Make can execute it whenever the makefile has been altered, using an empty dummy file as a marker.
-include dummy
dummy: Makefile
#touch $#
#$(MAKE) -s clean
This will work for most targets, that is targets that are actual files and that are removed by clean, and any targets that depend on them. Side-effect targets and some PHONY targets will slip through the net.
Since GNU make version 4.3 it is now possible with the use of those two special variable:
.EXTRA_PREREQS
To add new prerequisite to every target
MAKEFILE_LIST
To get the path of the make file
To have every target depend on the current make file:
Put near the top of the file (before any include since it would affect the MAKEFILE_LIST) the following line:
.EXTRA_PREREQS:= $(abspath $(lastword $(MAKEFILE_LIST)))
To have every target depend on the current make file and also the make files which were included
Put the following line at the end of your file:
.EXTRA_PREREQS+=$(foreach mk, ${MAKEFILE_LIST},$(abspath ${mk}))
The only answer I know to this is to add makefile explicitly to the dependencies. For example,
%.o: %.c makefile
$(CC) $(CFLAGS) -c $<

Resources