Skip to content

Commit

Permalink
Build bootclasspath in a UTF-8 environment
Browse files Browse the repository at this point in the history
Copybara Import from #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 bazelbuild/bazel#24457

Closes #243
END_PUBLIC

COPYBARA_INTEGRATE_REVIEW=#243 from fmeum:utf8-environment 05813e4
PiperOrigin-RevId: 700695134
Change-Id: I2f5753720ec3c838a4dd8b6aabf1050c6935ef3d
  • Loading branch information
fmeum authored and rules_java Copybara committed Nov 27, 2024
1 parent 6b37b15 commit c22454f
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ use_repo(compat, "compatibility_proxy")
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")
7 changes: 7 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ load("@stardoc//:setup.bzl", "stardoc_repositories")

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()
5 changes: 5 additions & 0 deletions test/analysis/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
load(":bootclasspath_tests.bzl", "bootclasspath_tests")

bootclasspath_tests(
name = "bootclasspath_tests",
)
25 changes: 25 additions & 0 deletions test/analysis/bootclasspath_tests.bzl
Original file line number Diff line number Diff line change
@@ -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,
],
)
6 changes: 6 additions & 0 deletions toolchains/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ load(
"java_runtime_version_alias",
"java_toolchain_alias",
)
load(":utf8_environment.bzl", "utf8_environment")

package(default_visibility = ["//visibility:public"])

Expand Down Expand Up @@ -282,6 +283,11 @@ alias(
}),
)

utf8_environment(
name = "utf8_environment",
visibility = ["//visibility:private"],
)

bootclasspath(
name = "platformclasspath",
src = "DumpPlatformClassPath.java",
Expand Down
8 changes: 8 additions & 0 deletions toolchains/default_java_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -223,6 +224,7 @@ def _java_home(java_executable):

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)

Expand All @@ -243,6 +245,7 @@ def _bootclasspath_impl(ctx):
inputs = [ctx.file.src] + ctx.files.java_runtime_alias,
outputs = [class_dir],
arguments = [args],
env = env,
execution_requirements = _SUPPORTS_PATH_MAPPING,
)

Expand Down Expand Up @@ -281,6 +284,7 @@ def _bootclasspath_impl(ctx):
inputs = inputs,
outputs = [bootclasspath],
arguments = [args],
env = env,
execution_requirements = _SUPPORTS_PATH_MAPPING,
)
return [
Expand All @@ -304,6 +308,10 @@ _bootclasspath = rule(
cfg = "exec",
allow_single_file = True,
),
"_utf8_environment": attr.label(
default = ":utf8_environment",
cfg = "exec",
),
},
toolchains = [_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE],
)
Expand Down
48 changes: 48 additions & 0 deletions toolchains/utf8_environment.bzl
Original file line number Diff line number Diff line change
@@ -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.",
)

0 comments on commit c22454f

Please sign in to comment.