Propagate `.jdeps` for `java_import` (#363) Downstream Java compilation actions need accurate `.jdeps` files for their reduced classpath optimization. With this change, `java_import` now always runs `ImportDepsChecker` to generate this file, but possibly suppresses its outputs. Note that Bazel (but not Blaze) always silences the output. Fixes #362 Closes #363 COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_java/pull/363 from fmeum:java-import-reduced-classpath 5daac7d7ba1eeb7016d5a2921bdd58d93722c586 PiperOrigin-RevId: 974359803 Change-Id: I151170f6382202f8faae0c75c52741920d45c81e
diff --git a/java/common/rules/impl/bazel_java_import_impl.bzl b/java/common/rules/impl/bazel_java_import_impl.bzl index c402fc4..aa829d1 100644 --- a/java/common/rules/impl/bazel_java_import_impl.bzl +++ b/java/common/rules/impl/bazel_java_import_impl.bzl
@@ -115,16 +115,23 @@ collected_jars = _collect_jars(ctx, jars) all_deps = _filter_provider(JavaInfo, deps, exports) - jdeps_artifact = None merged_java_info = java_common.merge(all_deps) - if not skip_incomplete_deps_check and "incomplete-deps" not in ctx.attr.tags: - jdeps_artifact = import_deps_check( - ctx, - collected_jars, - merged_java_info.compile_jars, - merged_java_info.transitive_compile_time_jars, - "java_import", - ) + + # import_deps_check is always run to generate the jdeps proto for downstream compile actions, + # but may be silenced. + has_incomplete_deps = "incomplete-deps" in ctx.attr.tags + if skip_incomplete_deps_check or has_incomplete_deps: + checking_mode = "silence" + else: + checking_mode = "error" + jdeps_artifact = import_deps_check( + ctx, + collected_jars, + merged_java_info.compile_jars, + merged_java_info.transitive_compile_time_jars, + "java_import", + checking_mode = checking_mode, + ) compilation_to_runtime_jar_map = _process_with_ijars_if_needed(collected_jars, ctx) runtime_deps_list = [runtime_dep[JavaInfo] for runtime_dep in runtime_deps if JavaInfo in runtime_dep] @@ -134,6 +141,7 @@ java_infos.append(JavaInfo( output_jar = jar, compile_jar = compilation_to_runtime_jar_map[jar], + compile_jdeps = jdeps_artifact, deps = all_deps, runtime_deps = runtime_deps_list, neverlink = neverlink, @@ -169,7 +177,7 @@ output_group_src_jars = depset() if srcjar == None else depset([srcjar]) validation_group = [] - if jdeps_artifact != None: + if jdeps_artifact != None and checking_mode != "silence": validation_group.append(jdeps_artifact) if srcjar != None: validation_group.append(srcjar)
diff --git a/java/common/rules/impl/import_deps_check.bzl b/java/common/rules/impl/import_deps_check.bzl index 69dec8b..f5a950f 100644 --- a/java/common/rules/impl/import_deps_check.bzl +++ b/java/common/rules/impl/import_deps_check.bzl
@@ -23,7 +23,8 @@ jars_to_check, declared_deps, transitive_deps, - rule_class): + rule_class, + checking_mode = "error"): """ Creates actions that checks import deps for java rules. @@ -33,6 +34,7 @@ declared_deps: (list[File]) A list of direct dependencies. transitive_deps: (list[File]) A list of transitive dependencies. rule_class: (String) Rule class. + checking_mode: (String) One of "error", "warning" or "silence". Returns: (File) Output file of the created action. @@ -53,9 +55,11 @@ before_each = "--classpath_entry", ) args.add_all(java_toolchain.bootclasspath, before_each = "--bootclasspath_entry") - args.add("--checking_mode=error") + args.add(checking_mode, format = "--checking_mode=%s") args.add("--jdeps_output", jdeps_output) - args.add("--rule_label", ctx.label) + + # ctx.label can start with an @ and must not be understood as a flagfile. + args.add(ctx.label, format = "--rule_label=%s") semantics.update_args_for_import_deps(ctx, args) inputs = depset(
diff --git a/test/java/bazel/rules/BUILD.bazel b/test/java/bazel/rules/BUILD.bazel index 6f97d15..09c1f1a 100644 --- a/test/java/bazel/rules/BUILD.bazel +++ b/test/java/bazel/rules/BUILD.bazel
@@ -1,10 +1,13 @@ load(":java_binary_tests.bzl", "java_binary_tests") +load(":java_import_tests.bzl", "java_import_tests") load(":java_library_tests.bzl", "java_library_tests") load(":java_plugin_tests.bzl", "java_plugin_tests") load(":java_test_tests.bzl", "java_test_tests") java_binary_tests(name = "java_binary_tests") +java_import_tests(name = "java_import_tests") + java_library_tests(name = "java_library_tests") java_plugin_tests(name = "java_plugin_tests")
diff --git a/test/java/bazel/rules/java_import_tests.bzl b/test/java/bazel/rules/java_import_tests.bzl new file mode 100644 index 0000000..8ea3ff2 --- /dev/null +++ b/test/java/bazel/rules/java_import_tests.bzl
@@ -0,0 +1,42 @@ +"""Tests for the Bazel java_import rule""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_import.bzl", "java_import") + +def _test_import_deps_checker_checking_mode(name): + util.helper_target( + java_import, + name = name + "/import-jar", + jars = ["import.jar"], + deps = [name + "/depjar"], + ) + util.helper_target( + java_import, + name = name + "/depjar", + jars = ["depjar.jar"], + ) + + analysis_test( + name = name, + impl = _test_import_deps_checker_checking_mode_impl, + target = name + "/import-jar", + # The rules_java Starlark implementation is used from Bazel 8 on. + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_import_deps_checker_checking_mode_impl(env, target): + # java_import only generates the jdeps proto, it never fails the build on incomplete deps. + assert_action = env.expect.that_target(target).action_named("ImportDepsChecker") + assert_action.contains_flag_values([ + ("--checking_mode", "silence"), + ("--rule_label", "//{package}:{name}"), + ]) + +def java_import_tests(name): + test_suite( + name = name, + tests = [ + _test_import_deps_checker_checking_mode, + ], + )
diff --git a/test/java/common/rules/java_import_tests.bzl b/test/java/common/rules/java_import_tests.bzl index 35b713d..c74bd3d 100644 --- a/test/java/common/rules/java_import_tests.bzl +++ b/test/java/common/rules/java_import_tests.bzl
@@ -178,6 +178,51 @@ "{package}/depjar.jar", ]) +# Regression test for https://github.com/bazelbuild/rules_java/issues/362: every java_import +# records a jdeps proto as its compile_jdeps so that reduced classpaths of downstream compilations +# are not missing its transitive dependencies. +def _test_compile_jdeps_propagated_for_deps(name): + util.helper_target( + java_import, + name = name + "/import-jar", + jars = ["import.jar"], + deps = [name + "/depjar"], + ) + util.helper_target( + java_import, + name = name + "/incomplete-jar", + jars = ["incomplete.jar"], + deps = [name + "/depjar"], + tags = ["incomplete-deps"], + ) + util.helper_target( + java_import, + name = name + "/depjar", + jars = ["depjar.jar"], + ) + + analysis_test( + name = name, + impl = _test_compile_jdeps_propagated_for_deps_impl, + targets = { + "incomplete_deps": name + "/incomplete-jar", + "with_deps": name + "/import-jar", + "without_deps": name + "/depjar", + }, + # The rules_java Starlark implementation is used from Bazel 8 on. + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_compile_jdeps_propagated_for_deps_impl(env, targets): + for name in ["with_deps", "without_deps", "incomplete_deps"]: + java_info_subject.from_target( + env, + getattr(targets, name), + expr = name, + ).compilation_args().compile_time_java_dependencies().contains_exactly([ + "{package}/_java_import/{name}/jdeps.proto", + ]) + # Regression test for b/262751943. def _test_commandline_contains_target_label(name): util.helper_target( @@ -959,6 +1004,7 @@ _test_simple, _test_with_java_library, _test_deps, + _test_compile_jdeps_propagated_for_deps, _test_commandline_contains_target_label, _test_java_library_allows_import_in_deps, _test_module_flags,
diff --git a/test/java/testutil/java_info_subject.bzl b/test/java/testutil/java_info_subject.bzl index 9a0fb53..8df4f78 100644 --- a/test/java/testutil/java_info_subject.bzl +++ b/test/java/testutil/java_info_subject.bzl
@@ -31,8 +31,9 @@ ) return public -def _java_info_subject_from_target(env, target): +def _java_info_subject_from_target(env, target, expr = None): return _new_java_info_subject(target[JavaInfo], meta = truth.expect(env).meta.derive( + expr = expr, format_str_kwargs = { "name": target.label.name, "package": target.label.package,
diff --git a/toolchains/default_java_toolchain.bzl b/toolchains/default_java_toolchain.bzl index e4097ae..f131a62 100644 --- a/toolchains/default_java_toolchain.bzl +++ b/toolchains/default_java_toolchain.bzl
@@ -76,6 +76,7 @@ # Default java_toolchain parameters _BASE_TOOLCHAIN_CONFIGURATION = dict( + deps_checker = Label("@remote_java_tools//:ImportDepsChecker"), forcibly_disable_header_compilation = False, genclass = Label("@remote_java_tools//:GenClass"), header_compiler = Label("@remote_java_tools//:TurbineDirect"),