-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Follow up fixes to #1753 #1933
Follow up fixes to #1753 #1933
Conversation
I've confirmed this fixes #1932, but some of CMake's test suite still fails. I'll track down the next case. |
…re checking the build log This is a followup fix for ninja-build#1753. Fixes ninja-build#1932 `build_log()` will always be valid (even for new builds). We should be checking for the output being older than the input before we check the build log for additional possible conditions that would make the output dirty.
See additional case posted in #1932 (comment). |
46202d4
to
8884066
Compare
@jdrouhard as of commit |
See additional case posted in #1932 (comment). |
…mtime in the build log Generator rules may create inputs before creating the outputs. To avoid possible infinite loops, record the actual mtime of the output file in build log instead of the most recent input when the edge started building, since the edge's rule could create newer inputs.
…ng isn't specified Since the edge command might produce the depfile (implicit input) along with the output(s), it should be taken into account when determining the mtime to record in the build log for the outputs. If it's not, then the next run could see a stale mtime since the previous run would have recorded the most recent mtime excluding the depfile itself. For special depfiles (msvcc and gcc as of this commit), the depfiles are themselves parsed when the edge command is finished and the most recent input time of the parsed implicit deps is directly used instead.
5fa40fe
to
f220571
Compare
src/build.cc
Outdated
@@ -692,7 +692,7 @@ bool Builder::StartEdge(Edge* edge, string* err) { | |||
Node* most_recent_input = NULL; | |||
for (vector<Node*>::iterator i = edge->inputs_.begin(); | |||
i != edge->inputs_.end() - edge->order_only_deps_; ++i) { | |||
if (!(*i)->Stat(disk_interface_, err)) | |||
if (!(*i)->StatIfNecessary(disk_interface_, err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was discussed in #1753 but I think the performance tradeoff should lean toward speed over correctness. If we err on the side of speed, we just might have unnecessary rebuilds on future runs (as opposed to the alternative which is thinking outputs are up to date when they are actually dirty).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A build system should not re-run commands when not needed. We don't know how many downstream dependencies might need to rebuild unnecessarily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this on the original PR, I think you actually wondered why this wasn't StatIfNecessary()
to begin with.
This shouldn't cause ninja to rerun commands if the inputs don't change, which is identical behavior to what was here before #1753.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an example that change affects:
rm -f .ninja_deps .ninja_log out1 out2 in1 in2imp
>in1
echo >build.ninja '
rule touch_out_discovered_during_build
command = touch $out $discovered
rule touch_dep_discovered_during_build
command = touch $out; echo "$out: $discovered" > $depfile
build out1: touch_out_discovered_during_build in1
discovered = in2imp
build out2: touch_dep_discovered_during_build in1 || out1
discovered = in2imp
depfile = out2.d
deps = gcc
default out2'
ninja >/dev/null 2>&1
sleep 1
>in1
ninja
ninja -d explain
With Stat
, or prior to #1753, the output is:
[1/2] touch out1 in2imp
[2/2] touch out2; echo "out2: in2imp" > out2.d
ninja: no work to do.
With StatIfNecessary
after #1753, the output is:
[1/2] touch out1 in2imp
[2/2] touch out2; echo "out2: in2imp" > out2.d
ninja explain: recorded mtime of out2 older than most recent input in2imp (... vs ...)
[1/1] touch out2; echo "out2: in2imp" > out2.d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this test is unfortunate. Using StatIfNecessary()
could lead to infinite rebuild loops (target would never be clean) with this specific relationship of rules and implicit dependencies being updated by the rules. out1
has no specific knowledge that it updated in2imp
so there's nothing we can do when finishing the command for out1
to update the cached mtime for in2imp
.
If we want to keep the better build correctness that #1753 provides, it looks like there's no way to avoid Stat()
when edges are started which does have a performance penalty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC #1753 provides robustness against edits made to the source tree during the build by processes outside the build system. We need to decide if supporting that is worth making everyone pay for the extra Stat
on every build just in case someone does that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This investigation led me to find that CMake Issue 20025 has the same root cause, even with Ninja 1.10 (which does not have #1753). Cases like this might be resolvable using a dyndep
binding to declare the dynamically-discovered implicit output so that Ninja knows about it. I still need to try that out to be sure.
However, CMake's cases are just examples of existing cases that may exist in the wild. Many projects would have had no choice but to express things as in my above example because dyndep
support is recent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest dropping commit 53f96fed
for now so we can get everything else fixed. Then open an issue to discuss this optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that sounds good. I'm going to go ahead and add regression tests for this case anyhow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be resolvable using a dyndep binding... I still need to try that out to be sure.
Unfortunately that won't work without additional changes to Ninja. See the explanation I posted in the CMake issue.
As of commit |
What test? We really should port more of CMake's ninja tests to native ninja tests. |
It's the |
These expose some quirky behavior of implicit deps that are not directly known to the ninja build system.
53f96fe
to
7b04cd7
Compare
Hi! Thanks for your work. I haven't followed everything yet. I think a good idea would be to actually revert the merge commit of #1753, then add the test cases (except those for #1753) and then draft a new version of #1753 with the fixups. What do you think? We could also merge this PR, but then the actual change (and the fixes for it) would be scattered. |
I can do that. I'll open another PR with the revert + new tests, and a second one that re-lands the change along with the fixes. |
This reverts commit 67fbbee. There were a few missing test cases exposed by CMake's test suite that need slight adjustments. Better to revert the original attempt, add the test cases, and then re-land the change with the fixes. Fixes ninja-build#1933
These expose some behavior related to implicit deps unknown to ninja and timestamps with generating them as part of a rule. See discussions in ninja-build#1932 and ninja-build#1933.
These expose some behavior related to implicit deps unknown to ninja and timestamps with generating them as part of a rule. See discussions in ninja-build#1932 and ninja-build#1933.
These expose some behavior related to implicit deps unknown to ninja and timestamps with generating them as part of a rule. See discussions in ninja-build#1932 and ninja-build#1933.
These are followup fixes for #1753 and fixes #1932.
Stat()
toStatIfNecessary()
inStartEdge()
)