Build bootclasspath in a UTF-8 environment Copybara Import from https://github.com/bazelbuild/rules_java/pull/243 BEGIN_PUBLIC Build bootclasspath in a UTF-8 environment (#243) `java` and `javac` convert file and classpaths to absolute paths and thus require a UTF-8 locale to work under a path that contains non-ASCII characters. Unblocks https://github.com/bazelbuild/bazel/pull/24457 Closes #243 END_PUBLIC COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_java/pull/243 from fmeum:utf8-environment 05813e491f73a167bf5c7d5e723d2417649f3867 PiperOrigin-RevId: 700695134 Change-Id: I2f5753720ec3c838a4dd8b6aabf1050c6935ef3d
diff --git a/MODULE.bazel b/MODULE.bazel index 706c277..b14fcbf 100644 --- a/MODULE.bazel +++ b/MODULE.bazel
@@ -97,6 +97,7 @@ bazel_dep(name = "rules_pkg", version = "0.9.1", dev_dependency = True) bazel_dep(name = "stardoc", version = "0.7.1", dev_dependency = True) bazel_dep(name = "rules_shell", version = "0.2.0", dev_dependency = True) +bazel_dep(name = "rules_testing", version = "0.7.0", dev_dependency = True) test_repositories = use_extension("//test:repositories.bzl", "test_repositories_ext", dev_dependency = True) use_repo(test_repositories, "guava", "truth")
diff --git a/WORKSPACE b/WORKSPACE index d5e6a7e..161fa9c 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -53,6 +53,13 @@ stardoc_repositories() +http_archive( + name = "rules_testing", + sha256 = "28c2d174471b587bf0df1fd3a10313f22c8906caf4050f8b46ec4648a79f90c3", + strip_prefix = "rules_testing-0.7.0", + url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.7.0/rules_testing-v0.7.0.tar.gz", +) + load("//test:repositories.bzl", "test_repositories") test_repositories()
diff --git a/test/analysis/BUILD.bazel b/test/analysis/BUILD.bazel new file mode 100644 index 0000000..754e1dd --- /dev/null +++ b/test/analysis/BUILD.bazel
@@ -0,0 +1,5 @@ +load(":bootclasspath_tests.bzl", "bootclasspath_tests") + +bootclasspath_tests( + name = "bootclasspath_tests", +)
diff --git a/test/analysis/bootclasspath_tests.bzl b/test/analysis/bootclasspath_tests.bzl new file mode 100644 index 0000000..c862d83 --- /dev/null +++ b/test/analysis/bootclasspath_tests.bzl
@@ -0,0 +1,25 @@ +"""Tests for the bootclasspath rule.""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "subjects") + +def _test_utf_8_environment(name): + analysis_test( + name = name, + impl = _test_utf_8_environment_impl, + target = Label("//toolchains:platformclasspath"), + ) + +def _test_utf_8_environment_impl(env, target): + for action in target.actions: + env_subject = env.expect.where(action = action).that_dict(action.env) + env_subject.keys().contains("LC_CTYPE") + env_subject.get("LC_CTYPE", factory = subjects.str).contains("UTF-8") + +def bootclasspath_tests(name): + test_suite( + name = name, + tests = [ + _test_utf_8_environment, + ], + )
diff --git a/toolchains/BUILD b/toolchains/BUILD index 191c311..ffbffc4 100644 --- a/toolchains/BUILD +++ b/toolchains/BUILD
@@ -15,6 +15,7 @@ "java_runtime_version_alias", "java_toolchain_alias", ) +load(":utf8_environment.bzl", "utf8_environment") package(default_visibility = ["//visibility:public"]) @@ -282,6 +283,11 @@ }), ) +utf8_environment( + name = "utf8_environment", + visibility = ["//visibility:private"], +) + bootclasspath( name = "platformclasspath", src = "DumpPlatformClassPath.java",
diff --git a/toolchains/default_java_toolchain.bzl b/toolchains/default_java_toolchain.bzl index a6d200b..75d05f7 100644 --- a/toolchains/default_java_toolchain.bzl +++ b/toolchains/default_java_toolchain.bzl
@@ -16,6 +16,7 @@ load("//java/common:java_common.bzl", "java_common") load("//java/toolchains:java_toolchain.bzl", "java_toolchain") +load(":utf8_environment.bzl", "Utf8EnvironmentInfo") # JVM options, without patching java.compiler and jdk.compiler modules. BASE_JDK9_JVM_OPTS = [ @@ -223,6 +224,7 @@ def _bootclasspath_impl(ctx): exec_javabase = ctx.attr.java_runtime_alias[java_common.JavaRuntimeInfo] + env = ctx.attr._utf8_environment[Utf8EnvironmentInfo].environment class_dir = ctx.actions.declare_directory("%s_classes" % ctx.label.name) @@ -243,6 +245,7 @@ inputs = [ctx.file.src] + ctx.files.java_runtime_alias, outputs = [class_dir], arguments = [args], + env = env, execution_requirements = _SUPPORTS_PATH_MAPPING, ) @@ -281,6 +284,7 @@ inputs = inputs, outputs = [bootclasspath], arguments = [args], + env = env, execution_requirements = _SUPPORTS_PATH_MAPPING, ) return [ @@ -304,6 +308,10 @@ cfg = "exec", allow_single_file = True, ), + "_utf8_environment": attr.label( + default = ":utf8_environment", + cfg = "exec", + ), }, toolchains = [_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE], )
diff --git a/toolchains/utf8_environment.bzl b/toolchains/utf8_environment.bzl new file mode 100644 index 0000000..5b4d554 --- /dev/null +++ b/toolchains/utf8_environment.bzl
@@ -0,0 +1,48 @@ +# Copyright 2024 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Determines the environment required for Java actions to support UTF-8. +""" + +visibility("private") + +Utf8EnvironmentInfo = provider( + doc = "The environment required for Java actions to support UTF-8.", + fields = { + "environment": "The environment to use for Java actions to support UTF-8.", + }, +) + +# The default UTF-8 locale on all recent Linux distributions. It is also available in Cygwin and +# MSYS2, but doesn't matter for determining the JVM's platform encoding on Windows, which always +# uses the active code page. +_DEFAULT_UTF8_ENVIRONMENT = Utf8EnvironmentInfo(environment = {"LC_CTYPE": "C.UTF-8"}) + +# macOS doesn't have the C.UTF-8 locale, but en_US.UTF-8 is available and works the same way. +_MACOS_UTF8_ENVIRONMENT = Utf8EnvironmentInfo(environment = {"LC_CTYPE": "en_US.UTF-8"}) + +def _utf8_environment_impl(ctx): + if ctx.target_platform_has_constraint(ctx.attr._macos_constraint[platform_common.ConstraintValueInfo]): + return _MACOS_UTF8_ENVIRONMENT + else: + return _DEFAULT_UTF8_ENVIRONMENT + +utf8_environment = rule( + _utf8_environment_impl, + attrs = { + "_macos_constraint": attr.label(default = "@platforms//os:macos"), + }, + doc = "Returns a suitable environment for Java actions to support UTF-8.", +)