Reputation: 959
From the docs:
$?
The names of all the prerequisites that are newer than the target, with spaces between them.
Now, given a makefile:
# Create target 'all', that is created later than 'old', which was created after 'older'.
$(shell touch older)
$(shell sleep 1)
$(shell touch old)
$(shell sleep 1)
$(shell touch all)
all : old phony;
@echo '"$$?" is: "$?"'
# A command to turn the file 'old' even "older", by acquiring the modification-time of 'older'.
old ::
cp -p 'older' 'old'
.PHONY: phony
Running, I get:
$ make
cp -p 'older' 'old'
"$?" is: "old phony"
# Trying again, but this time, with a *parallel-execution*.
$ make -j
cp -p 'older' 'old'
"$?" is: "phony"
*Can you see, that Make expand the value of $?
differently for a parallel execution (-j
), than it does for a non-parallel-execution?*
Let's first analyze the first case, i.e. for a non-parallel execution.
The modification-time of all
and old
are:
old
was "older" than all
. This is self-evident. Right?old
, old
got "older", so to speak, by "acquiring" the modification time of a file named: older
. This is basically a net-result of the shell command: cp -p older old
. Now, it is not hard to see, that older
was way "older" than all
.Now, Make ended up building the target all
, because of the other prerequisite, namely: phony
.
But, according the documentation, $?
should expands only to "the names of all the prerequisites that are newer than the target". This is an exact quote.
Could we agree, that old
was never newer than all
. And, if fact, had it not been for phony
, Make would not even re-build all
.
So, how wrong is it then, for Make, to expand $?
to old phony
.
phony
I get. But old
? Really?!
But, let's now turn our attention to parallel-execution, where Make expands $?
as phony
.
Here:
Certainly, one can say, that this expansion is right (compared to the expansion in a non-parallel execution).
The reason is, that only phony
is the file that triggered the re-build of all
. Without it, Make would not bother to re-build all
, at-all.
Still, one wonders, how can make expand the variable differently for a these two modes of execution.
I can not even think, how this could be any relevant to the expansion of $?
.
In summary, it looks like that a "random" change (i.e. a modification in the mode of execution, from a parallel to a non-parallel) influences a seemingly unrelated entity, that is the expansion of automatic-variables. Why?
Upvotes: 1
Views: 124
Reputation: 30841
Having built old
using the rules, Make now considers that to be the newest file in the dependency graph. It does not inspect old
after making it.
This is obviously the right thing to do for phony targets, and it usually is The Right Thing for file targets, too.
Upvotes: 1
Reputation: 7292
Any file built or updated by make has been updated, so it will implicitly assume it to be newer, even if you hack in a command that makes it older.
Theoretically, Make should work on the contents of a file, not the date. If the contents are different, then you should run dependent builds. Given that we don't have filesystems providing easy content-derivates (hashes or such) it uses the last-modified-date to do this. As that's also not 100% reliable - see for example systems on which those dates don't have sufficient accuracy or may be just in the future - it'll also use this as an information source. If it just built it, it must be modified, therefore it's correct to consider it "newer" or "rebuilt".
Upvotes: 0