If you think about this at Ninja level, using order-only deps is problematic.Given the following GN targets:executable("A") {
data_deps = [ ":B" ]
...
}
action("run_A") {
script = "run_A.py"
deps = [ ":A" ]
outputs = [ "$root_out_dir/run_A.stamp" ]
}
Ninja rules would look like this:build A: link ... || ./B
build run_A.stamp: ___run_A___build_toolchain_gcc__rule | ../../run_A.py A
According to Ninja document,> Order-only dependencies, expressed with the syntax || dep1 dep2 on the end of a build line. When these are out of date, the output is not rebuilt until they are built, but changes in order-only dependencies alone do not cause the output to be rebuilt.The problem here is that if only `B` gets updated, `run_A` wouldn't run.
(sending again from my @chromium and dropping internal mailing-list)Despite my understanding that data_deps are supposed to work as they do now, I admittedly failed to find any spots in chromium where they are used in that way.The best example I could find was that //base depends on ICU, and so //base has a data_dep on ICU's data file, and any executable that depends on //base might expect ICU's data file to be there in time. However, the host_toolchain tools that depend on //base don't seem likely to use any ICU functionality. It just seems to be a very rare thing that a binary used when building relies on auxiliary files. IMO it seems rare enough that it's not worth implementing a way to propagate them as Dirk describes.So... I'm basically over my initial reasons for opposing the change, but orderfile + order-only deps usage in Fuschia seems more concrete to me & reason to not just change it (or to provide an orderonly_deps).
To unsubscribe from this group and stop receiving emails from it, send an email to gn-dev+un...@chromium.org.
We could probably go through and migrate the Fuchsia build to differentiate our true data_deps from our order_only deps. Most of that usage is buried in templates (for better or worse). A migration path would look (to me) something like:
1. Add order_only_deps field, with gn option to treat data_deps as order-only deps in ninja (ie, parity behavior)2. Migrate our usages as needed (with lots of testing)
3. Flip the flag on our build to get the data-dep behavior.
Thank you all for your feedback! That's really helpful for me.I understand `data_deps` is used for the cases that GN can't express with regular deps, and we need to keep the "order-only" behavior somehow.Just let me give some reasons why I'm motivated for more parallel build.There was a Chromium Q build regression caused by `code_cache_generator` having `v8_context_snapshot_generator` as data_deps. At that time, I made a workaround to move `v8_context_snapshot_generator` to the deps that runs `code_cache_generator`.Also, we still see `v8_context_snapshot_generator` is blocking the entire build (http://b/413494195) by several minutes. Then, I thought it's better to change the data_deps itself, rather than handling it one by one.I initially planned to use "phony" to change the Ninja build graph (e.g. phony/X has executable X and data_deps of X). But, surprisingly, Chromium builds already worked mostly well with "validations". That's why I was pursuing this proposal.I now rethink that changing the specific `v8_context_snapshot_generator` blocking issue might be easier to resolve the CQ build time issue...> I do not think we should make a target W that wants to run X at build time have to explicitly add a data dependency on X's data deps. That feels like a layering violation and an abstraction violation, and it seems like it would be easy to get things wrong and end up with broken build graphs.Hmm, I understand the feeling. But, order-only deps don't guarantee to run W only when X's data_deps changes.Let's say if X has Y as data_deps. The following Ninja graph generated by the current GN doesn't rebuild W, when only Y changes.
I'll give my two cents here, as someone newish to the chrome build team who's come from bazel build teams.Firstly, In my opinion, order-only deps are never useful, as they inherently provide incorrect semantics for incremental builds, and don't work properly with remote execution. I don't think they provide any useful use cases that cannot be dealt with by judicial use of real dependencies.
AFAICT, there are a few possible semantics of data_deps we could choose:
- Targets depending on A must declare dependencies on the data dependencies of A in addition to A
- All targets depending on A also implicitly declare a dependency on the data dependencies of A
- All targets attempting to run A also implicitly declare a dependency on the data dependencies of A
FWIW, I agree that the first option seems like a bad idea to me due to the layering violations mentioned earlier in the thread.To extend the previous example, here we see two ways we attempt to use A. In the first, we attempt to run the binary. This requires the binary and all its runfiles. And in the second we attempt to strip the binary. This requires only the binary itself.
executable("A") {
data_deps = [ ":B" ]
...
}
action("run_A") {
script = "run_A.py"
deps = [ ":A" ]
outputs = [ "$root_out_dir/run_A.stamp" ]
}
action("strip_A") {
script = "strip_A.py"
deps = [ ":A" ]
outputs = [ "$root_out_dir/A.stripped" ]
}
Bazel uses the third set of semantics. Specifically, it distinguishes between a label / target, a binary, and a file. If this were bazel:
- The target A would output DefaultInfo(files = ["A"], runfiles = ["B"])
- The target run_A would register an action with a dependency on the executable A (ie. A's files and runfiles)
- The target run_A would register an action with a dependency on the file A (and thus ignores its runfiles)
In my opinion, GN desperately needs a concept of providers, since it would solve this, and about half the problems GN currently has, but I don't really want to hijack this thread to talk about it.
First option:I believe that if we choose the first option, there should be no dependency at all, so we should just remove the order-only deps, whichSecond option:If we choose the second option, I think that instead of order-only deps, we should provide a phony, to provide correct semantics while continuing to avoid B triggering a rebuild in A. Something along the lines of:phony A_exe: A B
cc_binary A: clang -o A ...
cc_binary B: clang -o B ...
# Depends on the phony A_exe. No clue what the ninja syntax is to represent this since I'm not familiar with ninja.
root_out_dir/run_A.stamp: run_A.pyThird option:While I'd love to do the third option, there's no way to tell just by looking at the command-line whether a binary is being run or just used, so we couldn't do so in a way that's backwards compatible. Additionally, the vast majority of a time a binary is being executed, so I don't think this will meaningfully negatively impact build performance.
On Fri, May 23, 2025 at 5:02 AM Andrew Grieve <agr...@google.com> wrote:
Despite my understanding that data_deps are supposed to work as they do now, I admittedly failed to find any spots in chromium where they are used in that way.The best example I could find was that //base depends on ICU, and so //base has a data_dep on ICU's data file, and any executable that depends on //base might expect ICU's data file to be there in time. However, the host_toolchain tools that depend on //base don't seem likely to use any ICU functionality. It just seems to be a very rare thing that a binary used when building relies on auxiliary files. IMO it seems rare enough that it's not worth implementing a way to propagate them as Dirk describes.So... I'm basically over my initial reasons for opposing the change, but orderfile + order-only deps usage in Fuschia seems more concrete to me & reason to not just change it (or to provide an orderonly_deps).
The spot that I think would be most sped up by this proposal is android static analysis steps, which currently use data_deps because validations are not exposed via GN. Although arguably for this case the best thing to do would be to directly expose "validation_deps". But maybe there are other spots where data_deps are introducing slow-downs.
On Thu, May 22, 2025 at 2:51 PM Dirk Pranke <dpr...@chromium.org> wrote:
--
You received this message because you are subscribed to the Google Groups "chrome-build-team" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chrome-build-t...@google.com.
To view this discussion visit https://groups.google.com/a/google.com/d/msgid/chrome-build-team/CABiQX1WP5GXKR6SJ1MCW9yp7KYoXAEiyXsq2UREM2Dfdj7U2tg%40mail.gmail.com.
--Thanks, Matt.
I've never been a big fan of order-only dependencies either, but I don't think I've ever really fully looked into them to think about when they are needed and how best to handle them. For at least the basic example given in the Ninja manual, I don't believe they have incorrect incremental semantics, but I could certainly see how they might be fragile and incorrect in other situations. I would be interested in others' thoughts on this.
I'm guessing the third bullet has a typo and you meant to write "strip_A" instead of "run_A"?
I'm no expert on Bazel, so I'm not really familiar with providers. From a glance, they look similar to GN's metadata features. I agree with not hijacking threads, so perhaps you could start a new one, but I'm curious to hear more of your thoughts on this and/or whatever problems you think GN has? :).
Second option:If we choose the second option, I think that instead of order-only deps, we should provide a phony, to provide correct semantics while continuing to avoid B triggering a rebuild in A. Something along the lines of:phony A_exe: A B
cc_binary A: clang -o A ...
cc_binary B: clang -o B ...
# Depends on the phony A_exe. No clue what the ninja syntax is to represent this since I'm not familiar with ninja.
root_out_dir/run_A.stamp: run_A.pyThird option:While I'd love to do the third option, there's no way to tell just by looking at the command-line whether a binary is being run or just used, so we couldn't do so in a way that's backwards compatible. Additionally, the vast majority of a time a binary is being executed, so I don't think this will meaningfully negatively impact build performance.I'm not wild about your second option, assuming I'm understanding it correctly. I feel like you should only have to type 'ninja A' to build A, and not 'ninja A_exe'. Nor should most things be trying to distinguish between a dependency on "A_exe" and "A". I think the template idea accomplishes what you mostly want here with a better UI and more safety; the dummy group is similar enough to a phony target, but has real dependency requirements to protect it.
phony A: A_internal B
cc_binary A_internal: clang -o A ...
cc_binary B: clang -o B ...
# Depends on the phony A_exe. No clue what the ninja syntax is to represent this since I'm not familiar with ninja.
root_out_dir/run_A.stamp: run_A.py
Edit: I've been informed that apparently ninja does have dynamic dependencies. Might be a good idea to just remove all order-only deps and implicit deps and replace them with dynamic deps.On Thu, May 29, 2025 at 2:50 PM Matt Stark <ms...@google.com> wrote:I've never been a big fan of order-only dependencies either, but I don't think I've ever really fully looked into them to think about when they are needed and how best to handle them. For at least the basic example given in the Ninja manual, I don't believe they have incorrect incremental semantics, but I could certainly see how they might be fragile and incorrect in other situations. I would be interested in others' thoughts on this.After thinking about it more, I'll amend my earlier statement. Order-only deps are, in my opinion, only useful for dynamic/implicit dependencies. The difference between dynamic and implicit dependencies is that dynamic dependencies are explicit dependencies created during the execution of the build, whereas implicit dependencies are... implicit. Implicit dependencies suck because they don't play nice with RBE, and thus will fail in wierd unexpected ways whenever you use RBE, which is why no build system that cares about correctness supports them.The problem is, ninja does not provide a concept of dynamic dependencies - only implicit dependencies. Implicit dependencies suck because they don't play nice with RBE, which doesn't have access to any files not explicitly provided. Currently, we solve this in siso by having attempting to turn those implicit dependencies into explicit, dynamic dependencies by reading depfiles, for example. However, doing this requires knowledge of precisely what format these depfiles use (and data dependencies don't have a depfile).I'm guessing the third bullet has a typo and you meant to write "strip_A" instead of "run_A"?Whoops, good catchI'm no expert on Bazel, so I'm not really familiar with providers. From a glance, they look similar to GN's metadata features. I agree with not hijacking threads, so perhaps you could start a new one, but I'm curious to hear more of your thoughts on this and/or whatever problems you think GN has? :).From what I could tell from looking at the documentation, metadata has a roughly similar idea, but isn't very helpful because it can only be put into files on disk, rather than read directly in your BUILD.gn. If other rules (which I think are approximately templates in GN?) could read it, it'd be more akin to bazel's providers, and would have an extremely large number of use cases (I could do some very cool things with that).
The problem is, ninja does not provide a concept of dynamic dependencies - only implicit dependencies. Implicit dependencies suck because they don't play nice with RBE, which doesn't have access to any files not explicitly provided. Currently, we solve this in siso by having attempting to turn those implicit dependencies into explicit, dynamic dependencies by reading depfiles, for example. However, doing this requires knowledge of precisely what format these depfiles use (and data dependencies don't have a depfile).
From what I could tell from looking at the documentation, metadata has a roughly similar idea, but isn't very helpful because it can only be put into files on disk, rather than read directly in your BUILD.gn. If other rules (which I think are approximately templates in GN?) could read it, it'd be more akin to bazel's providers, and would have an extremely large number of use cases (I could do some very cool things with that).
To unsubscribe from this group and stop receiving emails from it, send an email to gn-dev+un...@chromium.org.--Thanks, Matt.