diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java index d74b95af8c2f52..1e6215256cc94b 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java @@ -54,6 +54,7 @@ import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel; import com.google.devtools.build.lib.rules.java.JavaHelper; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider; +import com.google.devtools.build.lib.rules.java.JavaRuntimeInfo; import com.google.devtools.build.lib.rules.java.JavaSemantics; import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider; import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; @@ -532,6 +533,9 @@ public Iterable getJvmFlags( if (testClass == null) { ruleContext.ruleError("cannot determine test class"); } else { + if (JavaRuntimeInfo.from(ruleContext).version() >= 17) { + jvmFlags.add("-Djava.security.manager=allow"); + } // Always run junit tests with -ea (enable assertion) jvmFlags.add("-ea"); // "suite" is a misnomer. diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE.tmpl b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE.tmpl index e4132727095c69..91365fc3f1a569 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE.tmpl +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE.tmpl @@ -1,6 +1,7 @@ # External dependencies for the java_* rules. load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@bazel_tools//tools/jdk:jdk_build_file.bzl", "JDK_BUILD_TEMPLATE") load("@bazel_tools//tools/jdk:local_java_repository.bzl", "local_java_repository") load("@bazel_tools//tools/jdk:remote_java_repository.bzl", "remote_java_repository") @@ -8,7 +9,7 @@ maybe( local_java_repository, name = "local_jdk", java_home = DEFAULT_SYSTEM_JAVABASE, - build_file = "@bazel_tools//tools/jdk:jdk.BUILD", + build_file_content = JDK_BUILD_TEMPLATE, ) # OpenJDK distributions that should only be downloaded on demand (e.g. when diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java index b77cd763b771a0..61b359746d5009 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.rules.java; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.devtools.build.lib.packages.Type.INTEGER; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -116,7 +117,9 @@ public ConfiguredTarget create(RuleContext ruleContext) javaBinaryRunfilesPath, hermeticInputs, libModules, - hermeticStaticLibs); + defaultCDS, + hermeticStaticLibs, + ruleContext.attributes().get("version", INTEGER).toIntUnchecked()); TemplateVariableInfo templateVariableInfo = new TemplateVariableInfo( diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java index a1fdf3c2ca1182..d4a15ea99bf285 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java @@ -51,7 +51,9 @@ public static JavaRuntimeInfo create( PathFragment javaBinaryRunfilesPath, NestedSet hermeticInputs, @Nullable Artifact libModules, - ImmutableList hermeticStaticLibs) { + @Nullable Artifact defaultCDS, + ImmutableList hermeticStaticLibs, + int version) { return new JavaRuntimeInfo( javaBaseInputs, javaHome, @@ -60,7 +62,9 @@ public static JavaRuntimeInfo create( javaBinaryRunfilesPath, hermeticInputs, libModules, - hermeticStaticLibs); + defaultCDS, + hermeticStaticLibs, + version); } @Override @@ -124,6 +128,7 @@ private static JavaRuntimeInfo from(RuleContext ruleContext, ToolchainInfo toolc private final NestedSet hermeticInputs; @Nullable private final Artifact libModules; private final ImmutableList hermeticStaticLibs; + private final int version; private JavaRuntimeInfo( NestedSet javaBaseInputs, @@ -133,7 +138,9 @@ private JavaRuntimeInfo( PathFragment javaBinaryRunfilesPath, NestedSet hermeticInputs, @Nullable Artifact libModules, - ImmutableList hermeticStaticLibs) { + @Nullable Artifact defaultCDS, + ImmutableList hermeticStaticLibs, + int version) { this.javaBaseInputs = javaBaseInputs; this.javaHome = javaHome; this.javaBinaryExecPath = javaBinaryExecPath; @@ -142,6 +149,7 @@ private JavaRuntimeInfo( this.hermeticInputs = hermeticInputs; this.libModules = libModules; this.hermeticStaticLibs = hermeticStaticLibs; + this.version = version; } /** All input artifacts in the javabase. */ @@ -223,6 +231,11 @@ public Depset starlarkJavaBaseInputs() { return Depset.of(Artifact.TYPE, javaBaseInputs()); } + @Override + public int version() { + return version; + } + @Override public com.google.devtools.build.lib.packages.Provider getProvider() { return PROVIDER; diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java index 5c0378771884cf..eb2cb2b4cc84bc 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java @@ -18,6 +18,7 @@ import static com.google.devtools.build.lib.packages.BuildType.LABEL; import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; import static com.google.devtools.build.lib.packages.BuildType.LICENSE; +import static com.google.devtools.build.lib.packages.Type.INTEGER; import static com.google.devtools.build.lib.packages.Type.STRING; import com.google.devtools.build.lib.analysis.BaseRuleClasses; @@ -72,6 +73,11 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) */ .add(attr("java_home", STRING)) .add(attr("output_licenses", LICENSE)) + /* + The feature version of the Java runtime. I.e., the integer returned by + Runtime.version().feature(). + */ + .add(attr("version", INTEGER)) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java index aa195cfe367238..b5199849952df2 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaRuntimeInfoApi.java @@ -95,4 +95,11 @@ public interface JavaRuntimeInfoApi extends StructApi { doc = "Returns the JDK static libraries.", structField = true) Sequence starlarkHermeticStaticLibs(); + + /** The Java feature version of the runtime. This is 0 if the version is unknown. */ + @StarlarkMethod( + name = "version", + doc = "The Java feature version of the runtime. This is 0 if the version is unknown.", + structField = true) + int version(); } diff --git a/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary.bzl b/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary.bzl new file mode 100644 index 00000000000000..4f910cccfa25a3 --- /dev/null +++ b/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary.bzl @@ -0,0 +1,346 @@ +# Copyright 2022 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. + +load(":common/rule_util.bzl", "merge_attrs") +load(":common/java/java_util.bzl", "shell_quote") +load(":common/java/java_semantics.bzl", "semantics") +load(":common/cc/cc_helper.bzl", "cc_helper") +load(":common/java/java_helper.bzl", helper = "util") +load(":common/java/java_binary.bzl", "BASE_TEST_ATTRIBUTES", "BASIC_JAVA_BINARY_ATTRIBUTES", "basic_java_binary") +load(":common/paths.bzl", "paths") + +JavaInfo = _builtins.toplevel.JavaInfo + +def _bazel_java_binary_impl(ctx): + deps = _collect_all_targets_as_deps(ctx, classpath_type = "compile_only") + runtime_deps = _collect_all_targets_as_deps(ctx) + + main_class = _check_and_get_main_class(ctx) + coverage_main_class = main_class + coverage_config = helper.get_coverage_config(ctx) + if coverage_config: + main_class = coverage_config.main_class + + launcher_info = _get_launcher_info(ctx) + + executable = _get_executable(ctx) + + feature_config = helper.get_feature_config(ctx) + strip_as_default = helper.should_strip_as_default(ctx, feature_config) + + providers, default_info, jvm_flags = basic_java_binary( + ctx, + deps, + runtime_deps, + ctx.files.resources, + main_class, + coverage_main_class, + coverage_config, + launcher_info, + executable, + feature_config, + strip_as_default, + ) + + if ctx.attr.use_testrunner: + if semantics.find_java_runtime_toolchain(ctx).version >= 17: + jvm_flags.append("-Djava.security.manager=allow") + test_class = ctx.attr.test_class if hasattr(ctx.attr, "test_class") else "" + if test_class == "": + test_class = helper.primary_class(ctx) + if test_class == None: + fail("cannot determine test class") + jvm_flags.extend([ + "-ea", + "-Dbazel.test_suite=" + shell_quote(test_class), + ]) + + java_attrs = providers["InternalDeployJarInfo"].java_attrs + + if executable: + _create_stub(ctx, java_attrs, launcher_info.launcher, executable, jvm_flags, main_class, coverage_main_class) + + runfiles = default_info.runfiles + + test_support = helper.get_test_support(ctx) + if test_support: + runfiles = runfiles.merge(test_support[DefaultInfo].default_runfiles) + + providers["DefaultInfo"] = DefaultInfo( + files = default_info.files, + runfiles = runfiles, + executable = default_info.executable, + ) + + return providers.values() + +def _bazel_java_test_impl(ctx): + return _bazel_java_binary_impl(ctx) + helper.test_providers(ctx) + +def _collect_all_targets_as_deps(ctx, classpath_type = "all"): + deps = helper.collect_all_targets_as_deps(ctx, classpath_type = classpath_type) + + if classpath_type == "compile_only" and ctx.fragments.java.enforce_explicit_java_test_deps(): + return deps + + test_support = helper.get_test_support(ctx) + if test_support: + deps.append(test_support) + return deps + +def _check_and_get_main_class(ctx): + create_executable = ctx.attr.create_executable + main_class = _get_main_class(ctx) + + if not create_executable and main_class: + fail("main class must not be specified when executable is not created") + if create_executable and not main_class: + if not ctx.attr.srcs: + fail("need at least one of 'main_class' or Java source files") + main_class = helper.primary_class(ctx) + if main_class == None: + fail("main_class was not provided and cannot be inferred: " + + "source path doesn't include a known root (java, javatests, src, testsrc)") + + return _get_main_class(ctx) + +def _get_main_class(ctx): + if not ctx.attr.create_executable: + return None + + main_class = _get_main_class_from_rule(ctx) + + if main_class == "": + main_class = helper.primary_class(ctx) + return main_class + +def _get_main_class_from_rule(ctx): + main_class = ctx.attr.main_class + if main_class: + return main_class + if ctx.attr.use_testrunner: + return "com.google.testing.junit.runner.BazelTestRunner" + return main_class + +def _get_launcher_info(ctx): + launcher = helper.launcher_artifact_for_target(ctx) + return struct( + launcher = launcher, + unstripped_launcher = launcher, + runfiles = [], + runtime_jars = [], + jvm_flags = [], + classpath_resources = [], + ) + +def _get_executable(ctx): + if not ctx.attr.create_executable: + return None + executable_name = ctx.label.name + if helper.is_windows(ctx): + executable_name = executable_name + ".exe" + + return ctx.actions.declare_file(executable_name) + +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) + workspace_name = ctx.workspace_name + workspace_prefix = workspace_name + ("/" if workspace_name else "") + runfiles_enabled = helper.runfiles_enabled(ctx) + coverage_enabled = ctx.configuration.coverage_enabled + + test_support = helper.get_test_support(ctx) + test_support_jars = test_support[JavaInfo].transitive_runtime_jars if test_support else depset() + classpath = depset( + transitive = [ + java_attrs.runtime_classpath, + test_support_jars if ctx.fragments.java.enforce_explicit_java_test_deps() else depset(), + ], + ) + + if helper.is_windows(ctx): + jvm_flags_for_launcher = [] + for flag in jvm_flags: + jvm_flags_for_launcher.extend(ctx.tokenize(flag)) + return _create_windows_exe_launcher(ctx, java_executable, classpath, main_class, jvm_flags_for_launcher, runfiles_enabled, executable) + + if runfiles_enabled: + prefix = "" if helper.is_absolute_path(ctx, java_executable) else "${JAVA_RUNFILES}/" + java_bin = "JAVABIN=${JAVABIN:-" + prefix + java_executable + "}" + else: + java_bin = "JAVABIN=${JAVABIN:-$(rlocation " + java_executable + ")}" + + td = ctx.actions.template_dict() + td.add_joined( + "%classpath%", + classpath, + map_each = lambda file: _format_classpath_entry(runfiles_enabled, workspace_prefix, file), + join_with = ctx.configuration.host_path_separator, + format_joined = "\"%s\"", + allow_closure = True, + ) + + ctx.actions.expand_template( + template = ctx.file._stub_template, + output = executable, + substitutions = { + "%runfiles_manifest_only%": "" if runfiles_enabled else "1", + "%workspace_prefix%": workspace_prefix, + "%javabin%": java_bin, + "%needs_runfiles%": "0" if helper.is_absolute_path(ctx, java_runtime_toolchain.java_executable_exec_path) else "1", + "%set_jacoco_metadata%": "", + "%set_jacoco_main_class%": "export JACOCO_MAIN_CLASS=" + coverage_main_class if coverage_enabled else "", + "%set_jacoco_java_runfiles_root%": "export JACOCO_JAVA_RUNFILES_ROOT=${JAVA_RUNFILES}/" + workspace_prefix if coverage_enabled else "", + "%java_start_class%": shell_quote(main_class), + "%jvm_flags%": " ".join(jvm_flags), + }, + computed_substitutions = td, + is_executable = True, + ) + return executable + +def _format_classpath_entry(runfiles_enabled, workspace_prefix, file): + if runfiles_enabled: + return "${RUNPATH}" + file.short_path + + return "$(rlocation " + paths.normalize(workspace_prefix + file.short_path) + ")" + +def _create_windows_exe_launcher(ctx, java_executable, classpath, main_class, jvm_flags_for_launcher, runfiles_enabled, executable): + launch_info = ctx.actions.args().use_param_file("%s", use_always = True).set_param_file_format("multiline") + launch_info.add("binary_type=Java") + launch_info.add(ctx.workspace_name, format = "workspace_name=%s") + launch_info.add("1" if runfiles_enabled else "0", format = "symlink_runfiles_enabled=%s") + launch_info.add(java_executable, format = "java_bin_path=%s") + launch_info.add(main_class, format = "java_start_class=%s") + launch_info.add_joined(classpath, map_each = _short_path, join_with = ";", format_joined = "classpath=%s", omit_if_empty = False) + launch_info.add_joined(jvm_flags_for_launcher, join_with = "\t", format_joined = "jvm_flags=%s", omit_if_empty = False) + jar_bin_path = semantics.find_java_runtime_toolchain(ctx).java_home + "/bin/jar.exe" + launch_info.add(jar_bin_path, format = "jar_bin_path=%s") + launcher_artifact = ctx.executable._launcher + ctx.actions.run( + executable = ctx.executable._windows_launcher_maker, + inputs = [launcher_artifact], + outputs = [executable], + arguments = [launcher_artifact.path, launch_info, executable.path], + use_default_shell_env = True, + ) + return executable + +def _short_path(file): + return file.short_path + +def _compute_test_support(use_testrunner): + return Label(semantics.JAVA_TEST_RUNNER_LABEL) if use_testrunner else None + +def _compute_launcher_attr(launcher): + return launcher + +def _make_binary_rule(implementation, attrs, executable = False, test = False): + return rule( + implementation = implementation, + attrs = attrs, + executable = executable, + test = test, + fragments = ["cpp", "java"], + provides = [JavaInfo], + toolchains = [semantics.JAVA_TOOLCHAIN, semantics.JAVA_RUNTIME_TOOLCHAIN] + cc_helper.use_cpp_toolchain(), + # TODO(hvd): replace with filegroups? + outputs = { + "classjar": "%{name}.jar", + "sourcejar": "%{name}-src.jar", + "deploysrcjar": "%{name}_deploy-src.jar", + }, + exec_groups = { + "cpp_link": exec_group(toolchains = cc_helper.use_cpp_toolchain()), + }, + ) + +_BASE_BINARY_ATTRS = merge_attrs( + BASIC_JAVA_BINARY_ATTRIBUTES, + { + "_test_support": attr.label(default = _compute_test_support), + "_launcher": attr.label( + cfg = "exec", + executable = True, + default = "@bazel_tools//tools/launcher:launcher", + ), + "_windows_launcher_maker": attr.label( + default = "@bazel_tools//tools/launcher:launcher_maker", + cfg = "exec", + executable = True, + ), + }, +) + +def make_java_binary(executable, resolve_launcher_flag, has_launcher = False): + return _make_binary_rule( + _bazel_java_binary_impl, + merge_attrs( + _BASE_BINARY_ATTRS, + { + "resource_strip_prefix": attr.string(), + "_java_launcher": attr.label( + default = configuration_field( + fragment = "java", + name = "launcher", + ) if resolve_launcher_flag else (_compute_launcher_attr if has_launcher else None), + ), + }, + ({} if executable else { + "args": attr.string_list(), + "output_licenses": attr.license() if hasattr(attr, "license") else attr.string_list(), + }), + ), + executable = executable, + ) + +java_binary = make_java_binary(executable = True, resolve_launcher_flag = True) + +def make_java_test(resolve_launcher_flag, has_launcher = False): + return _make_binary_rule( + _bazel_java_test_impl, + merge_attrs( + BASE_TEST_ATTRIBUTES, + _BASE_BINARY_ATTRS, + { + "_java_launcher": attr.label( + default = configuration_field( + fragment = "java", + name = "launcher", + ) if resolve_launcher_flag else (_compute_launcher_attr if has_launcher else None), + ), + "_lcov_merger": attr.label( + cfg = "exec", + default = configuration_field( + fragment = "coverage", + name = "output_generator", + ), + ), + "_collect_cc_coverage": attr.label( + cfg = "exec", + allow_single_file = True, + default = "@bazel_tools//tools/test:collect_cc_coverage", + ), + }, + override_attrs = { + "use_testrunner": attr.bool(default = True), + "stamp": attr.int(default = 0, values = [-1, 0, 1]), + }, + remove_attrs = ["deploy_env"], + ), + test = True, + ) + +java_test = make_java_test(True) diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java index 5d196a2e8c3004..378768323a32e9 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java @@ -578,6 +578,7 @@ public void setupMockToolsRepository(MockToolsConfig config) throws IOException "", "def http_jar(**kwargs):", " pass"); + config.create("embedded_tools/tools/jdk/jdk_build_file.bzl", "JDK_BUILD_TEMPLATE = ''"); config.create( "embedded_tools/tools/jdk/local_java_repository.bzl", "def local_java_repository(**kwargs):", diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/java/BUILD b/src/test/java/com/google/devtools/build/lib/bazel/rules/java/BUILD index 39f91cf4598dd7..877d27d3911282 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/rules/java/BUILD +++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/java/BUILD @@ -1,4 +1,4 @@ -load("@rules_java//java:defs.bzl", "java_library", "java_test") + load("@rules_java//java:defs.bzl", "java_library", "java_test") package( default_testonly = 1, @@ -16,10 +16,15 @@ java_library( name = "JavaTests_lib", srcs = glob(["*.java"]), deps = [ + "//src/main/java/com/google/devtools/build/lib/analysis:actions/template_expansion_action", + "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", "//src/main/java/com/google/devtools/build/lib/bazel/rules/java:bazel_java_semantics", "//src/main/java/com/google/devtools/build/lib/packages", + "//src/main/java/com/google/devtools/build/lib/util:os", "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", "//src/test/java/com/google/devtools/build/lib/analysis/util", + "//src/test/java/com/google/devtools/build/lib/testutil:TestConstants", + "//third_party:guava", "//third_party:junit4", "//third_party:truth", ], diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/java/JavaConfiguredTargetsTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/java/JavaConfiguredTargetsTest.java new file mode 100644 index 00000000000000..fadb56b8c2a797 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/java/JavaConfiguredTargetsTest.java @@ -0,0 +1,96 @@ +// Copyright 2022 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. + +package com.google.devtools.build.lib.bazel.rules.java; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.MoreCollectors.onlyElement; +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.testutil.TestConstants.TOOLS_REPOSITORY; + +import com.google.common.base.Joiner; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; +import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; +import com.google.devtools.build.lib.util.OS; +import java.util.Arrays; +import java.util.Objects; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests of bazel java rules. */ +@RunWith(JUnit4.class) +public final class JavaConfiguredTargetsTest extends BuildViewTestCase { + + @Test + public void testResourceStripPrefix() throws Exception { + scratch.file( + "a/BUILD", + "java_binary(", + " name = 'bin',", + " srcs = ['Foo.java'],", + " resources = ['path/to/strip/bar.props'],", + " main_class = 'Foo',", + " resource_strip_prefix = 'a/path/to/strip'", + ")"); + + ConfiguredTarget target = getConfiguredTarget("//a:bin"); + + assertThat(target).isNotNull(); + String resourceJarArgs = + Joiner.on(" ").join(getGeneratingSpawnActionArgs(getBinArtifact("bin.jar", target))); + assertThat(resourceJarArgs).contains("--resources a/path/to/strip/bar.props:bar.props"); + } + + @Test + public void javaTestSetsSecurityManagerPropertyOnVersion17() throws Exception { + scratch.file( + "a/BUILD", + "java_runtime(", + " name = 'jvm',", + " java = 'java_home/bin/java',", + " version = 17,", + ")", + "toolchain(", + " name = 'java_runtime_toolchain',", + " toolchain = ':jvm',", + " toolchain_type = '" + TOOLS_REPOSITORY + "//tools/jdk:runtime_toolchain_type',", + ")", + "java_test(", + " name = 'test',", + " srcs = ['FooTest.java'],", + " test_class = 'FooTest',", + ")"); + useConfiguration("--extra_toolchains=//a:java_runtime_toolchain"); + var ct = getConfiguredTarget("//a:test"); + var executable = getExecutable(ct); + if (OS.getCurrent() == OS.WINDOWS) { + var jvmFlags = + getGeneratingSpawnActionArgs(executable).stream() + .filter(a -> a.startsWith("jvm_flags=")) + .flatMap(a -> Arrays.stream(a.substring("jvm_flags=".length()).split("\t"))) + .collect(toImmutableList()); + assertThat(jvmFlags).contains("-Djava.security.manager=allow"); + } else { + var jvmFlags = + ((TemplateExpansionAction) getGeneratingAction(executable)) + .getSubstitutions().stream() + .filter(s -> Objects.equals(s.getKey(), "%jvm_flags%")) + .collect(onlyElement()) + .getValue(); + assertThat(jvmFlags).contains("-Djava.security.manager=allow"); + } + } +} diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java index 509f7b50d3b1e5..d011d44a980493 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfoTest.java @@ -37,7 +37,9 @@ public void equalityIsObjectIdentity() { PathFragment.create(""), NestedSetBuilder.emptySet(Order.STABLE_ORDER), null, - ImmutableList.of()); + null, + ImmutableList.of(), + 17); JavaRuntimeInfo b = JavaRuntimeInfo.create( NestedSetBuilder.emptySet(Order.STABLE_ORDER), @@ -47,7 +49,9 @@ public void equalityIsObjectIdentity() { PathFragment.create(""), NestedSetBuilder.emptySet(Order.STABLE_ORDER), null, - ImmutableList.of()); + null, + ImmutableList.of(), + 17); new EqualsTester().addEqualityGroup(a).addEqualityGroup(b).testEquals(); } diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java index aa63fa25e9823a..7103946d2043e1 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java @@ -106,6 +106,8 @@ private static void mockEmbeddedTools(Path embeddedBinaries) throws IOException " if name not in native.existing_rules():", " repo_rule(name = name, **kwargs)"); FileSystemUtils.writeIsoLatin1(tools.getRelative("tools/jdk/BUILD")); + FileSystemUtils.writeIsoLatin1( + tools.getRelative("tools/jdk/jdk_build_file.bzl"), "JDK_BUILD_TEMPLATE = ''"); FileSystemUtils.writeIsoLatin1( tools.getRelative("tools/jdk/local_java_repository.bzl"), "def local_java_repository(**kwargs):", diff --git a/src/test/py/bazel/query_test.py b/src/test/py/bazel/query_test.py index ee52d932ed57a4..12804d7dee7faa 100644 --- a/src/test/py/bazel/query_test.py +++ b/src/test/py/bazel/query_test.py @@ -40,8 +40,10 @@ def testSimpleQuery(self): def testQueryFilesUsedByRepositoryRules(self): self.ScratchFile('WORKSPACE') - self._AssertQueryOutputContains("kind('source file', deps(//external:*))", - '@bazel_tools//tools/jdk:jdk.BUILD') + self._AssertQueryOutputContains( + "kind('source file', deps(//external:*))", + '@bazel_tools//tools/genrule:genrule-setup.sh', + ) def testBuildFilesForExternalRepos_Simple(self): self.ScratchFile('WORKSPACE', [ diff --git a/tools/jdk/BUILD b/tools/jdk/BUILD index b78e0a337094ce..56c6d70126382d 100644 --- a/tools/jdk/BUILD +++ b/tools/jdk/BUILD @@ -16,7 +16,7 @@ filegroup( "default_java_toolchain.bzl", "fail_rule.bzl", "java_toolchain_alias.bzl", - "jdk.BUILD", + "jdk_build_file.bzl", "local_java_repository.bzl", "nosystemjdk/README", "proguard_whitelister.py", diff --git a/tools/jdk/BUILD.tools b/tools/jdk/BUILD.tools index a8bb7c78899595..5d00b96cefbef8 100644 --- a/tools/jdk/BUILD.tools +++ b/tools/jdk/BUILD.tools @@ -210,7 +210,6 @@ alias( exports_files([ "BUILD.java_tools", - "jdk.BUILD", ]) alias( diff --git a/tools/jdk/jdk.BUILD b/tools/jdk/jdk_build_file.bzl similarity index 81% rename from tools/jdk/jdk.BUILD rename to tools/jdk/jdk_build_file.bzl index 86be2fe831955d..bbee0e20368dec 100644 --- a/tools/jdk/jdk.BUILD +++ b/tools/jdk/jdk_build_file.bzl @@ -1,4 +1,24 @@ +<<<<<<< HEAD:tools/jdk/jdk.BUILD load("@rules_java//java:defs.bzl", "java_import", "java_runtime") +======= +# Copyright 2023 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. + +"""A templated BUILD file for Java repositories.""" + +JDK_BUILD_TEMPLATE = """load("@rules_java//java:defs.bzl", "java_runtime") +>>>>>>> 7556e1107b (Add version to JavaRuntimeInfo.):tools/jdk/jdk_build_file.bzl package(default_visibility = ["//visibility:public"]) @@ -200,10 +220,15 @@ java_runtime( ":jdk-lib", ":jre-default", ], + version = {RUNTIME_VERSION}, ) +<<<<<<< HEAD:tools/jdk/jdk.BUILD config_setting( name = "windows", constraint_values = ["@platforms//os:windows"], visibility = ["//visibility:private"], ) +======= +""" +>>>>>>> 7556e1107b (Add version to JavaRuntimeInfo.):tools/jdk/jdk_build_file.bzl diff --git a/tools/jdk/local_java_repository.bzl b/tools/jdk/local_java_repository.bzl index 05686c70b44be7..2b1e26be71a1cc 100644 --- a/tools/jdk/local_java_repository.bzl +++ b/tools/jdk/local_java_repository.bzl @@ -144,11 +144,17 @@ def _local_java_repository_impl(repository_ctx): version = repository_ctx.attr.version if repository_ctx.attr.version != "" else _detect_java_version(repository_ctx, java_bin) # Prepare BUILD file using "local_java_runtime" macro - build_file = "" - if repository_ctx.attr.build_file != None: + if repository_ctx.attr.build_file_content and repository_ctx.attr.build_file: + fail("build_file and build_file_content are exclusive") + if repository_ctx.attr.build_file_content: + build_file = repository_ctx.attr.build_file_content + elif repository_ctx.attr.build_file: build_file = repository_ctx.read(repository_ctx.path(repository_ctx.attr.build_file)) + else: + build_file = "" + build_file = build_file.format(RUNTIME_VERSION = version if version.isdigit() else "0") - runtime_name = '"jdk"' if repository_ctx.attr.build_file else None + runtime_name = '"jdk"' if build_file else None local_java_runtime_macro = """ local_java_runtime( name = "%s", @@ -199,10 +205,11 @@ _local_java_repository_rule = repository_rule( "java_home": attr.string(), "version": attr.string(), "build_file": attr.label(), + "build_file_content": attr.string(), }, ) -def local_java_repository(name, java_home, version = "", build_file = None): +def local_java_repository(name, java_home, version = "", build_file = None, build_file_content = None): """Registers a runtime toolchain for local JDK and creates an unregistered compile toolchain. Toolchain resolution is constrained with --java_runtime_version flag @@ -218,7 +225,8 @@ def local_java_repository(name, java_home, version = "", build_file = None): name: A unique name for this rule. java_home: Location of the JDK imported. build_file: optionally BUILD file template + build_file_content: optional BUILD file template as a string version: optionally java version """ - _local_java_repository_rule(name = name, java_home = java_home, version = version, build_file = build_file) + _local_java_repository_rule(name = name, java_home = java_home, version = version, build_file = build_file, build_file_content = build_file_content) native.register_toolchains("@" + name + "//:runtime_toolchain_definition") diff --git a/tools/jdk/remote_java_repository.bzl b/tools/jdk/remote_java_repository.bzl index 791696c7dc9500..c2d81ca0e79919 100644 --- a/tools/jdk/remote_java_repository.bzl +++ b/tools/jdk/remote_java_repository.bzl @@ -18,6 +18,7 @@ Rule remote_java_repository imports and registers JDK with the toolchain resolut """ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/jdk:jdk_build_file.bzl", "JDK_BUILD_TEMPLATE") def _toolchain_config_impl(ctx): ctx.file("WORKSPACE", "workspace(name = \"{name}\")\n".format(name = ctx.name)) @@ -47,7 +48,7 @@ def remote_java_repository(name, version, target_compatible_with = None, prefix """ http_archive( name = name, - build_file = "@bazel_tools//tools/jdk:jdk.BUILD", + build_file_content = JDK_BUILD_TEMPLATE.format(RUNTIME_VERSION = version), **kwargs ) _toolchain_config(