Skip to content

Support RunfilesGroupInfo - #368

Open
malt3 wants to merge 1 commit into
bazelbuild:masterfrom
malt3:support_runfiles_groups
Open

Support RunfilesGroupInfo#368
malt3 wants to merge 1 commit into
bazelbuild:masterfrom
malt3:support_runfiles_groups

Conversation

@malt3

@malt3 malt3 commented Jul 24, 2026

Copy link
Copy Markdown

Teach the Java rules to describe their runfiles as named, ordered groups so that downstream packaging rules can build more efficient artifacts.

java_binary, java_test, java_library, and java_import now return RunfilesGroupInfo (and RunfilesGroupMetadataInfo) from the rules_runfiles_group ruleset alongside DefaultInfo. Instead of seeing a single flat runfiles tree, a packaging rule (e.g. a container-image or archive rule) can split a binary's runfiles into layers and order them so that the content that changes least often lands in the most cacheable layers:

  • the JDK / java_runtime at the foundation tier (never merged),
  • java_import targets (typically third-party jars) at the shared-deps tier,
  • first-party java_library code, the binary's own jars, and the executable at the executable tier.

Libraries propagate fine-grained per-target groups up through their dependents; the binary collects them, adds its own groups, and tags every group it produces with the rules_java merge affinity so that JVM-shaped groups stay together when a packager has to merge groups to fit a layer limit. java_import gains a runfiles_weight attribute so dependency-management rulesets can hint at relative sizes to guide those merge decisions.

Consumers that don't understand RunfilesGroupInfo are unaffected and keep using DefaultInfo.default_runfiles.

Adds a dependency on rules_runfiles_group for both Bzlmod and WORKSPACE setups.

Validation

I took the liberty to host a BCR mirror that has support enabled for rules_java and rules_img. I also created a demo repo to show the effect.

This shows two java_binary targets with overlapping dependencies. Both are packaged as container images.
Without RunfilesGroupInfo, the whole java_binary is stored as a single layer and there is no sharing (only the base image layer is shared):

With RunfilesGroupInfo, individual runfiles from java_library targets get their own layers and most of the content is shared across the container images:

@malt3
malt3 requested review from a team and hvadehra as code owners July 24, 2026 16:38
@malt3
malt3 force-pushed the support_runfiles_groups branch 2 times, most recently from eb1d207 to a0618f8 Compare July 24, 2026 16:48
Comment thread java/bazel/rules/bazel_java_binary.bzl Outdated
Comment thread java/bazel/rules/bazel_java_binary.bzl Outdated
@malt3

malt3 commented Jul 24, 2026

Copy link
Copy Markdown
Author

I discussed with @fmeum that it's possible to make this provider a lot more memory efficient. I'll also add a global flag to enable/disable the emition of this provider for memory conscious users.
I'll update this PR accordingly.

Comment thread java/bazel/rules/bazel_java_binary.bzl Outdated
@malt3
malt3 force-pushed the support_runfiles_groups branch 2 times, most recently from f989530 to 705d909 Compare July 27, 2026 12:56

@fmeum fmeum left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can mark this rfr.

@malt3

malt3 commented Jul 27, 2026

Copy link
Copy Markdown
Author

You can mark this rfr.

I will, but it's referencing a prerelease version of rules_runfiles_group.
I'll kick off a new release of that module now. Just FYI for any reviewer.

EDIT: done. Now pointing at rules_runfiles_group@0.1.0

@malt3
malt3 marked this pull request as ready for review July 27, 2026 14:57
Teach the Java rules to describe their runfiles as named, ordered groups
so that downstream packaging rules can build more efficient artifacts.

`java_binary`, `java_test`, `java_library`, and `java_import` now return
`RunfilesGroupInfo` from the `rules_runfiles_group` ruleset alongside
`DefaultInfo`. Instead of seeing a single flat runfiles tree, a packaging rule
(e.g. a container-image or archive rule) can split a binary's runfiles into
layers and order them so that the content that changes least often lands in the
most cacheable layers:

  * the JDK / java_runtime at the foundation tier (never merged),
  * `java_import` targets (typically third-party jars) at the shared-deps tier,
  * `java_library` code, the binary's own jars, and the executable at the
    executable tier, marked `first_party` only for targets in the main
    repository -- plenty of Java code Bazel builds from source belongs to
    somebody else.

Libraries propagate fine-grained per-target groups up through their dependents
as a depset of group entries, each carrying its own metadata, so what a target
retains does not grow with the size of its closure. The binary collects them,
adds its own groups, and tags every group it produces with the `rules_java`
merge affinity so that JVM-shaped groups stay together when a packager has to
merge groups to fit a layer limit. A dependency that returns `JavaInfo` but no
`RunfilesGroupInfo` -- a custom rule, or `rules_jvm_external`'s `jvm_import` --
gets a synthesized group covering its transitive runtime jars and its default
runfiles, so a packager never silently loses its files. `java_import` gains a
`runfiles_weight` attribute so dependency-management rulesets can hint at
relative sizes to guide those merge decisions.

Emission is off by default and gated on the ruleset-wide
`--@rules_runfiles_group//runfiles_group:enabled` flag, so a build that packages
nothing pays nothing for the providers. Consumers that don't understand
`RunfilesGroupInfo` are unaffected and keep using
`DefaultInfo.default_runfiles`.

Adds a dependency on `rules_runfiles_group` for both Bzlmod and WORKSPACE
setups.
@hvadehra

hvadehra commented Aug 6, 2026

Copy link
Copy Markdown
Member

Instead of making changes to various rules repos, have you considered achieving this with an aspect? ISTM this is the exactly kind of thing aspects were designed for.

@malt3

malt3 commented Aug 6, 2026

Copy link
Copy Markdown
Author

@hvadehra I have considered it, but I haven't found a good way to do this so far.
The biggest blocker I see is that currently, the Aspect has to be tailor-made for every language ruleset.
I don't know of an efficient way to walk the deps of a java_binary (or other language rule) and decide for each dep which runfiles that dep has contributed to the runfiles of the leaf.

Or to make this more concrete: In the implementation function of an aspect, I can inspect the DefaultInfo of the current target, but I cannot get an incremental view of said DefaultInfo (given a target x that inherits DefaultInfo/runfiles from a and b and merges them into it's own runfiles, get the subset of files added by x that were not provided by a or b).
The only way that I know of is to call to_list() on the depsets and figure out what was added by a specific target. This is undesirable IMO.

If we figure out a way to do the same work efficiently in an Aspect, I'd be happy to do so.

@hvadehra

hvadehra commented Aug 6, 2026

Copy link
Copy Markdown
Member

I could imagine having a runfiles_group_support.bzl in rules_java with something like:

def process_target_from_aspect(ctx):
   if not _is_rules_java_target(ctx):
     return None
   
   if ctx.rule.kind == "java_binary":
     // do what this PR currently does and return the right RunfilesGroupInfo()
   elif ...
   

with tests ensuring the rule implementations and the function stay in sync (at least in the ways we care about).

@malt3

malt3 commented Aug 6, 2026

Copy link
Copy Markdown
Author

@hvadehra I like your proposal. Let me rephrase it in my own words to ensure we are on the same page:

  • java_library targets do not provide RunfilesGroupInfo directly
  • java_binary would apply an aspect to it's own deps that is specific to rules_java
  • The Aspect collects information on runfiles groups
  • java_binary does return RunfilesGroupInfo (if the global configuration setting demands it)

Can you confirm if I understand your idea correctly? If we agree on that, I can implement your proposal.

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.

3 participants