Skip to content

deprecate force_all_deps_direct in favor of extra_named_deps - #4160

Merged
scentini merged 7 commits into
bazelbuild:mainfrom
krasimirgg:jul26-extra-named-deps
Jul 23, 2026
Merged

deprecate force_all_deps_direct in favor of extra_named_deps#4160
scentini merged 7 commits into
bazelbuild:mainfrom
krasimirgg:jul26-extra-named-deps

Conversation

@krasimirgg

Copy link
Copy Markdown
Collaborator

This is intended to give better control and more flexibility for extensions like Crubit, which automatically generates rust bindings for C++ code. The bindings generator uses an aspect to crawl over a dependency graph of cc_libraries, plugs itself as a tool similar to a C++ compiler, parses the header files and generates the corresponding Rust bindings.
Due to the C++ compilation model, it's possible that a header file in a library uses a C++ symbol that is only defined in a header file owned by an indirect dependency of a c++ library. For example:

rust_library(name = "a", hdrs = ["a.h"])
rust_library(name = "b", hdrs = ["b.h"], deps = ["a"]) 
rust_library(name = "c", hdrs = ["c.h"], deps = ["b"])

# c.h
using C = int;
# a.h
C f();

While compiling the generated Rust bindings of c, the Rust compiler needs access to the generated Rust bindings of a, which is an indirect dependency. Historically, this was achieved via the force_all_deps_direct feature, which has the effect of putting all direct and indirect crate dependencies as --extern while compiling the bindings for a c++ target. This is imprecise and suffers from crate name collisions.

It is imprecise, because if any cc_library happens to depend on a rust library as an implementation detail, that rust library does not need to be made available via --extern.

It suffers from crate name collisions, because by default the crate names of generated bindings are derived from the name of the label of the c++ library. In a build graph where where two c++ libraries from different packages share the same name, there is a naming collision when client bindings are compiled:

# the generated bindings of both //p:a and //q:a produce a crate named a.
cc_library(name = "client", deps = ["//p:a", "//q:a"])

To handle these, we provide extra_named_deps a mechanism for extensions calling rustc_compile_action to supply an extra depset of named dependencies. The Crubit aspect can then compute appropriate names for the generated bindings of dependencies. For this to work at scale, we supply this as a depset to be computed recursively by the aspect crawling the dependency graph, avoiding quadratic blaze analysis time overhead.

The supplied test is a mock of the type of code pattern possible in this context -- a chain of 3 rust libraries, where the top-level one refers to its indirect dependency via a custom crate name.

… new `extra_named_deps` argument

This is intended to give better control and more flexibility for
extensions like Crubit, which automatically generates rust bindings for
C++ code. The bindings generator uses an aspect to crawl over a
dependency graph of cc_libraries, plugs itself as a tool similar to a
C++ compiler, parses the header files and generates the corresponding
Rust bindings.
Due to the C++ compilation model, it's possible that a header file in a
library uses a C++ symbol that is only defined in a header file owned by
an indirect dependency of a c++ library. For example:

rust_library(name = "a", hdrs = ["a.h"])
rust_library(name = "b", hdrs = ["b.h"], deps = ["a"])
rust_library(name = "c", hdrs = ["c.h"], deps = ["b"])

using A = int;
A f();

While compiling the generated Rust bindings of c, the Rust compiler
needs access to the generated Rust bindings of a, which is an indirect
dependency. Historically, this was achieved via the
`force_all_deps_direct` feature, which has the effect of putting all
direct and indirect crate dependencies as `--extern` while compiling the
bindings for a c++ target. This is imprecise and suffers from crate name
collisions. It is imprecise, because if any cc_library happens to depend
on a rust library as an implementation detail, that rust library does
not need to be made available via --extern. It suffers from crate name
collisions, because by default the crate names of generated bindings are
derived from the name of the label of the c++ library. In a build graph
where where two c++ libraries from different packages share the same
name, there is a naming collision when client bindings are compiled:

cc_library(name = "client", deps = ["//p:a", "//q:a"])

To handle these, we provide extra_named_deps: a mechanism for extensions calling
rustc_compile_action to supply an extra depset of named dependencies.
The Crubit aspect can then compute appropriate names for the generated
bindings of dependencies. For this to work at scale, we supply this as a
depset to be computed recursively by the aspect crawling the dependency
graph, avoiding quadratic blaze analysis time overhead.

The supplied test is a mock of the type of code pattern possible in this
context -- a chain of 3 rust libraries, where the top-level one refers
to its indirect dependency via a custom crate name.
@krasimirgg
krasimirgg requested a review from scentini July 22, 2026 14:07
@krasimirgg
krasimirgg marked this pull request as ready for review July 22, 2026 14:07
@scentini
scentini added this pull request to the merge queue Jul 23, 2026
Merged via the queue into bazelbuild:main with commit 0c5c01d Jul 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants