From bfdf72a6a8f26074c8f7e5388f8d58de7333e8c3 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 30 Dec 2022 14:38:28 -0600 Subject: [PATCH] Add version to JavaRuntimeInfo. 1. As suggested in https://github.com/bazelbuild/bazel/issues/6354#issuecomment-1310489402, add a JDK version attribute to the java_runtime rule. This will allow changing behavior based on the Java runtime's version. 2. As an application of the above, pass -Djava.security.manager=allow to Java tests on JDK 17+. This makes the Bazel Java test runner to work on JDK 19. Fixes https://github.com/bazelbuild/bazel/issues/14502. 3. To make the above generally useful, the remote_java_repository and local_java_repository must set the new version attribute in the java_runtime rules that they create. This means the old static jdk.BUILD file no longer suffices. Move the contents of jdk.BUILD into a Starlark file, so the version can be interpolated in by JDK repository rules and macros. (This isn't the nicest, but local_java_repository is not a repository rule, so the template cannot be in a non-Starlark file.) --- .../bazel/rules/java/BazelJavaSemantics.java | 4 +++ .../lib/bazel/rules/java/jdk.WORKSPACE.tmpl | 3 +- .../build/lib/rules/java/JavaRuntime.java | 4 ++- .../build/lib/rules/java/JavaRuntimeInfo.java | 16 +++++++-- .../build/lib/rules/java/JavaRuntimeRule.java | 5 +++ .../java/JavaRuntimeInfoApi.java | 7 ++++ .../bazel/java/bazel_java_binary.bzl | 2 ++ .../lib/analysis/mock/BazelAnalysisMock.java | 1 + .../devtools/build/lib/bazel/rules/java/BUILD | 2 ++ .../rules/java/JavaConfiguredTargetsTest.java | 34 +++++++++++++++++++ .../lib/rules/java/JavaRuntimeInfoTest.java | 6 ++-- .../packages/BazelPackageLoaderTest.java | 2 ++ src/test/py/bazel/query_test.py | 2 +- tools/jdk/BUILD | 2 +- tools/jdk/BUILD.tools | 1 - tools/jdk/{jdk.BUILD => jdk_build_file.bzl} | 4 ++- tools/jdk/local_java_repository.bzl | 18 +++++++--- tools/jdk/remote_java_repository.bzl | 3 +- 18 files changed, 99 insertions(+), 17 deletions(-) rename tools/jdk/{jdk.BUILD => jdk_build_file.bzl} (92%) 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 5869d56a2363ba..4e1ce53450daf3 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 @@ -57,6 +57,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; @@ -548,6 +549,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 65ae7a39e281ac..98d48bd7840fd9 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 183bb35bd3c670..a65f31ca3b6c2f 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; @@ -129,7 +130,8 @@ public ConfiguredTarget create(RuleContext ruleContext) hermeticInputs, libModules, defaultCDS, - hermeticStaticLibs); + 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 d8f91904543a40..579a87924ade15 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 @@ -52,7 +52,8 @@ public static JavaRuntimeInfo create( NestedSet hermeticInputs, @Nullable Artifact libModules, @Nullable Artifact defaultCDS, - ImmutableList hermeticStaticLibs) { + ImmutableList hermeticStaticLibs, + int version) { return new JavaRuntimeInfo( javaBaseInputs, javaHome, @@ -62,7 +63,8 @@ public static JavaRuntimeInfo create( hermeticInputs, libModules, defaultCDS, - hermeticStaticLibs); + hermeticStaticLibs, + version); } @Override @@ -125,6 +127,7 @@ private static JavaRuntimeInfo from(RuleContext ruleContext, ToolchainInfo toolc @Nullable private final Artifact libModules; @Nullable private final Artifact defaultCDS; private final ImmutableList hermeticStaticLibs; + private final int version; private JavaRuntimeInfo( NestedSet javaBaseInputs, @@ -135,7 +138,8 @@ private JavaRuntimeInfo( NestedSet hermeticInputs, @Nullable Artifact libModules, @Nullable Artifact defaultCDS, - ImmutableList hermeticStaticLibs) { + ImmutableList hermeticStaticLibs, + int version) { this.javaBaseInputs = javaBaseInputs; this.javaHome = javaHome; this.javaBinaryExecPath = javaBinaryExecPath; @@ -145,6 +149,7 @@ private JavaRuntimeInfo( this.libModules = libModules; this.defaultCDS = defaultCDS; this.hermeticStaticLibs = hermeticStaticLibs; + this.version = version; } /** All input artifacts in the javabase. */ @@ -232,6 +237,11 @@ public Depset starlarkJavaBaseInputs() { return Depset.of(Artifact.class, 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 50a6e5c7fa34b1..ce876ebae67df0 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; @@ -83,6 +84,10 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) */ .add(attr("java_home", STRING)) .add(attr("output_licenses", LICENSE)) + /* + The major version of the Java runtime. + */ + .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 73c791dfb921db..55d89bb397c7ab 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 @@ -104,4 +104,11 @@ public interface JavaRuntimeInfoApi extends StructApi { doc = "Returns the JDK static libraries.", structField = true) Sequence starlarkHermeticStaticLibs(); + + /** The Java version of the runtime. This may be 0 if the version is unknown. */ + @StarlarkMethod( + name = "version", + doc = "The Java version of the runtime. This may be 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 index 9f0ac1b2ced645..e85a9e8dd56767 100644 --- a/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary.bzl +++ b/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary.bzl @@ -54,6 +54,8 @@ def _bazel_java_binary_impl(ctx): ) 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) 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 ccf37edb96b154..8d9297b920fdd6 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 @@ -580,6 +580,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 e966e902cb5f63..16dc4cb58274a3 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 @@ -17,11 +17,13 @@ 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/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 index d911e6378473d6..8caeb79ecbe376 100644 --- 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 @@ -14,10 +14,13 @@ package com.google.devtools.build.lib.bazel.rules.java; +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 org.junit.Test; import org.junit.runner.RunWith; @@ -46,4 +49,35 @@ public void testResourceStripPrefix() throws Exception { 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 jvmFlags = + ((TemplateExpansionAction) getGeneratingAction(getBinArtifact("test", ct))) + .getSubstitutions().stream() + .filter(s -> "%jvm_flags%".equals(s.getKey())) + .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 60cf66d994585d..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 @@ -38,7 +38,8 @@ public void equalityIsObjectIdentity() { NestedSetBuilder.emptySet(Order.STABLE_ORDER), null, null, - ImmutableList.of()); + ImmutableList.of(), + 17); JavaRuntimeInfo b = JavaRuntimeInfo.create( NestedSetBuilder.emptySet(Order.STABLE_ORDER), @@ -49,7 +50,8 @@ public void equalityIsObjectIdentity() { NestedSetBuilder.emptySet(Order.STABLE_ORDER), null, null, - ImmutableList.of()); + 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 8fa62afbf1f72f..a00664fd5cb33c 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..01237ebab7b2da 100644 --- a/src/test/py/bazel/query_test.py +++ b/src/test/py/bazel/query_test.py @@ -41,7 +41,7 @@ def testSimpleQuery(self): def testQueryFilesUsedByRepositoryRules(self): self.ScratchFile('WORKSPACE') self._AssertQueryOutputContains("kind('source file', deps(//external:*))", - '@bazel_tools//tools/jdk:jdk.BUILD') + '@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 37da6445a4705e..c6998668444117 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 16c74b417cdd0b..1263aa113d048b 100644 --- a/tools/jdk/BUILD.tools +++ b/tools/jdk/BUILD.tools @@ -200,7 +200,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 92% rename from tools/jdk/jdk.BUILD rename to tools/jdk/jdk_build_file.bzl index 427da22cbb9086..f397ddc7525c4f 100644 --- a/tools/jdk/jdk.BUILD +++ b/tools/jdk/jdk_build_file.bzl @@ -1,4 +1,4 @@ -load("@rules_java//java:defs.bzl", "java_runtime") +JDK_BUILD_TEMPLATE = """load("@rules_java//java:defs.bzl", "java_runtime") package(default_visibility = ["//visibility:public"]) @@ -67,4 +67,6 @@ java_runtime( ":jdk-lib", ":jre", ], + version = {RUNTIME_VERSION}, ) +""" \ No newline at end of file diff --git a/tools/jdk/local_java_repository.bzl b/tools/jdk/local_java_repository.bzl index 205a763e07280e..c772b9dffdf7c3 100644 --- a/tools/jdk/local_java_repository.bzl +++ b/tools/jdk/local_java_repository.bzl @@ -146,11 +146,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", @@ -201,10 +207,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 @@ -220,7 +227,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..668ed4d4d4d8e7 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(