-
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
Method for detecting missing dependency graph edges #1660
Comments
I'm interested in random order too. |
I recently ran into one of those missing-dependency bugs in a CMake project, and I came up with a different way to diagnose it. The problem, in my case, was that a header file was being generated by build step A, and used by build step B, but there was no explicit dependency written into But the nice thing about this kind of makefile bug is that you can detect it after the fact, because the header dependencies that ninja collected during the build show up the problem. Even if your build happens not to fail, you can look at I actually wrote a script to do this analysis, by running both |
@sgtatham Great idea! I didn't know that Ninja records header dependencies during the build. Do you mind sharing your script? Also if I'm understanding you, that only works for headers, right? |
Sharing my script: sure. I developed it in order to locate a bug of this kind in the LLVM project, so once I'd found the bug, I checked in the script to the LLVM repo. It's here: https://github.com/llvm/llvm-project/blob/master/llvm/utils/check_ninja_deps.py This should work for any dependencies discovered at build time and recorded via ninja's |
Just found this script that @sgtatham reported and it pinpointed issues that had been non-deterministically plaguing us for a while. FYI, it is now here: https://github.com/llvm/llvm-project/blob/main/llvm/utils/check_ninja_deps.py (branch renamed) It would be really a nice value add if ninja grew such a feature natively, imo. |
Hi all, I'm a bit late in spotting this issue, but ninja 1.11+ now has a I think this can be closed as resolved by #1331 and released in 1.11. |
Actually I don't think this is really solved. Looks like I previously suggested:
It turns out GNU Make actually has this option ( |
Yes, missingdeps relies on depfiles (more generally on input information on build steps/edges). I would argue that if build steps don't have correct input information, the build is already broken and will never be reliable, incrementally in particular. No depfiles and insuficient input info means build steps aren't re-run when they should. Personally I don't think it's useful to optimize tooling for cases where this is not getting fixed. But I'm just a drive-by contributor here ;) This is somewhat skewed from a Chromium/GN perspective, where all custom actions (roughly: go through Python wrappers and either declare all their inputs statically, or generate depfiles based on what they did. It turns out it's usually easy to get all the used files listed. |
Of course. The whole point of this issue is that it's difficult to get dependencies correct and it would be nice to have some kind of tool assistance for doing that. Make's Obviously the proper fix is to use Bazel (or Buck, Pants, Please, Nix, etc) which was created to solve this exact problem (cache invalidation essentially). But "everyone must use Bazel" isn't a very practical answer, so it would be good if people using Ninja had something to help rather than nothing (or something that only works for C headers). |
It's not only for C headers. Arbitrary build steps can generate depfiles too, and arguably should if they can't list all inputs separately. And I think that if a build has dep issues, fixing input info is the first step. |
They can generate a depfile, but not a reliable depfile. You said some of your build steps declare all their inputs statically. How do you know you didn't make a mistake and miss a dependency when you wrote that list? That's what this issue is about preventing. |
I certainly admit that Make is much better than Ninja at certain things. For example, Make supports user-defined functions, while Ninja does not, very intentionally :-) Apart from that, I would prefer to make Ninja's behavior as deterministic as possible, as we already suffer from enough cases where its incremental builds are flakily broken (which is a risk for any non-trivial project after a regeneration step). Introducing even more randomness to help fix broken build plan generators does not seem in line with Ninja's design goals. |
Right! That's exactly what this kind of option is meant to help diagnose. There's also no need for it to introduce indeterminacy. You can use a seed (the Make option supports this). Though commands aren't run in a deterministic order in the first place are they? I think there might be some miscommunication about what this feature does - I can't imagine you would want to deny debugging tools to your users (you already have the I can't imagine it would be very hard to implement, but tbh I've moved companies since I had to deal with the particular dependency graph bug that drove me to open this issue.... Also given that Make has the equivalent feature and it was a CMake project I'm not sure why I didn't just switch generator. Maybe that Make option didn't exist at the time. |
In large CMake projects it can often be the case that you forget a dependency between two targets. But because you are lucky Ninja happens to build those two targets in the right order anyway. Maybe you're entire CI system is lucky too, but some unlucky person gets the wrong order and their build fails.
Nix (and maybe Bazel?) completely solves this by putting each target in a hashed directory whose name is only known to explicit dependants. But with Ninja you basically have to rely on luck, which sucks.
I can think of two solutions for CMake/Ninja:
Use
strace
orLD_PRELOAD
or something like that to trace file accesses. Then you can tell if one step accesses a file that was modified by another step that it doesn't explicitly depend on. This may be tricky.Allow running the build with different build orders (that are allowed by the DAG). It's probably infeasible to enumerate every possible combination for most build graphs, but running it with a few different random ones is better than nothing. Something like
--build_order_seed=45
.The text was updated successfully, but these errors were encountered: