-
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
Built targets are still dirty after a successful build #2473
Comments
Ping @jdrouhard, is there any chance that the changes in #1943 could be responsible for this behavior? |
Can you post the full By design, Ninja uses timestamps to determine quickly and cheaply if the content of a target (i.e. a file-system path) has changed. Unfortunately, for directories, the timestamp value is not a reliable indication that anything changed in it. Its timestamp is only updated when one of its direct entries (top-level files or sub-directories directly under it) change, and ignores anything below. This is what is happening here. In general, one should not use directories as output / target paths in Ninja to avoid this problem. The change in #1943 does not change that, it just triggers the problematic issue for your build plan. One way to deal with this is to always produce the directory atomically, i.e. create a new empty temporary directory, populate it, then compare its content with the existing one. If they are the same do not do anything (use the NOTE: This can only work if the content of the directory is never modified by other commands though; but if you have a build plan with different actions poking at the directory, you probably have a broken build graph with flaky incremental build breaks that occur randomly. Another alternative is to create a zip archive instead of a directory, that can be treated as a single file by Ninja, but it also means that anything that depends on it needs to run a command that unzip its content to a temporary directory before being able to use it (e.g. that's what the Chromium build does for Android resources). I would not recommend it though. |
It turns out the problem was in our build-system's ninja generator. Sorry for the noise! |
Thanks for telling us about it :-) |
When we use ninja to build our software, we run it twice: first to build the actual software, and then a second time afterwards to verify that it no-ops. We do this is because we have a very complex build with several no-code targets and such, and we want to make sure that no targets are still considered dirty even after a successful result. This second no-op pass is achieved by running
ninja -n -d explain
and then failing the build if we don't grepno work to do
in ninja's output.As of ninja 1.12.0, our builds now fail this step because ninja outputs the following:
We have about a dozen such targets that fail this test (none of which are no-code targets). The difference in these timestamps varies from a few milliseconds to a few seconds. Looking at the release notes and changelog of 1.12.0, this PR jumped out at me:
For a no-op build, it seems that this could mistakenly mark a target as dirty, since the mtime would be when the command started and not when the output (ie, none) was written to disk. I'm not terribly familiar with ninja internals, so please forgive me if I'm way off here. 😅
We are running ninja 1.12.0 (we'll update to 1.12.1 later, but not until we figure out what's going on with 1.12.0) on macOS Ventura using Xcode 15.2, in case that matters.
The text was updated successfully, but these errors were encountered: