Skip to content

Commit 1ad4ccc

Browse files
committed
Support RunfilesGroupInfo
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.
1 parent 9ed4512 commit 1ad4ccc

15 files changed

Lines changed: 608 additions & 6 deletions

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ bazel_dep(name = "platforms", version = "0.0.11")
99
bazel_dep(name = "rules_cc", version = "0.2.17")
1010
bazel_dep(name = "bazel_features", version = "1.30.0")
1111
bazel_dep(name = "bazel_skylib", version = "1.6.1")
12+
bazel_dep(name = "rules_runfiles_group", version = "0.1.0")
1213
bazel_dep(name = "protobuf", version = "32.1", repo_name = "com_google_protobuf")
1314
bazel_dep(name = "zlib", version = "1.3.1.bcr.5")
1415

distro/relnotes.bzl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ bazel_dep(name = "rules_java", version = "{VERSION}")
2020
2121
**WORKSPACE setup**
2222
23-
With Bazel 8.0.0 and before 8.3.0, add the following to your `.bazelrc` file:
23+
With Bazel 8.x, add the following to your `.bazelrc` file:
2424
2525
~~~
26+
# https://github.com/bazelbuild/bazel/issues/23043
2627
# https://github.com/bazelbuild/bazel/pull/26119
27-
common --repositories_without_autoloads=bazel_features_version,bazel_features_globals
28+
common --repositories_without_autoloads=rules_runfiles_group,bazel_features_version,bazel_features_globals
2829
~~~
2930
3031
In all cases, add the following to your `WORKSPACE` file:

java/bazel/rules/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ bzl_library(
3636
"@bazel_skylib//lib:paths",
3737
"@rules_cc//cc:find_cc_toolchain_bzl",
3838
"@rules_cc//cc/common",
39+
"@rules_runfiles_group//runfiles_group:lib",
40+
"@rules_runfiles_group//runfiles_group:providers",
3941
],
4042
)
4143

java/bazel/rules/bazel_java_binary.bzl

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
load("@bazel_features//:features.bzl", "bazel_features")
1717
load("@bazel_skylib//lib:paths.bzl", "paths")
1818
load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain")
19+
load("@rules_runfiles_group//runfiles_group:lib.bzl", "runfiles_groups")
20+
load("@rules_runfiles_group//runfiles_group:providers.bzl", "RunfilesGroupInfo")
1921
load("//java/common:java_semantics.bzl", "semantics")
2022
load(
2123
"//java/common/rules:android_lint.bzl",
@@ -26,6 +28,16 @@ load("//java/common/rules:rule_util.bzl", "merge_attrs")
2628
load("//java/common/rules/impl:java_binary_deploy_jar.bzl", "create_deploy_archives")
2729
load("//java/common/rules/impl:java_binary_impl.bzl", "basic_java_binary", "binary_provider_helper")
2830
load("//java/common/rules/impl:java_helper.bzl", "helper")
31+
load(
32+
"//java/common/rules/impl:runfiles_group_support.bzl",
33+
"BINARY_GROUP",
34+
"JAVA_RUNTIME_GROUP",
35+
"MERGE_AFFINITY",
36+
"RUNFILES_GROUP_ATTRS",
37+
"collect_entries",
38+
"own_kind",
39+
"runfiles_groups_enabled",
40+
)
2941
load("//java/private:java_info.bzl", "JavaInfo")
3042

3143
def _bazel_java_binary_impl(ctx):
@@ -100,9 +112,11 @@ def bazel_base_binary_impl(ctx, is_test_rule_class):
100112

101113
runfiles = default_info.runfiles
102114

115+
toolchain_files = depset()
103116
if executable:
104117
runtime_toolchain = semantics.find_java_runtime_toolchain(ctx)
105-
runfiles = runfiles.merge(ctx.runfiles(transitive_files = runtime_toolchain.files))
118+
toolchain_files = runtime_toolchain.files
119+
runfiles = runfiles.merge(ctx.runfiles(transitive_files = toolchain_files))
106120

107121
test_support = helper.get_test_support(ctx)
108122
if test_support:
@@ -114,6 +128,8 @@ def bazel_base_binary_impl(ctx, is_test_rule_class):
114128
executable = default_info.executable,
115129
)
116130

131+
_add_runfiles_group_provider(providers, ctx, java_attrs, executable, toolchain_files, test_support)
132+
117133
info = providers.pop("InternalDeployJarInfo")
118134
create_deploy_archives(
119135
ctx,
@@ -128,6 +144,52 @@ def bazel_base_binary_impl(ctx, is_test_rule_class):
128144

129145
return providers.values()
130146

147+
def _add_runfiles_group_provider(providers, ctx, java_attrs, executable, toolchain_files, test_support):
148+
if not runfiles_groups_enabled(ctx):
149+
return
150+
151+
own = [runfiles_groups.entry(
152+
name = ctx.label,
153+
content = java_attrs.runtime_jars,
154+
kind = own_kind(ctx.label),
155+
rank = runfiles_groups.RANK_EXECUTABLE,
156+
merge_affinity = MERGE_AFFINITY,
157+
)]
158+
159+
executable_group = None
160+
if executable:
161+
# toolchain_files is only populated for a target with an executable.
162+
own.append(runfiles_groups.entry(
163+
name = JAVA_RUNTIME_GROUP,
164+
content = toolchain_files,
165+
kind = "foundation",
166+
rank = runfiles_groups.RANK_FOUNDATION,
167+
do_not_merge = True,
168+
merge_affinity = MERGE_AFFINITY,
169+
))
170+
own.append(runfiles_groups.entry(
171+
name = BINARY_GROUP,
172+
content = depset([executable]),
173+
kind = own_kind(ctx.label),
174+
rank = runfiles_groups.RANK_EXECUTABLE,
175+
merge_affinity = MERGE_AFFINITY,
176+
))
177+
executable_group = BINARY_GROUP
178+
179+
deps = [ctx.attr.deps, ctx.attr.runtime_deps]
180+
if test_support:
181+
deps.append(test_support)
182+
183+
providers["RunfilesGroupInfo"] = RunfilesGroupInfo(
184+
entries = collect_entries(
185+
ctx,
186+
deps = deps,
187+
data = [getattr(ctx.attr, "data", [])],
188+
own = own,
189+
),
190+
executable_group = executable_group,
191+
)
192+
131193
def _get_coverage_runner(ctx):
132194
if ctx.configuration.coverage_enabled and ctx.attr.create_executable:
133195
toolchain = semantics.find_java_toolchain(ctx)
@@ -370,6 +432,7 @@ logic as the Java package of source files. For example, a source file at
370432
executable = True,
371433
),
372434
} if not bazel_features.rules._has_launcher_maker_toolchain else {},
435+
RUNFILES_GROUP_ATTRS,
373436
)
374437

375438
def make_java_binary(executable):

java/bazel/rules/bazel_java_import.bzl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ Definition of java_import rule.
1818

1919
load("//java/common:java_semantics.bzl", "semantics")
2020
load("//java/common/rules:java_import.bzl", "JAVA_IMPORT_ATTRS")
21+
load("//java/common/rules:rule_util.bzl", "merge_attrs")
2122
load("//java/common/rules/impl:bazel_java_import_impl.bzl", "bazel_java_import_rule")
23+
load("//java/common/rules/impl:runfiles_group_support.bzl", "RUNFILES_GROUP_ATTRS")
2224
load("//java/private:java_info.bzl", "JavaInfo")
2325

2426
def _proxy(ctx):
@@ -33,6 +35,7 @@ def _proxy(ctx):
3335
ctx.files.proguard_specs,
3436
ctx.attr.add_exports,
3537
ctx.attr.add_opens,
38+
runfiles_weight = ctx.attr.runfiles_weight,
3639
).values()
3740

3841
java_import = rule(
@@ -59,7 +62,7 @@ java_import = rule(
5962
</code>
6063
</pre>
6164
""",
62-
attrs = JAVA_IMPORT_ATTRS,
65+
attrs = merge_attrs(JAVA_IMPORT_ATTRS, RUNFILES_GROUP_ATTRS),
6366
provides = [JavaInfo],
6467
fragments = ["java", "cpp"],
6568
toolchains = [semantics.JAVA_TOOLCHAIN],

java/bazel/rules/bazel_java_library.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ Definition of java_library rule.
1919
load("//java/common:java_semantics.bzl", "semantics")
2020
load("//java/common/rules:android_lint.bzl", "android_lint_subrule")
2121
load("//java/common/rules:java_library.bzl", "JAVA_LIBRARY_ATTRS")
22+
load("//java/common/rules:rule_util.bzl", "merge_attrs")
2223
load("//java/common/rules/impl:bazel_java_library_impl.bzl", "bazel_java_library_rule")
24+
load("//java/common/rules/impl:runfiles_group_support.bzl", "RUNFILES_GROUP_ATTRS")
2325
load("//java/private:java_info.bzl", "JavaInfo")
2426

2527
def _proxy(ctx):
@@ -53,7 +55,7 @@ java_library = rule(
5355
jar").</li>
5456
</ul>
5557
""",
56-
attrs = JAVA_LIBRARY_ATTRS,
58+
attrs = merge_attrs(JAVA_LIBRARY_ATTRS, RUNFILES_GROUP_ATTRS),
5759
provides = [JavaInfo],
5860
outputs = {
5961
"classjar": "lib%{name}.jar",

java/common/rules/impl/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ bzl_library(
2323
"//java/common:proguard_spec_info_bzl",
2424
"@com_google_protobuf//bazel/common:proto_info_bzl",
2525
"@rules_cc//cc/common:cc_helper_bzl",
26+
"@rules_runfiles_group//runfiles_group:lib",
27+
"@rules_runfiles_group//runfiles_group:providers",
2628
],
2729
)
2830

java/common/rules/impl/bazel_java_import_impl.bzl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ Definition of java_import rule.
1717
"""
1818

1919
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
20+
load("@rules_runfiles_group//runfiles_group:lib.bzl", "runfiles_groups")
21+
load("@rules_runfiles_group//runfiles_group:providers.bzl", "RunfilesGroupInfo")
2022
load("//java/common:java_semantics.bzl", "semantics")
2123
load("//java/common/rules/impl:basic_java_library_impl.bzl", "construct_defaultinfo")
2224
load("//java/common/rules/impl:import_deps_check.bzl", "import_deps_check")
25+
load("//java/common/rules/impl:runfiles_group_support.bzl", "MERGE_AFFINITY", "collect_entries", "runfiles_groups_enabled")
2326
load("//java/private:java_common.bzl", "java_common")
2427
load("//java/private:java_common_internal.bzl", _run_ijar_private_for_builtins = "run_ijar")
2528
load("//java/private:java_info.bzl", "JavaInfo")
@@ -85,7 +88,8 @@ def bazel_java_import_rule(
8588
add_exports = [],
8689
add_opens = [],
8790
permit_exports = True,
88-
skip_incomplete_deps_check = True):
91+
skip_incomplete_deps_check = True,
92+
runfiles_weight = 0):
8993
"""Implements java_import.
9094
9195
This rule allows the use of precompiled .jar files as libraries in other Java rules.
@@ -103,6 +107,7 @@ def bazel_java_import_rule(
103107
add_opens: (list[str]) Allow this library to reflectively access the given <module>/<package>.
104108
permit_exports: (bool) Allow using exports
105109
skip_incomplete_deps_check: (bool) If this target is allowed to have incomplete deps
110+
runfiles_weight: (int) Weight hint for the target's runfiles group entry. If > 0, set as weight.
106111
107112
Returns:
108113
(list[provider]) A list containing DefaultInfo, JavaInfo,
@@ -182,4 +187,26 @@ def bazel_java_import_rule(
182187
"_hidden_top_level_INTERNAL_": target["ProguardSpecProvider"].specs,
183188
}
184189
)
190+
191+
if not neverlink:
192+
_add_runfiles_group_provider(target, ctx, collected_jars, deps, exports, runtime_deps, runfiles_weight = runfiles_weight)
193+
185194
return target
195+
196+
def _add_runfiles_group_provider(target, ctx, own_jars, deps, exports, runtime_deps, runfiles_weight = 0):
197+
if not runfiles_groups_enabled(ctx):
198+
return
199+
200+
target["RunfilesGroupInfo"] = RunfilesGroupInfo(entries = collect_entries(
201+
ctx,
202+
deps = [deps, exports, runtime_deps],
203+
data = [getattr(ctx.attr, "data", [])],
204+
own = [runfiles_groups.entry(
205+
name = ctx.label,
206+
content = depset(own_jars),
207+
kind = "third_party",
208+
rank = runfiles_groups.RANK_SHARED_DEPS,
209+
weight = runfiles_weight if runfiles_weight > 0 else None,
210+
merge_affinity = MERGE_AFFINITY,
211+
)],
212+
))

java/common/rules/impl/bazel_java_library_impl.bzl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
Definition of java_library rule.
1717
"""
1818

19+
load("@rules_runfiles_group//runfiles_group:lib.bzl", "runfiles_groups")
20+
load("@rules_runfiles_group//runfiles_group:providers.bzl", "RunfilesGroupInfo")
1921
load("//java/common/rules/impl:basic_java_library_impl.bzl", "basic_java_library", "construct_defaultinfo")
22+
load("//java/common/rules/impl:runfiles_group_support.bzl", "MERGE_AFFINITY", "collect_entries", "own_kind", "runfiles_groups_enabled")
2023

2124
# copybara: default visibility
2225

@@ -98,4 +101,23 @@ def bazel_java_library_rule(
98101
)
99102
target["OutputGroupInfo"] = OutputGroupInfo(**base_info.output_groups)
100103

104+
if not neverlink:
105+
_add_runfiles_group_provider(target, ctx, base_info.runfiles, deps, exports, runtime_deps)
106+
101107
return target
108+
109+
def _add_runfiles_group_provider(target, ctx, own_runfiles, deps, exports, runtime_deps):
110+
if not runfiles_groups_enabled(ctx):
111+
return
112+
113+
target["RunfilesGroupInfo"] = RunfilesGroupInfo(entries = collect_entries(
114+
ctx,
115+
deps = [deps, exports, runtime_deps],
116+
data = [getattr(ctx.attr, "data", [])],
117+
own = [runfiles_groups.entry(
118+
name = ctx.label,
119+
content = depset(own_runfiles),
120+
kind = own_kind(ctx.label),
121+
merge_affinity = MERGE_AFFINITY,
122+
)],
123+
))

0 commit comments

Comments
 (0)