aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2016-10-14 01:15:45 +0000
committerGravatar Yue Gan <yueg@google.com>2016-10-14 09:33:36 +0000
commitf535f363b42817705166d0c135ce881157349788 (patch)
tree04a3b246c00e665e2129d70169b9b618b6548e38 /src/main/java/com/google/devtools
parent322f531f12addfe2c4671eb5d3a0ea8b9f2843ac (diff)
Desugar Java 8 for Android builds without incremental dexing.
This includes applying desugaring for mobile-install's stub apk. -- MOS_MIGRATED_REVID=136111631
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java105
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuntimeJarProvider.java102
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java107
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java38
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java20
6 files changed, 293 insertions, 85 deletions
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<Artifact, Artifact> 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<Artifact> filesBuilder,
Artifact binaryJar,
+ Function<Artifact, Artifact> 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<Artifact, Artifact> 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<Artifact> 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<Artifact, Artifact> 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<Artifact, Artifact> derivedJarFunction)
throws InterruptedException, RuleErrorException {
List<String> 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<Artifact> 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
@@ -1313,12 +1335,58 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
* 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<Artifact, Artifact> 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<String> 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.
+ */
private static Function<Artifact, Artifact> collectDexArchives(
RuleContext ruleContext,
AndroidCommon common,
List<String> dexopts,
AndroidSemantics semantics,
- JavaTargetAttributes attributes) {
+ Function<Artifact, Artifact> 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<String> dexopts,
AndroidSemantics semantics,
JavaTargetAttributes attributes,
+ Function<Artifact, Artifact> 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.<ImmutableMap<Artifact, Artifact>>emptySet(STABLE_ORDER));
+
+ /**
+ * Builder for {@link AndroidRuntimeJarProvider}.
+ */
+ public static class Builder {
+
+ private final ImmutableMap.Builder<Artifact, Artifact> newlyDesugared = ImmutableMap.builder();
+ private final NestedSetBuilder<ImmutableMap<Artifact, Artifact>> transitiveMappings =
+ NestedSetBuilder.stableOrder();
+
+ public Builder() {
+ }
+
+ /**
+ * Copies all mappings from the given providers, which is useful to aggregate providers from
+ * dependencies.
+ */
+ public Builder addTransitiveProviders(Iterable<AndroidRuntimeJarProvider> 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<ImmutableMap<Artifact, Artifact>> runtimeJars;
+
+ private AndroidRuntimeJarProvider(NestedSet<ImmutableMap<Artifact, Artifact>> runtimeJars) {
+ this.runtimeJars = runtimeJars;
+ }
+
+ /**
+ * Returns function that maps Jars to desugaring results if available and returns the given Jar
+ * otherwise.
+ */
+ public Function<Artifact, Artifact> collapseToFunction() {
+ final HashMap<Artifact, Artifact> collapsed = new HashMap<>();
+ for (ImmutableMap<Artifact, Artifact> partialMapping : runtimeJars) {
+ collapsed.putAll(partialMapping);
+ }
+ return new Function<Artifact, Artifact>() {
+ @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<Rule, AspectParameters> PARAM_EXTRACTOR =
new Function<Rule, AspectParameters>() {
@@ -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<Rule, AspectParameters> ONLY_DESUGAR_JAVA8 =
+ new Function<Rule, AspectParameters>() {
+ @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<Artifact, Artifact> 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<Artifact, Artifact> desugaredJars =
- desugarJarsIfRequested(base, ruleContext, jarProvider);
Set<Set<String>> aspectDexopts = aspectDexopts(ruleContext);
for (Artifact jar : jarProvider.getRuntimeJars()) {
for (Set<String> 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<Artifact, Artifact> 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<Artifact> 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<Artifact> bootclasspath = getBootclasspath(base);
- LinkedHashMap<Artifact, Artifact> desugaredJars = new LinkedHashMap<>();
- for (Artifact jar : jarProvider.getRuntimeJars()) {
- Artifact desugared = createDesugarAction(ruleContext, jar, bootclasspath,
- compileTimeClasspath);
- desugaredJars.put(jar, desugared);
+ Map<Artifact, Artifact> 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<Artifact> 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<Artifact> 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 <T extends TransitiveInfoProvider> IterablesChain<T> collectPrerequisites(
+ RuleContext ruleContext, Class<T> classType) {
+ IterablesChain.Builder<T> 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<Artifact> 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<String> deployManifestLines = ImmutableList.of();
@Nullable private Artifact launcher;
+ private Function<Artifact, Artifact> derivedJars = Functions.identity();
/**
* Type of compression to apply to output archive.
@@ -151,6 +154,11 @@ public class DeployArchiveBuilder {
return this;
}
+ public DeployArchiveBuilder setDerivedJarFunction(Function<Artifact, Artifact> derivedJars) {
+ this.derivedJars = derivedJars;
+ return this;
+ }
+
public static CustomCommandLine.Builder defaultSingleJarCommandLine(Artifact outputJar,
String javaMainClass,
ImmutableList<String> deployManifestLines, Iterable<Artifact> 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<Artifact> getArchiveInputs(JavaTargetAttributes attributes) {
+ return getArchiveInputs(attributes, Functions.<Artifact>identity());
+ }
+
+ private static IterablesChain<Artifact> getArchiveInputs(JavaTargetAttributes attributes,
+ Function<Artifact, Artifact> derivedJarFunction) {
+ IterablesChain.Builder<Artifact> 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<Artifact> classpathResources = attributes.getClassPathResources();
@@ -207,10 +232,12 @@ public class DeployArchiveBuilder {
IterablesChain<Artifact> 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<Artifact> 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<Artifact> buildInfoArtifacts = ruleContext.getBuildInfo(JavaBuildInfoFactory.KEY);
inputs.add(buildInfoArtifacts);
- Iterable<Artifact> runtimeClasspath = Iterables.concat(
- runtimeJars,
- attributes.getRuntimeClassPathForArchive());
+ Iterable<Artifact> 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<Artifact> processorPath = new LinkedHashSet<>();
private final Set<String> processorNames = new LinkedHashSet<>();
-
+
private final Set<Artifact> apiGeneratingProcessorPath = new LinkedHashSet<>();
private final Set<String> 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<Artifact> processorPath;
private final ImmutableSet<String> processorNames;
-
+
private final ImmutableSet<Artifact> apiGeneratingProcessorPath;
private final ImmutableSet<String> apiGeneratingProcessorNames;
@@ -521,7 +519,7 @@ public class JavaTargetAttributes {
public ImmutableSet<Artifact> getProcessorPath() {
return processorPath;
}
-
+
public Collection<Artifact> getApiGeneratingProcessorPath() {
return apiGeneratingProcessorPath;
}
@@ -566,16 +564,6 @@ public class JavaTargetAttributes {
return !classPathResources.isEmpty();
}
- public Iterable<Artifact> getArchiveInputs(boolean includeClasspath) {
- IterablesChain.Builder<Artifact> 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;
}