From f535f363b42817705166d0c135ce881157349788 Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 14 Oct 2016 01:15:45 +0000 Subject: Desugar Java 8 for Android builds without incremental dexing. This includes applying desugaring for mobile-install's stub apk. -- MOS_MIGRATED_REVID=136111631 --- .../build/lib/rules/android/AndroidBinary.java | 105 +++++++++++++++----- .../lib/rules/android/AndroidRuleClasses.java | 6 +- .../rules/android/AndroidRuntimeJarProvider.java | 102 ++++++++++++++++++++ .../build/lib/rules/android/DexArchiveAspect.java | 107 +++++++++++++-------- .../build/lib/rules/java/DeployArchiveBuilder.java | 38 +++++++- .../build/lib/rules/java/JavaTargetAttributes.java | 20 +--- 6 files changed, 293 insertions(+), 85 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuntimeJarProvider.java (limited to 'src/main/java/com') diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java index 8a229275be..cd0a3c4bad 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java @@ -20,6 +20,7 @@ import static com.google.common.collect.Iterables.filter; import static com.google.devtools.build.lib.analysis.OutputGroupProvider.INTERNAL_SUFFIX; import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -346,8 +347,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { true /* isBinary */); ruleContext.assertNoErrors(); + Function derivedJarFunction = + collectDesugaredJars(ruleContext, androidCommon, androidSemantics, resourceClasses); Artifact deployJar = createDeployJar(ruleContext, javaSemantics, androidCommon, resourceClasses, - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR)); + derivedJarFunction); Artifact proguardMapping = ruleContext.getPrerequisiteArtifact( "proguard_apply_mapping", Mode.TARGET); @@ -356,6 +359,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext, filesBuilder, deployJar, + derivedJarFunction, /* isBinaryJarFiltered */ false, javaCommon, androidCommon, @@ -378,6 +382,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { RuleContext ruleContext, NestedSetBuilder filesBuilder, Artifact binaryJar, + Function derivedJarFunction, boolean isBinaryJarFiltered, JavaCommon javaCommon, AndroidCommon androidCommon, @@ -429,7 +434,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { isBinaryJarFiltered, androidCommon, resourceApk.getMainDexProguardConfig(), - resourceClasses); + resourceClasses, + derivedJarFunction); Artifact finalDexes; Artifact finalProguardMap; @@ -842,11 +848,19 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .addRuntimeClassPathEntries(provider.getJavaCompilationArgs().getRuntimeJars()) .build(); + Function desugaredJars = Functions.identity(); + if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8()) { + desugaredJars = + collectDesugaredJarsFromAttributes(ruleContext, ImmutableList.of(attribute)) + .build() + .collapseToFunction(); + } Artifact stubDeployJar = getDxArtifact(ruleContext, split ? "split_stub_deploy.jar" : "stub_deploy.jar"); new DeployArchiveBuilder(javaSemantics, ruleContext) .setOutputJar(stubDeployJar) .setAttributes(attributes) + .setDerivedJarFunction(desugaredJars) .build(); Artifact stubDex = getDxArtifact(ruleContext, @@ -871,9 +885,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ResourceApk resourceApk, NativeLibs nativeLibs, Artifact debugKeystore) { - + // TODO(bazel-team): Sufficient to use resourceClasses.getRuntimeClasspathForArchive? + // Deleting getArchiveInputs could simplify the implementation of DeployArchiveBuidler.build() Iterable jars = IterablesChain.concat( - resourceClasses.getArchiveInputs(true), androidCommon.getRuntimeJars()); + DeployArchiveBuilder.getArchiveInputs(resourceClasses), androidCommon.getRuntimeJars()); // The resources jars from android_library rules contain stub ids, so filter those out of the // transitive jars. @@ -911,12 +926,15 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { JavaSemantics javaSemantics, AndroidCommon common, JavaTargetAttributes attributes, - Artifact deployJar) + Function derivedJarFunction) throws InterruptedException { + Artifact deployJar = + ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR); new DeployArchiveBuilder(javaSemantics, ruleContext) .setOutputJar(deployJar) .setAttributes(attributes) .addRuntimeJars(common.getRuntimeJars()) + .setDerivedJarFunction(derivedJarFunction) .build(); return deployJar; } @@ -1092,7 +1110,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { boolean isBinaryJarFiltered, AndroidCommon common, @Nullable Artifact mainDexProguardSpec, - JavaTargetAttributes attributes) + JavaTargetAttributes attributes, + Function derivedJarFunction) throws InterruptedException, RuleErrorException { List dexopts = ruleContext.getTokenizedStringListAttr("dexopts"); MultidexMode multidexMode = getMultidexMode(ruleContext); @@ -1131,7 +1150,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip"); Artifact jarToDex = getDxArtifact(ruleContext, "classes.jar"); createShuffleJarAction(ruleContext, true, (Artifact) null, ImmutableList.of(jarToDex), - common, inclusionFilterJar, dexopts, androidSemantics, attributes, (Artifact) null); + common, inclusionFilterJar, dexopts, androidSemantics, attributes, derivedJarFunction, + (Artifact) null); createDexMergerAction(ruleContext, "off", jarToDex, classesDex, (Artifact) null, dexopts); return new DexingOutput(classesDex, binaryJar, ImmutableList.of(classesDex)); } else { @@ -1169,6 +1189,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { dexopts, androidSemantics, attributes, + derivedJarFunction, mainDexList); List shardDexes = new ArrayList<>(dexShards); @@ -1215,7 +1236,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { if (incrementalDexing.contains(AndroidBinaryType.MULTIDEX_UNSHARDED)) { Artifact jarToDex = AndroidBinary.getDxArtifact(ruleContext, "classes.jar"); createShuffleJarAction(ruleContext, true, (Artifact) null, ImmutableList.of(jarToDex), - common, inclusionFilterJar, dexopts, androidSemantics, attributes, (Artifact) null); + common, inclusionFilterJar, dexopts, androidSemantics, attributes, derivedJarFunction, + (Artifact) null); createDexMergerAction(ruleContext, "minimal", jarToDex, classesDex, mainDexList, dexopts); } else { // Because the dexer also places resources into this zip, we also need to create a cleanup @@ -1309,6 +1331,52 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.registerAction(dexmerger.build(ruleContext)); } + /** + * Returns a {@link DexArchiveProvider} of all transitively generated dex archives as well as dex + * archives for the Jars produced by the binary target itself. + */ + public static Function collectDesugaredJars( + RuleContext ruleContext, + AndroidCommon common, + AndroidSemantics semantics, + JavaTargetAttributes attributes) { + if (!AndroidCommon.getAndroidConfig(ruleContext).desugarJava8()) { + return Functions.identity(); + } + AndroidRuntimeJarProvider.Builder result = + collectDesugaredJarsFromAttributes( + ruleContext, semantics.getAttributesWithJavaRuntimeDeps(ruleContext)); + for (Artifact jar : common.getJarsProducedForRuntime()) { + // Create dex archives next to all Jars produced by AndroidCommon for this rule. We need to + // do this (instead of placing dex archives into the _dx subdirectory like DexArchiveAspect) + // because for "legacy" ResourceApks, AndroidCommon produces Jars per resource dependency that + // can theoretically have duplicate basenames, so they go into special directories, and we + // piggyback on that naming scheme here by placing dex archives into the same directories. + PathFragment jarPath = jar.getRootRelativePath(); + Artifact desugared = + DexArchiveAspect.desugar( + ruleContext, + jar, + attributes.getBootClassPath(), + attributes.getCompileTimeClassPath(), + ruleContext.getDerivedArtifact( + jarPath.replaceName(jarPath.getBaseName() + "_desugared.jar"), jar.getRoot())); + result.addDesugaredJar(jar, desugared); + } + return result.build().collapseToFunction(); + } + + private static AndroidRuntimeJarProvider.Builder collectDesugaredJarsFromAttributes( + RuleContext ruleContext, ImmutableList attributes) { + AndroidRuntimeJarProvider.Builder result = new AndroidRuntimeJarProvider.Builder(); + for (String attr : attributes) { + // Use all available AndroidRuntimeJarProvider from attributes that carry runtime dependencies + result.addTransitiveProviders( + ruleContext.getPrerequisites(attr, Mode.TARGET, AndroidRuntimeJarProvider.class)); + } + return result; + } + /** * Returns a {@link DexArchiveProvider} of all transitively generated dex archives as well as dex * archives for the Jars produced by the binary target itself. @@ -1318,7 +1386,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { AndroidCommon common, List dexopts, AndroidSemantics semantics, - JavaTargetAttributes attributes) { + Function derivedJarFunction) { DexArchiveProvider.Builder result = new DexArchiveProvider.Builder(); for (String attr : semantics.getAttributesWithJavaRuntimeDeps(ruleContext)) { // Use all available DexArchiveProviders from attributes that carry runtime dependencies @@ -1334,22 +1402,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { // can theoretically have duplicate basenames, so they go into special directories, and we // piggyback on that naming scheme here by placing dex archives into the same directories. PathFragment jarPath = jar.getRootRelativePath(); - Artifact jarToDex = jar; - if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8()) { - // desugar jars first if desired... - jarToDex = - DexArchiveAspect.desugar( - ruleContext, - jar, - attributes.getBootClassPath(), - attributes.getCompileTimeClassPath(), - ruleContext.getDerivedArtifact( - jarPath.replaceName(jarPath.getBaseName() + "_desugared.jar"), jar.getRoot())); - } Artifact dexArchive = DexArchiveAspect.createDexArchiveAction( ruleContext, - jarToDex, + derivedJarFunction.apply(jar), incrementalDexopts, ruleContext.getDerivedArtifact( jarPath.replaceName(jarPath.getBaseName() + ".dex.zip"), jar.getRoot())); @@ -1368,6 +1424,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { List dexopts, AndroidSemantics semantics, JavaTargetAttributes attributes, + Function derivedJarFunction, @Nullable Artifact mainDexList) throws InterruptedException { checkArgument(mainDexList == null || shards.size() > 1); @@ -1411,8 +1468,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { // there should be very few or no Jar files that still end up in shards. The dexing // step below will have to deal with those in addition to merging .dex files together. classpath = Iterables.transform(classpath, - collectDexArchives(ruleContext, common, dexopts, semantics, attributes)); + collectDexArchives(ruleContext, common, dexopts, semantics, derivedJarFunction)); shardCommandLine.add("--split_dexed_classes"); + } else { + classpath = Iterables.transform(classpath, derivedJarFunction); } shardCommandLine.addBeforeEachExecPath("--input_jar", classpath); shardAction.addInputs(classpath); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java index 879b8a2a10..4b68f53115 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java @@ -662,10 +662,12 @@ public final class AndroidRuleClasses { .value(env.getToolsLabel(STRIP_RESOURCES_LABEL))) .add( attr("$incremental_stub_application", LABEL) - .value(env.getToolsLabel(DEFAULT_INCREMENTAL_STUB_APPLICATION))) + .value(env.getToolsLabel(DEFAULT_INCREMENTAL_STUB_APPLICATION)) + .aspect(dexArchiveAspect, DexArchiveAspect.ONLY_DESUGAR_JAVA8)) .add( attr("$incremental_split_stub_application", LABEL) - .value(env.getToolsLabel(DEFAULT_INCREMENTAL_SPLIT_STUB_APPLICATION))) + .value(env.getToolsLabel(DEFAULT_INCREMENTAL_SPLIT_STUB_APPLICATION)) + .aspect(dexArchiveAspect, DexArchiveAspect.ONLY_DESUGAR_JAVA8)) .add( attr("$desugar", LABEL) .cfg(HOST) diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuntimeJarProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuntimeJarProvider.java new file mode 100644 index 0000000000..85e5fa97fd --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuntimeJarProvider.java @@ -0,0 +1,102 @@ +// Copyright 2016 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.rules.android; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +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 java.util.HashMap; +import javax.annotation.Nullable; + +/** + * Provider of Jar files transitively to be included into the runtime classpath of an Android app. + */ +@Immutable +public class AndroidRuntimeJarProvider implements TransitiveInfoProvider { + + /** Provider that doesn't provide any runtime Jars, typically used for neverlink targets. */ + public static final AndroidRuntimeJarProvider NEVERLINK = + new AndroidRuntimeJarProvider( + NestedSetBuilder.>emptySet(STABLE_ORDER)); + + /** + * Builder for {@link AndroidRuntimeJarProvider}. + */ + public static class Builder { + + private final ImmutableMap.Builder newlyDesugared = ImmutableMap.builder(); + private final NestedSetBuilder> transitiveMappings = + NestedSetBuilder.stableOrder(); + + public Builder() { + } + + /** + * Copies all mappings from the given providers, which is useful to aggregate providers from + * dependencies. + */ + public Builder addTransitiveProviders(Iterable providers) { + for (AndroidRuntimeJarProvider provider : providers) { + transitiveMappings.addTransitive(provider.runtimeJars); + } + return this; + } + + /** Adds a mapping from a Jar to its desugared version. */ + public Builder addDesugaredJar(Artifact jar, Artifact desugared) { + newlyDesugared.put(checkNotNull(jar, "jar"), checkNotNull(desugared, "desugared")); + return this; + } + + /** + * Returns the finished {@link AndroidRuntimeJarProvider}. + */ + public AndroidRuntimeJarProvider build() { + return new AndroidRuntimeJarProvider(transitiveMappings.add(newlyDesugared.build()).build()); + } + } + + /** Mappings from Jar artifacts to the corresponding dex archives. */ + private final NestedSet> runtimeJars; + + private AndroidRuntimeJarProvider(NestedSet> runtimeJars) { + this.runtimeJars = runtimeJars; + } + + /** + * Returns function that maps Jars to desugaring results if available and returns the given Jar + * otherwise. + */ + public Function collapseToFunction() { + final HashMap collapsed = new HashMap<>(); + for (ImmutableMap partialMapping : runtimeJars) { + collapsed.putAll(partialMapping); + } + return new Function() { + @Override + @Nullable + public Artifact apply(@Nullable Artifact jar) { + Artifact result = collapsed.get(jar); + return result != null ? result : jar; // return null iff input == null + } + }; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java b/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java index fdfe7c216a..59b1df5eef 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java @@ -13,7 +13,6 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; -import static com.google.common.base.Preconditions.checkState; import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL; @@ -38,10 +37,12 @@ import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.collect.IterablesChain; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.packages.AspectDefinition; import com.google.devtools.build.lib.packages.AspectParameters; @@ -54,7 +55,8 @@ import com.google.devtools.build.lib.rules.java.JavaCommon; import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; import com.google.devtools.build.lib.rules.java.JavaCompilationInfoProvider; import com.google.devtools.build.lib.rules.java.JavaRuntimeJarProvider; -import java.util.LinkedHashMap; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -65,7 +67,7 @@ public final class DexArchiveAspect extends NativeAspectClass implements Configu public static final String NAME = "DexArchiveAspect"; /** * Function that returns a {@link Rule}'s {@code incremental_dexing} attribute for use by this - * aspect. Must be provided when attaching this aspect to a rule. + * aspect. Must be provided when attaching this aspect to a target. */ public static final Function PARAM_EXTRACTOR = new Function() { @@ -78,6 +80,21 @@ public final class DexArchiveAspect extends NativeAspectClass implements Configu return result.build(); } }; + /** + * Function that limits this aspect to Java 8 desugaring (disabling incremental dexing) when + * attaching this aspect to a target. This is intended for implicit attributes like the stub APKs + * for {@code blaze mobile-install}. + */ + static final Function ONLY_DESUGAR_JAVA8 = + new Function() { + @Override + public AspectParameters apply(Rule rule) { + return new AspectParameters.Builder() + .addAttribute("incremental_dexing", TriState.NO.name()) + .build(); + } + }; + /** Aspect-only label for dexbuidler executable, to avoid name clashes with labels on rules. */ private static final String ASPECT_DEXBUILDER_PREREQ = "$dex_archive_dexbuilder"; /** Aspect-only label for desugaring executable, to avoid name clashes with labels on rules. */ @@ -97,11 +114,14 @@ public final class DexArchiveAspect extends NativeAspectClass implements Configu // Actually we care about JavaRuntimeJarProvider, but rules don't advertise that provider. .requireProvider(JavaCompilationArgsProvider.class) // Parse labels since we don't have RuleDefinitionEnvironment.getLabel like in a rule - .add(attr(ASPECT_DEXBUILDER_PREREQ, LABEL).cfg(HOST).exec() - .value(Label.parseAbsoluteUnchecked(toolsRepository + "//tools/android:dexbuilder"))) .add(attr(ASPECT_DESUGAR_PREREQ, LABEL).cfg(HOST).exec() .value(Label.parseAbsoluteUnchecked(toolsRepository + "//tools/android:desugar_java8"))) .requiresConfigurationFragments(AndroidConfiguration.class); + if (TriState.valueOf(params.getOnlyValueOfAttribute("incremental_dexing")) != TriState.NO) { + // Marginally improves "query2" precision for targets that disable incremental dexing + result.add(attr(ASPECT_DEXBUILDER_PREREQ, LABEL).cfg(HOST).exec() + .value(Label.parseAbsoluteUnchecked(toolsRepository + "//tools/android:dexbuilder"))); + } for (String attr : TRANSITIVE_ATTRIBUTES) { result.attributeAspect(attr, this); } @@ -111,28 +131,27 @@ public final class DexArchiveAspect extends NativeAspectClass implements Configu @Override public ConfiguredAspect create(ConfiguredTarget base, RuleContext ruleContext, AspectParameters params) throws InterruptedException { + ConfiguredAspect.Builder result = new ConfiguredAspect.Builder(NAME, ruleContext); + Function desugaredJars = + desugarJarsIfRequested(base, ruleContext, result); + TriState incrementalAttr = TriState.valueOf(params.getOnlyValueOfAttribute("incremental_dexing")); if (incrementalAttr == TriState.NO || (getAndroidConfig(ruleContext).getIncrementalDexingBinaries().isEmpty() && incrementalAttr != TriState.YES)) { // Dex archives will never be used, so don't bother setting them up. - return new ConfiguredAspect.Builder(NAME, ruleContext).build(); + return result.build(); } - checkState(base.getProvider(DexArchiveProvider.class) == null, - "dex archive natively generated: %s", ruleContext.getLabel()); if (JavaCommon.isNeverLink(ruleContext)) { - return new ConfiguredAspect.Builder(NAME, ruleContext) - .addProvider(DexArchiveProvider.NEVERLINK) - .build(); + return result.addProvider(DexArchiveProvider.NEVERLINK).build(); } - DexArchiveProvider.Builder result = createArchiveProviderBuilderFromDeps(ruleContext); + DexArchiveProvider.Builder dexArchives = new DexArchiveProvider.Builder() + .addTransitiveProviders(collectPrerequisites(ruleContext, DexArchiveProvider.class)); JavaRuntimeJarProvider jarProvider = base.getProvider(JavaRuntimeJarProvider.class); if (jarProvider != null) { - Function desugaredJars = - desugarJarsIfRequested(base, ruleContext, jarProvider); Set> aspectDexopts = aspectDexopts(ruleContext); for (Artifact jar : jarProvider.getRuntimeJars()) { for (Set incrementalDexopts : aspectDexopts) { @@ -148,49 +167,59 @@ public final class DexArchiveAspect extends NativeAspectClass implements Configu desugaredJars.apply(jar), incrementalDexopts, AndroidBinary.getDxArtifact(ruleContext, filename)); - result.addDexArchive(incrementalDexopts, dexArchive, jar); + dexArchives.addDexArchive(incrementalDexopts, dexArchive, jar); } } } - return new ConfiguredAspect.Builder(NAME, ruleContext).addProvider(result.build()).build(); + return result.addProvider(dexArchives.build()).build(); } /** - * Runs Jars in {@code jarProvider} through desugaring action if flag is set. Note that this - * cannot happen in a separate aspect because aspects don't see providers added by other aspects - * executed on the same target. + * Runs Jars in {@link JavaRuntimeJarProvider} through desugaring action if flag is set and adds + * the result to {@code result}. Note that this cannot happen in a separate aspect because aspects + * don't see providers added by other aspects executed on the same target. */ private Function desugarJarsIfRequested( - ConfiguredTarget base, RuleContext ruleContext, JavaRuntimeJarProvider jarProvider) { + ConfiguredTarget base, RuleContext ruleContext, ConfiguredAspect.Builder result) { if (!getAndroidConfig(ruleContext).desugarJava8()) { return Functions.identity(); } - // These are all transitive hjars of dependencies and hjar of the jar itself - NestedSet compileTimeClasspath = base - .getProvider(JavaCompilationArgsProvider.class) // aspect definition requires this - .getRecursiveJavaCompilationArgs() - .getCompileTimeJars(); - // For android_* targets we need to honor their bootclasspath (nicer in general to do so) - ImmutableList bootclasspath = getBootclasspath(base); - LinkedHashMap desugaredJars = new LinkedHashMap<>(); - for (Artifact jar : jarProvider.getRuntimeJars()) { - Artifact desugared = createDesugarAction(ruleContext, jar, bootclasspath, - compileTimeClasspath); - desugaredJars.put(jar, desugared); + Map newlyDesugared = new HashMap<>(); + if (JavaCommon.isNeverLink(ruleContext)) { + result.addProvider(AndroidRuntimeJarProvider.NEVERLINK); + return Functions.forMap(newlyDesugared); } - return Functions.forMap(desugaredJars); + AndroidRuntimeJarProvider.Builder desugaredJars = new AndroidRuntimeJarProvider.Builder() + .addTransitiveProviders(collectPrerequisites(ruleContext, AndroidRuntimeJarProvider.class)); + JavaRuntimeJarProvider jarProvider = base.getProvider(JavaRuntimeJarProvider.class); + if (jarProvider != null) { + // These are all transitive hjars of dependencies and hjar of the jar itself + NestedSet compileTimeClasspath = base + .getProvider(JavaCompilationArgsProvider.class) // aspect definition requires this + .getRecursiveJavaCompilationArgs() + .getCompileTimeJars(); + // For android_* targets we need to honor their bootclasspath (nicer in general to do so) + ImmutableList bootclasspath = getBootclasspath(base); + for (Artifact jar : jarProvider.getRuntimeJars()) { + Artifact desugared = createDesugarAction(ruleContext, jar, bootclasspath, + compileTimeClasspath); + newlyDesugared.put(jar, desugared); + desugaredJars.addDesugaredJar(jar, desugared); + } + } + result.addProvider(desugaredJars.build()); + return Functions.forMap(newlyDesugared); } - private static DexArchiveProvider.Builder createArchiveProviderBuilderFromDeps( - RuleContext ruleContext) { - DexArchiveProvider.Builder result = new DexArchiveProvider.Builder(); + private static IterablesChain collectPrerequisites( + RuleContext ruleContext, Class classType) { + IterablesChain.Builder result = IterablesChain.builder(); for (String attr : TRANSITIVE_ATTRIBUTES) { if (ruleContext.getRule().getRuleClassObject().hasAttr(attr, LABEL_LIST)) { - result.addTransitiveProviders( - ruleContext.getPrerequisites(attr, Mode.TARGET, DexArchiveProvider.class)); + result.add(ruleContext.getPrerequisites(attr, Mode.TARGET, classType)); } } - return result; + return result.build(); } private static ImmutableList getBootclasspath(ConfiguredTarget base) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java index 2a72321d61..2e1be9d437 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java @@ -13,6 +13,8 @@ // limitations under the License. package com.google.devtools.build.lib.rules.java; +import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; @@ -56,6 +58,7 @@ public class DeployArchiveBuilder { @Nullable private String javaStartClass; private ImmutableList deployManifestLines = ImmutableList.of(); @Nullable private Artifact launcher; + private Function derivedJars = Functions.identity(); /** * Type of compression to apply to output archive. @@ -151,6 +154,11 @@ public class DeployArchiveBuilder { return this; } + public DeployArchiveBuilder setDerivedJarFunction(Function derivedJars) { + this.derivedJars = derivedJars; + return this; + } + public static CustomCommandLine.Builder defaultSingleJarCommandLine(Artifact outputJar, String javaMainClass, ImmutableList deployManifestLines, Iterable buildInfoFiles, @@ -192,6 +200,23 @@ public class DeployArchiveBuilder { return args; } + /** Computes input artifacts for a deploy archive based on the given attributes. */ + public static IterablesChain getArchiveInputs(JavaTargetAttributes attributes) { + return getArchiveInputs(attributes, Functions.identity()); + } + + private static IterablesChain getArchiveInputs(JavaTargetAttributes attributes, + Function derivedJarFunction) { + IterablesChain.Builder inputs = IterablesChain.builder(); + inputs.add( + ImmutableList.copyOf( + Iterables.transform(attributes.getRuntimeClassPathForArchive(), derivedJarFunction))); + // TODO(bazel-team): Remove? Resources not used as input to singlejar action + inputs.add(ImmutableList.copyOf(attributes.getResources().values())); + inputs.add(attributes.getClassPathResources()); + return inputs.build(); + } + /** Builds the action as configured. */ public void build() throws InterruptedException { ImmutableList classpathResources = attributes.getClassPathResources(); @@ -207,10 +232,12 @@ public class DeployArchiveBuilder { IterablesChain runtimeJars = runtimeJarsBuilder.build(); + // TODO(kmb): Consider not using getArchiveInputs, specifically because we don't want/need to + // transform anything but the runtimeClasspath and b/c we currently do it twice here and below IterablesChain.Builder inputs = IterablesChain.builder(); - inputs.add(attributes.getArchiveInputs(true)); + inputs.add(getArchiveInputs(attributes, derivedJars)); - inputs.add(ImmutableList.copyOf(runtimeJars)); + inputs.add(ImmutableList.copyOf(Iterables.transform(runtimeJars, derivedJars))); if (runfilesMiddleman != null) { inputs.addElement(runfilesMiddleman); } @@ -218,9 +245,10 @@ public class DeployArchiveBuilder { ImmutableList buildInfoArtifacts = ruleContext.getBuildInfo(JavaBuildInfoFactory.KEY); inputs.add(buildInfoArtifacts); - Iterable runtimeClasspath = Iterables.concat( - runtimeJars, - attributes.getRuntimeClassPathForArchive()); + Iterable runtimeClasspath = + Iterables.transform( + Iterables.concat(runtimeJars, attributes.getRuntimeClassPathForArchive()), + derivedJars); if (launcher != null) { inputs.addElement(launcher); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java index a9b0c75009..300475520d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java @@ -21,13 +21,11 @@ import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.IterablesChain; 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.CppFileTypes; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.PathFragment; - import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; @@ -73,7 +71,7 @@ public class JavaTargetAttributes { private final Set processorPath = new LinkedHashSet<>(); private final Set processorNames = new LinkedHashSet<>(); - + private final Set apiGeneratingProcessorPath = new LinkedHashSet<>(); private final Set apiGeneratingProcessorNames = new LinkedHashSet<>(); @@ -303,7 +301,7 @@ public class JavaTargetAttributes { Iterables.addAll(processorPath, jars); return this; } - + public Builder addApiGeneratingProcessorName(String processor) { Preconditions.checkArgument(!built); apiGeneratingProcessorNames.add(processor); @@ -390,7 +388,7 @@ public class JavaTargetAttributes { private final ImmutableSet processorPath; private final ImmutableSet processorNames; - + private final ImmutableSet apiGeneratingProcessorPath; private final ImmutableSet apiGeneratingProcessorNames; @@ -521,7 +519,7 @@ public class JavaTargetAttributes { public ImmutableSet getProcessorPath() { return processorPath; } - + public Collection getApiGeneratingProcessorPath() { return apiGeneratingProcessorPath; } @@ -566,16 +564,6 @@ public class JavaTargetAttributes { return !classPathResources.isEmpty(); } - public Iterable getArchiveInputs(boolean includeClasspath) { - IterablesChain.Builder inputs = IterablesChain.builder(); - if (includeClasspath) { - inputs.add(ImmutableList.copyOf(getRuntimeClassPathForArchive())); - } - inputs.add(ImmutableList.copyOf(getResources().values())); - inputs.add(getClassPathResources()); - return inputs.build(); - } - public String getRuleKind() { return ruleKind; } -- cgit v1.2.3