From ac2e77648a1030b1e31d92fb545d261f811f5cc6 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 16 Aug 2022 13:07:48 -0700 Subject: [PATCH] Add Java runtime's static libraries as implicit dependencies for launcher (similar to java_binary specified deps), if hermetic is enabled. The static libraries are statically linked with the launcher in that case. With this change, we will be able to enable hermetic Java at build time with just java_binary target's hermetic attribute. Please see[] #hermetic-java-static-linking PiperOrigin-RevId: 468003715 Change-Id: Ic9da65cb524fbe55d63fb3a5b52e6dd3ed2112ea --- .../build/lib/rules/java/JavaCommon.java | 9 ++++ .../build/lib/rules/java/JavaRuntime.java | 8 +++- .../build/lib/rules/java/JavaRuntimeInfo.java | 32 ++++++++++++-- .../build/lib/rules/java/JavaRuntimeRule.java | 6 +++ .../java/JavaRuntimeInfoApi.java | 7 +++ .../devtools/build/lib/rules/java/BUILD | 1 + .../lib/rules/java/JavaRuntimeInfoTest.java | 7 ++- .../lib/rules/java/JavaStarlarkApiTest.java | 43 +++++++++++++++++++ 8 files changed, 107 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java index ae568298b16178..200560bbb8128c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.rules.java; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.devtools.build.lib.packages.Type.BOOLEAN; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -566,6 +567,14 @@ public ImmutableList targetsTreatedAsDeps( return targetsTreatedAsDeps.get(type); } + public ImmutableList hermeticStaticLibs() { + if (ruleContext.isAttrDefined("hermetic", BOOLEAN) + && ruleContext.attributes().get("hermetic", BOOLEAN)) { + return JavaRuntimeInfo.from(ruleContext).hermeticStaticLibs(); + } + return ImmutableList.of(); + } + /** Returns the default dependencies for the given classpath context. */ public static ImmutableList defaultDeps( RuleContext ruleContext, JavaSemantics semantics, ClasspathType type) { 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 a830b8f73b78a6..b77cd763b771a0 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 @@ -16,6 +16,7 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; @@ -32,6 +33,7 @@ import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.rules.cpp.CcInfo; import com.google.devtools.build.lib.util.OsUtils; import com.google.devtools.build.lib.vfs.PathFragment; import javax.annotation.Nullable; @@ -94,6 +96,9 @@ public ConfiguredTarget create(RuleContext ruleContext) Artifact libModules = ruleContext.getPrerequisiteArtifact("lib_modules"); + ImmutableList hermeticStaticLibs = + ImmutableList.copyOf(ruleContext.getPrerequisites("hermetic_static_libs", CcInfo.PROVIDER)); + NestedSet filesToBuild = filesBuilder.build(); // TODO(cushon): clean up uses of java_runtime in data deps and remove this @@ -110,7 +115,8 @@ public ConfiguredTarget create(RuleContext ruleContext) javaHomeRunfilesPath, javaBinaryRunfilesPath, hermeticInputs, - libModules); + libModules, + hermeticStaticLibs); 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 b911ed64857bdb..039125bede868f 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 @@ -16,16 +16,20 @@ import static com.google.devtools.build.lib.rules.java.JavaRuleClasses.JAVA_RUNTIME_ATTRIBUTE_NAME; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.platform.ToolchainInfo; import com.google.devtools.build.lib.collect.nestedset.Depset; import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.BuiltinProvider; import com.google.devtools.build.lib.packages.NativeInfo; +import com.google.devtools.build.lib.rules.cpp.CcInfo; +import com.google.devtools.build.lib.rules.cpp.LibraryToLink; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaRuntimeInfoApi; import com.google.devtools.build.lib.vfs.PathFragment; import javax.annotation.Nullable; @@ -45,7 +49,8 @@ public static JavaRuntimeInfo create( PathFragment javaHomeRunfilesPath, PathFragment javaBinaryRunfilesPath, NestedSet hermeticInputs, - @Nullable Artifact libModules) { + @Nullable Artifact libModules, + ImmutableList hermeticStaticLibs) { return new JavaRuntimeInfo( javaBaseInputs, javaHome, @@ -53,7 +58,8 @@ public static JavaRuntimeInfo create( javaHomeRunfilesPath, javaBinaryRunfilesPath, hermeticInputs, - libModules); + libModules, + hermeticStaticLibs); } @Override @@ -104,6 +110,7 @@ public static JavaRuntimeInfo from(RuleContext ruleContext, String attributeName private final PathFragment javaBinaryRunfilesPath; private final NestedSet hermeticInputs; @Nullable private final Artifact libModules; + private final ImmutableList hermeticStaticLibs; private JavaRuntimeInfo( NestedSet javaBaseInputs, @@ -112,7 +119,8 @@ private JavaRuntimeInfo( PathFragment javaHomeRunfilesPath, PathFragment javaBinaryRunfilesPath, NestedSet hermeticInputs, - @Nullable Artifact libModules) { + @Nullable Artifact libModules, + ImmutableList hermeticStaticLibs) { this.javaBaseInputs = javaBaseInputs; this.javaHome = javaHome; this.javaBinaryExecPath = javaBinaryExecPath; @@ -120,6 +128,7 @@ private JavaRuntimeInfo( this.javaBinaryRunfilesPath = javaBinaryRunfilesPath; this.hermeticInputs = hermeticInputs; this.libModules = libModules; + this.hermeticStaticLibs = hermeticStaticLibs; } /** All input artifacts in the javabase. */ @@ -179,6 +188,23 @@ public Artifact libModules() { return libModules; } + public ImmutableList hermeticStaticLibs() { + return hermeticStaticLibs; + } + + public NestedSet collectHermeticStaticLibrariesToLink() { + NestedSetBuilder result = NestedSetBuilder.stableOrder(); + for (CcInfo lib : hermeticStaticLibs()) { + result.addTransitive(lib.getCcLinkingContext().getLibraries()); + } + return result.build(); + } + + @Override + public Depset starlarkHermeticStaticLibs() { + return Depset.of(LibraryToLink.TYPE, collectHermeticStaticLibrariesToLink()); + } + @Override public Depset starlarkJavaBaseInputs() { return Depset.of(Artifact.TYPE, javaBaseInputs()); 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 f9be8a25b572ee..5c0378771884cf 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 @@ -26,6 +26,8 @@ import com.google.devtools.build.lib.analysis.TemplateVariableInfo; import com.google.devtools.build.lib.analysis.config.ConfigAwareRuleClassBuilder; import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier; +import com.google.devtools.build.lib.rules.cpp.CcInfo; import com.google.devtools.build.lib.util.FileTypeSet; /** Rule definition for {@code java_runtime} */ @@ -54,6 +56,10 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) .singleArtifact() .allowedFileTypes(FileTypeSet.ANY_FILE) .exec()) + .add( + attr("hermetic_static_libs", LABEL_LIST) + .mandatoryProviders(StarlarkProviderIdentifier.forKey(CcInfo.PROVIDER.getKey())) + .allowedFileTypes()) /* The path to the java executable. */ 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 9a35939069ef66..3c3790aae713ef 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 @@ -86,4 +86,11 @@ public interface JavaRuntimeInfoApi extends StructApi { allowReturnNones = true) @Nullable FileApi libModules(); + + /** The JDK static libraries needed for hermetic deployments. */ + @StarlarkMethod( + name = "hermetic_static_libs", + doc = "Returns the JDK static libraries.", + structField = true) + Depset starlarkHermeticStaticLibs(); } diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/BUILD b/src/test/java/com/google/devtools/build/lib/rules/java/BUILD index f05a24e644342d..795d7ee9b551ac 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/java/BUILD +++ b/src/test/java/com/google/devtools/build/lib/rules/java/BUILD @@ -122,6 +122,7 @@ java_test( "//src/main/java/com/google/devtools/build/lib/collect/nestedset", "//src/main/java/com/google/devtools/build/lib/rules/java:java-compilation", "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", + "//third_party:guava", "//third_party:guava-testlib", "//third_party:junit4", ], 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 d6fd39d3a28233..509f7b50d3b1e5 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 @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.rules.java; +import com.google.common.collect.ImmutableList; import com.google.common.testing.EqualsTester; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; @@ -35,7 +36,8 @@ public void equalityIsObjectIdentity() { PathFragment.create(""), PathFragment.create(""), NestedSetBuilder.emptySet(Order.STABLE_ORDER), - null); + null, + ImmutableList.of()); JavaRuntimeInfo b = JavaRuntimeInfo.create( NestedSetBuilder.emptySet(Order.STABLE_ORDER), @@ -44,7 +46,8 @@ public void equalityIsObjectIdentity() { PathFragment.create(""), PathFragment.create(""), NestedSetBuilder.emptySet(Order.STABLE_ORDER), - null); + null, + ImmutableList.of()); new EqualsTester().addEqualityGroup(a).addEqualityGroup(b).testEquals(); } diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java index 13860198c6b9b3..7b731e77b0f42e 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java @@ -3307,4 +3307,47 @@ public void mergeAddExports() throws Exception { private InstrumentedFilesInfo getInstrumentedFilesProvider(String label) throws Exception { return getConfiguredTarget(label).get(InstrumentedFilesInfo.STARLARK_CONSTRUCTOR); } + + @Test + public void hermeticStaticLibs() throws Exception { + scratch.file("a/libStatic.a"); + scratch.file( + "a/BUILD", + "load(':rule.bzl', 'jrule')", + "load('" + + TestConstants.TOOLS_REPOSITORY + + "//tools/jdk:java_toolchain_alias.bzl', 'java_runtime_alias')", + "genrule(name='gen', cmd='', outs=['foo/bar/bin/java'])", + "cc_import(name='libs', static_library = 'libStatic.a')", + "cc_library(name = 'jdk_static_libs00', data = ['libStatic.a'], linkstatic = 1)", + "java_runtime(name='jvm', srcs=[], java='foo/bar/bin/java', hermetic_static_libs =" + + " ['libs'])", + "java_runtime_alias(name='alias')", + "jrule(name='r')", + "toolchain(", + " name = 'java_runtime_toolchain',", + " toolchain = ':jvm',", + " toolchain_type = '" + + TestConstants.TOOLS_REPOSITORY + + "//tools/jdk:runtime_toolchain_type',", + ")"); + scratch.file( + "a/rule.bzl", + "load('//myinfo:myinfo.bzl', 'MyInfo')", + "def _impl(ctx):", + " provider = ctx.attr._java_runtime[java_common.JavaRuntimeInfo]", + " return MyInfo(", + " hermetic_static_libs = provider.hermetic_static_libs,", + " )", + "jrule = rule(_impl, attrs = { '_java_runtime': attr.label(default=Label('//a:alias'))})"); + + useConfiguration("--extra_toolchains=//a:all"); + ConfiguredTarget ct = getConfiguredTarget("//a:r"); + StructImpl myInfo = getMyInfoFromTarget(ct); + Depset hermeticStaticLibs = (Depset) myInfo.getValue("hermetic_static_libs"); + assertThat( + hermeticStaticLibs.getSet(LibraryToLink.class).toList().stream() + .map(LibraryToLink::getLibraryIdentifier)) + .containsExactly("a/libStatic"); + } }