Skip to content

feat: coalesce crates into one linked lib where possible across hubs/features/versions - #255

Draft
genevieve-me wants to merge 4 commits into
hermeticbuild:mainfrom
genevieve-me:feat/crate-coalescence-cross-hub
Draft

feat: coalesce crates into one linked lib where possible across hubs/features/versions#255
genevieve-me wants to merge 4 commits into
hermeticbuild:mainfrom
genevieve-me:feat/crate-coalescence-cross-hub

Conversation

@genevieve-me

Copy link
Copy Markdown

Resolves #144. Depends on hermeticbuild/rules_rust#57. Hefty MR so I tried to break it into individually reviewable commits: a lot of the lines changed number is churn in Bazel lockfiles.

This change allows one Bzlmod module to share a @crates hub with another module without producing duplicate Rust libraries for the same Cargo package. When the same compatible Cargo package appears in multiple hubs, rules_rs now reuses a single generated library target. If two configured instances are not safe to link into the same binary, the build fails during analysis instead of quietly linking both copies.

Each hub records the compilation properties that affect whether two crate instances can safely be shared, and those records are combined before assigning compatible instances to a canonical generated target. If the information needed to establish compatibility is missing, that combination is rejected.

I tested this to cover compatibility edge cases like optional-dependency and feature interactions that can change the effective crate graph, e.g., dep?/feature interactions and dependencies whose presence or configuration depends on enabled features.

The MR split up metadata and archive handling so that crates with the same name and version from different registries can coexist correctly - I figured some users might have an internal registry with a foobar 1.0.0 that collides with crates.io foobar 1.0.0.

This will need a rules_rust dependency bump once identity is in that ruleset.

Behavior notes

Dependency processing now uses deterministic topological ordering, so coalescing gives the same result regardless of input ordering. Repository staging and generated names are deterministic, with explicit collision detection.

This does not introduce global Cargo dependency resolution. Each hub still owns its own lockfile and dependency closure; coalescing only determines when compatible crate instances from those independent hubs may safely share a generated library target.

Package identity from rules_rust includes the package source as well as its name and version. In the future, we could use full Cargo Package IDs instead of name and version, since right now crates with the same name and version but different sources are rejected.

The current compatibility-class construction is intentionally conservative and fails closed when link safety cannot be established.

Move resolution and generated repository rendering into a private module, leaving tag declarations and orchestration in the public extension. Preserve behavior and update Starlark library dependencies.
Share schema-qualified registry and Git fact keys between downloading and resolution. Include Git checkout and member-layout inputs, and stage sparse metadata under source-qualified paths. Regenerate facts with Bazel 9.0.0 and add cache-key regression coverage.
Attach source-qualified logical identity to registry and Git libraries and proc macros, leaving binaries and build scripts untagged. Pin the public rules_rust revision providing optional identity metadata and verify provider propagation with analysis tests.
identity, compatibility, deterministic ordering, finalization, and core regressions
@genevieve-me
genevieve-me force-pushed the feat/crate-coalescence-cross-hub branch from bd488b3 to 6414a90 Compare September 8, 2026 23:10
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.

Allow a bzlmod module to consume a @crates hub declared by another module

1 participant