Use the `launcher_maker` toolchain if available (#294)
This avoids an unnecessary dependency on a C++ toolchain matching the target platform when not building for Windows.
Also fix the configuration of the launcher, which should be built for the target platform.
Closes #294
COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_java/pull/294 from fmeum:cross-compile-to-unix 13f097a3c541f603e091c139a4543b632382c9aa
PiperOrigin-RevId: 762307907
Change-Id: I1e172a81bd198b02032a705c459ead48b0012aea
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index 6dc8cf3..18088a2 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -42,16 +42,33 @@
flags_workspace_integration: &flags_workspace_integration
- "--noenable_bzlmod"
- "--enable_workspace"
+ # TODO(hvd): remove after Bazel 8.3.0
+ - "--repositories_without_autoloads=bazel_features_version,bazel_features_globals"
buildifier: latest
matrix:
all_platforms: ["ubuntu2004", "macos", "macos_arm64", "windows"]
- integration_platforms: ["ubuntu2004", "macos", "macos_arm64", "windows"]
bazel: ["7.6.1", "8.2.1", "last_green"] # Bazel 6 tested separately, needs different flags
- modern_bazel: ["8.2.1", "last_green"] # Fully supported Bazel versions
+ modern_bazel: ["last_green"] # Fully supported Bazel versions
tasks:
+# Bazel 9+
+ build_and_test:
+ name: "Bazel {modern_bazel}"
+ bazel: ${{ modern_bazel }}
+ platform: ${{ all_platforms }}
+ build_targets: *build_targets
+ test_targets: *test_targets
+# Bazel 8.x
+ build_and_test_bazel8:
+ name: "Bazel 8.2.1"
+ bazel: "8.2.1"
+ platform: ${{ all_platforms }}
+ build_targets: *build_targets
+ test_targets: *test_targets
+ test_flags:
+ - "--test_tag_filters=-min_bazel_9"
# Bazel 7.x
build_and_test_bazel7:
name: "Bazel 7.6.1"
@@ -60,14 +77,7 @@
build_targets: *build_targets
test_targets: *test_targets
test_flags:
- - "--test_tag_filters=-min_bazel_8"
-# Bazel 8+
- build_and_test:
- name: "Bazel {modern_bazel}"
- bazel: ${{ modern_bazel }}
- platform: ${{ all_platforms }}
- build_targets: *build_targets
- test_targets: *test_targets
+ - "--test_tag_filters=-min_bazel_8,-min_bazel_9"
# Bazel 6.x
build_and_test_bazel6:
name: "Bazel 6.5.0"
@@ -76,11 +86,11 @@
build_targets: *build_targets_bazel6
test_targets: *test_targets_bazel6
test_flags:
- - "--test_tag_filters=-min_bazel_7,-min_bazel_8"
+ - "--test_tag_filters=-min_bazel_7,-min_bazel_8,-min_bazel_9"
ubuntu2004_integration_bazel6:
name: "Integration w/ Bazel 6.5.0"
bazel: 6.5.0
- platform: ${{ integration_platforms }}
+ platform: ${{ all_platforms }}
working_directory: "test/repo"
shell_commands:
- sh setup.sh
@@ -93,7 +103,7 @@
integration_build_and_test:
name: "Integration w/ Bazel {bazel}"
bazel: ${{ bazel }}
- platform: ${{ integration_platforms }}
+ platform: ${{ all_platforms }}
working_directory: "test/repo"
shell_commands:
- sh setup.sh
@@ -104,7 +114,7 @@
integration_build_and_test_workspace:
name: "Integration (WORKSPACE) w/ Bazel {bazel}"
bazel: ${{ bazel }}
- platform: ${{ integration_platforms }}
+ platform: ${{ all_platforms }}
working_directory: "test/repo"
shell_commands:
- sh setup.sh
diff --git a/MODULE.bazel b/MODULE.bazel
index 4b70044..bcfd03a 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -7,14 +7,7 @@
bazel_dep(name = "platforms", version = "0.0.11")
bazel_dep(name = "rules_cc", version = "0.0.15")
-bazel_dep(name = "bazel_features", version = "1.28.0")
-archive_override(
- module_name = "bazel_features",
- integrity = "sha256-SOPLvKDy+RN7GHKN8eFjQ+58Wx4Isj+vcXoUluBqxLo=",
- strip_prefix = "bazel_features-59915eb2ca215c7b2266c83c49bb7522a5b6737f",
- urls = ["https://github.com/bazel-contrib/bazel_features/archive/59915eb2ca215c7b2266c83c49bb7522a5b6737f.zip"],
-)
-
+bazel_dep(name = "bazel_features", version = "1.30.0")
bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "protobuf", version = "27.0", repo_name = "com_google_protobuf")
bazel_dep(name = "zlib", version = "1.3.1.bcr.5")
diff --git a/WORKSPACE b/WORKSPACE
index 6b8beb6..acd7cae 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -41,6 +41,10 @@
rules_java_dependencies()
+load("@bazel_features//:deps.bzl", "bazel_features_deps")
+
+bazel_features_deps()
+
load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility
proto_bazel_features(name = "proto_bazel_features")
@@ -63,14 +67,3 @@
load("//test:repositories.bzl", "test_repositories")
test_repositories()
-
-http_archive(
- name = "bazel_features",
- sha256 = "48e3cbbca0f2f9137b18728df1e16343ee7c5b1e08b23faf717a1496e06ac4ba",
- strip_prefix = "bazel_features-59915eb2ca215c7b2266c83c49bb7522a5b6737f",
- url = "https://github.com/bazel-contrib/bazel_features/archive/59915eb2ca215c7b2266c83c49bb7522a5b6737f.zip",
-)
-
-load("@bazel_features//:deps.bzl", "bazel_features_deps")
-
-bazel_features_deps()
diff --git a/distro/relnotes.bzl b/distro/relnotes.bzl
index 5641bf7..ce04d50 100644
--- a/distro/relnotes.bzl
+++ b/distro/relnotes.bzl
@@ -18,6 +18,16 @@
~~~
**WORKSPACE setup**
+
+With Bazel 8.0.0 and before 8.3.0, add the following to your `.bazelrc` file:
+
+~~~
+# https://github.com/bazelbuild/bazel/pull/26119
+common --repositories_without_autoloads=bazel_features_version,bazel_features_globals
+~~~
+
+In all cases, add the following to your `WORKSPACE` file:
+
~~~
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
@@ -31,6 +41,9 @@
load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies")
rules_java_dependencies()
+load("@bazel_features//:deps.bzl", "bazel_features_deps")
+bazel_features_deps()
+
# note that the following line is what is minimally required from protobuf for the java rules
# consider using the protobuf_deps() public API from @com_google_protobuf//:protobuf_deps.bzl
load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility
diff --git a/java/bazel/rules/bazel_java_binary.bzl b/java/bazel/rules/bazel_java_binary.bzl
index def12d1..cbbe0de 100644
--- a/java/bazel/rules/bazel_java_binary.bzl
+++ b/java/bazel/rules/bazel_java_binary.bzl
@@ -13,6 +13,7 @@
# limitations under the License.
"""Bazel java_binary rule"""
+load("@bazel_features//:features.bzl", "bazel_features")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain")
load("//java/common:java_semantics.bzl", "semantics")
@@ -202,6 +203,14 @@
return ctx.actions.declare_file(executable_name)
+_LAUNCHER_MAKER_TOOLCHAIN_TYPE = "@bazel_tools//tools/launcher:launcher_maker_toolchain_type"
+_LAUNCHER_MAKER_TOOLCHAIN = config_common.toolchain_type(_LAUNCHER_MAKER_TOOLCHAIN_TYPE, mandatory = True)
+
+def _find_launcher_maker(ctx):
+ if bazel_features.rules._has_launcher_maker_toolchain:
+ return ctx.toolchains[_LAUNCHER_MAKER_TOOLCHAIN_TYPE].binary
+ return ctx.executable._windows_launcher_maker
+
def _create_stub(ctx, java_attrs, launcher, executable, jvm_flags, main_class, coverage_main_class):
java_runtime_toolchain = semantics.find_java_runtime_toolchain(ctx)
java_executable = helper.get_java_executable(ctx, java_runtime_toolchain, launcher)
@@ -282,11 +291,13 @@
# TODO(b/295221112): Change to use the "launcher" attribute (only windows use a fixed _launcher attribute)
launcher_artifact = ctx.executable._launcher
ctx.actions.run(
- executable = ctx.executable._windows_launcher_maker,
+ executable = _find_launcher_maker(ctx),
inputs = [launcher_artifact],
outputs = [executable],
arguments = [launcher_artifact.path, launch_info, executable.path],
use_default_shell_env = True,
+ toolchain = _LAUNCHER_MAKER_TOOLCHAIN_TYPE if bazel_features.rules._has_launcher_maker_toolchain else None,
+ mnemonic = "JavaLauncherMaker",
)
return executable
@@ -308,6 +319,8 @@
provides = [JavaInfo],
toolchains = [semantics.JAVA_TOOLCHAIN] + use_cc_toolchain() + (
[semantics.JAVA_RUNTIME_TOOLCHAIN] if executable or test else []
+ ) + (
+ [_LAUNCHER_MAKER_TOOLCHAIN] if bazel_features.rules._has_launcher_maker_toolchain else []
),
# TODO(hvd): replace with filegroups?
outputs = {
@@ -340,16 +353,18 @@
),
"_test_support": attr.label(default = _compute_test_support),
"_launcher": attr.label(
- cfg = "exec",
+ cfg = "target",
executable = True,
default = "@bazel_tools//tools/launcher:launcher",
),
+ },
+ {
"_windows_launcher_maker": attr.label(
default = "@bazel_tools//tools/launcher:launcher_maker",
cfg = "exec",
executable = True,
),
- },
+ } if not bazel_features.rules._has_launcher_maker_toolchain else {},
)
def make_java_binary(executable):
diff --git a/java/rules_java_deps.bzl b/java/rules_java_deps.bzl
index 0c96d8c..b32edd2 100644
--- a/java/rules_java_deps.bzl
+++ b/java/rules_java_deps.bzl
@@ -210,6 +210,15 @@
],
)
+def bazel_features_repo():
+ maybe(
+ http_archive,
+ name = "bazel_features",
+ sha256 = "a660027f5a87f13224ab54b8dc6e191693c554f2692fcca46e8e29ee7dabc43b",
+ strip_prefix = "bazel_features-1.30.0",
+ url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.30.0/bazel_features-v1.30.0.tar.gz",
+ )
+
def rules_java_dependencies():
"""An utility method to load non-toolchain dependencies of rules_java.
@@ -223,3 +232,4 @@
zlib_repo()
absl_repo()
rules_license_repo()
+ bazel_features_repo()
diff --git a/test/java/bazel/BUILD.bazel b/test/java/bazel/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/java/bazel/BUILD.bazel
diff --git a/test/java/bazel/rules/BUILD.bazel b/test/java/bazel/rules/BUILD.bazel
new file mode 100644
index 0000000..3bf8f43
--- /dev/null
+++ b/test/java/bazel/rules/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":java_binary_tests.bzl", "java_binary_tests")
+
+java_binary_tests(name = "java_binary_tests")
diff --git a/test/java/bazel/rules/java_binary_tests.bzl b/test/java/bazel/rules/java_binary_tests.bzl
new file mode 100644
index 0000000..32036d8
--- /dev/null
+++ b/test/java/bazel/rules/java_binary_tests.bzl
@@ -0,0 +1,55 @@
+"""Tests for the Bazel java_binary rule"""
+
+load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
+load("@rules_testing//lib:util.bzl", "util")
+load("//java:java_binary.bzl", "java_binary")
+
+def _test_java_binary_cross_compilation_to_unix(name):
+ # A Unix platform that:
+ # - has a JDK
+ # - does not require a launcher
+ # - is not supported by the default C++ toolchain
+ util.helper_target(
+ native.platform,
+ name = name + "/platform",
+ constraint_values = [
+ "@platforms//os:linux",
+ "@platforms//cpu:s390x",
+ ],
+ )
+
+ util.helper_target(
+ java_binary,
+ name = name + "/bin",
+ srcs = ["java/C.java"],
+ main_class = "C",
+ )
+
+ analysis_test(
+ name = name,
+ impl = _test_java_binary_cross_compilation_to_unix_impl,
+ target = name + "/bin",
+ config_settings = {
+ "//command_line_option:platforms": [Label(name + "/platform")],
+ },
+ # Requires the launcher_maker toolchain.
+ attr_values = {"tags": ["min_bazel_9"]},
+ )
+
+def _test_java_binary_cross_compilation_to_unix_impl(env, target):
+ # The main assertion is that analysis succeeds, but verify the absence of a
+ # binary launcher for good measure. We do this by checking that the output
+ # executable is the stub script, and not a bespoke launcher
+ executable = target[DefaultInfo].files_to_run.executable.short_path
+ assert_action = env.expect.that_target(target).action_generating(executable)
+ assert_action.mnemonic().equals("TemplateExpand")
+ assert_action.substitutions().keys().contains("%jvm_flags%")
+ assert_action.inputs().contains_exactly(["java/bazel/rules/java_stub_template.txt"])
+
+def java_binary_tests(name):
+ test_suite(
+ name = name,
+ tests = [
+ _test_java_binary_cross_compilation_to_unix,
+ ],
+ )
diff --git a/test/repo/WORKSPACE b/test/repo/WORKSPACE
index eb68085..c272975 100644
--- a/test/repo/WORKSPACE
+++ b/test/repo/WORKSPACE
@@ -9,6 +9,10 @@
rules_java_dependencies()
+load("@bazel_features//:deps.bzl", "bazel_features_deps")
+
+bazel_features_deps()
+
load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility
proto_bazel_features(name = "proto_bazel_features")