aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google
diff options
context:
space:
mode:
authorGravatar kmb <kmb@google.com>2018-02-07 15:48:56 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-07 15:50:49 -0800
commite066095f837d482c31beb5520bc018a6dd744db2 (patch)
tree8fb377e32dd6be7f8b33cc29940198787423001a /src/main/java/com/google
parentbeb66e0fb63ce5cff2da8faa58ff9a55887affb3 (diff)
Hooks to support core library desugaring in Android builds
RELNOTES: None. PiperOrigin-RevId: 184909685
Diffstat (limited to 'src/main/java/com/google')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java80
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java3
4 files changed, 115 insertions, 6 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 fc808ae89a..c8b78e5f4a 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
@@ -32,6 +32,7 @@ import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
import com.google.devtools.build.lib.actions.FailAction;
import com.google.devtools.build.lib.actions.ParameterFile;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -150,6 +151,13 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
"proguard_apply_mapping",
"'proguard_apply_dictionary' can only be used when 'proguard_specs' is also set");
}
+
+ if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()
+ && getMultidexMode(ruleContext) == MultidexMode.OFF) {
+ // Multidex is required so we can include legacy libs as a separate .dex file.
+ ruleContext.throwWithAttributeError(
+ "multidex", "Support for Java 8 libraries on legacy devices requires multidex");
+ }
}
private static RuleConfiguredTargetBuilder init(
@@ -397,8 +405,60 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
FilesToRunProvider resourceExtractor =
ruleContext.getExecutablePrerequisite("$resource_extractor", Mode.HOST);
+ Artifact finalClassesDex;
+ if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()
+ && dexPostprocessingOutput.classesDexZip().getFilename().endsWith(".zip")) {
+ Artifact java8LegacyDex;
+ if (binaryJar == jarToDex) {
+ // No Proguard: use canned Java 8 legacy .dex file
+ java8LegacyDex =
+ ruleContext.getPrerequisiteArtifact("$java8_legacy_dex", Mode.TARGET);
+ } else {
+ // Proguard is used: build custom Java 8 legacy .dex file
+ java8LegacyDex = getDxArtifact(ruleContext, "_java8_legacy.dex.zip");
+ Artifact androidJar = AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar();
+ ruleContext.registerAction(
+ new SpawnAction.Builder()
+ .setExecutable(
+ ruleContext.getExecutablePrerequisite("$build_java8_legacy_dex", Mode.HOST))
+ .addInput(jarToDex)
+ .addInput(androidJar)
+ .addOutput(java8LegacyDex)
+ .addCommandLine(
+ CustomCommandLine.builder()
+ .addExecPath("--binary", jarToDex)
+ .addExecPath("--android_jar", androidJar)
+ .addExecPath("--output", java8LegacyDex)
+ .build())
+ .setMnemonic("BuildLegacyDex")
+ .setProgressMessage("Building Java 8 legacy library for %s", ruleContext.getLabel())
+ .build(ruleContext));
+ }
+
+ // Append legacy .dex library to app's .dex files
+ finalClassesDex = getDxArtifact(ruleContext, "_final_classes.dex.zip");
+ ruleContext.registerAction(
+ new SpawnAction.Builder()
+ .useDefaultShellEnvironment()
+ .setMnemonic("AppendJava8LegacyDex")
+ .setProgressMessage("Adding Java 8 legacy library for %s", ruleContext.getLabel())
+ .setExecutable(ruleContext.getExecutablePrerequisite("$merge_dexzips", Mode.HOST))
+ .addInput(dexPostprocessingOutput.classesDexZip())
+ .addInput(java8LegacyDex)
+ .addOutput(finalClassesDex)
+ // Order matters here: we want java8LegacyDex to be the highest-numbered classesN.dex
+ .addCommandLine(CustomCommandLine.builder()
+ .addExecPath("--input_zip", dexPostprocessingOutput.classesDexZip())
+ .addExecPath("--input_zip", java8LegacyDex)
+ .addExecPath("--output_zip", finalClassesDex)
+ .build())
+ .build(ruleContext));
+ } else {
+ finalClassesDex = dexPostprocessingOutput.classesDexZip();
+ }
+
ApkActionsBuilder.create("apk")
- .setClassesDex(dexPostprocessingOutput.classesDexZip())
+ .setClassesDex(finalClassesDex)
.addInputZip(resourceApk.getArtifact())
.setJavaResourceZip(dexingOutput.javaResourceJar, resourceExtractor)
.addInputZips(nativeLibsZips)
@@ -596,11 +656,19 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
}
AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
- NestedSet<Artifact> libraryJars =
+ NestedSetBuilder<Artifact> libraryJars =
NestedSetBuilder.<Artifact>naiveLinkOrder()
- .add(sdk.getAndroidJar())
- .addTransitive(common.getTransitiveNeverLinkLibraries())
- .build();
+ .add(sdk.getAndroidJar());
+ if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()) {
+ // Proguard sees the desugared app, so it needs legacy APIs to resolve symbols
+ libraryJars.addTransitive(
+ ruleContext
+ .getPrerequisite("$desugared_java8_legacy_apis", Mode.TARGET)
+ .getProvider(FileProvider.class)
+ .getFilesToBuild());
+ }
+ libraryJars.addTransitive(common.getTransitiveNeverLinkLibraries());
+
Artifact proguardSeeds =
ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_PROGUARD_SEEDS);
Artifact proguardUsage =
@@ -615,7 +683,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
proguardUsage,
proguardMapping,
proguardDictionary,
- libraryJars,
+ libraryJars.build(),
proguardOutputJar,
javaSemantics,
getProguardOptimizationPasses(ruleContext),
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
index 5d824b55f9..ce2bb0178d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
@@ -394,6 +394,20 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
)
public boolean desugarJava8;
+ @Option(
+ name = "experimental_desugar_java8_libs",
+ defaultValue = "false",
+ documentationCategory = OptionDocumentationCategory.INPUT_STRICTNESS,
+ effectTags = {
+ OptionEffectTag.AFFECTS_OUTPUTS,
+ OptionEffectTag.LOADING_AND_ANALYSIS,
+ OptionEffectTag.LOSES_INCREMENTAL_STATE,
+ },
+ metadataTags = OptionMetadataTag.EXPERIMENTAL,
+ help = "Whether to include supported Java 8 libraries in apps for legacy devices."
+ )
+ public boolean desugarJava8Libs;
+
// This flag is intended to be flipped globally.
@Option(
name = "experimental_check_desugar_deps",
@@ -769,6 +783,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
host.fatApkCpus = ImmutableList.of(); // Fat APK archs don't apply to the host.
host.desugarJava8 = desugarJava8;
+ host.desugarJava8Libs = desugarJava8Libs;
host.checkDesugarDeps = checkDesugarDeps;
host.incrementalDexing = incrementalDexing;
host.incrementalDexingShardsAfterProguard = incrementalDexingShardsAfterProguard;
@@ -822,6 +837,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
private final ImmutableList<String> dexoptsSupportedInDexMerger;
private final boolean useWorkersWithDexbuilder;
private final boolean desugarJava8;
+ private final boolean desugarJava8Libs;
private final boolean checkDesugarDeps;
private final boolean useRexToCompressDexFiles;
private final boolean allowAndroidLibraryDepsWithoutSrcs;
@@ -856,6 +872,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
this.dexoptsSupportedInDexMerger = ImmutableList.copyOf(options.dexoptsSupportedInDexMerger);
this.useWorkersWithDexbuilder = options.useWorkersWithDexbuilder;
this.desugarJava8 = options.desugarJava8;
+ this.desugarJava8Libs = options.desugarJava8Libs;
this.checkDesugarDeps = options.checkDesugarDeps;
this.allowAndroidLibraryDepsWithoutSrcs = options.allowAndroidLibraryDepsWithoutSrcs;
this.useAndroidResourceShrinking =
@@ -879,6 +896,10 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
throw new InvalidConfigurationException(
"--experimental_incremental_dexing_after_proguard must be a positive number");
}
+ if (desugarJava8Libs && !desugarJava8) {
+ throw new InvalidConfigurationException(
+ "Java 8 library support requires --desugar_java8 to be enabled.");
+ }
}
@AutoCodec.Instantiator
@@ -896,6 +917,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
ImmutableList<String> dexoptsSupportedInDexMerger,
boolean useWorkersWithDexbuilder,
boolean desugarJava8,
+ boolean desugarJava8Libs,
boolean checkDesugarDeps,
boolean useRexToCompressDexFiles,
boolean allowAndroidLibraryDepsWithoutSrcs,
@@ -926,6 +948,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
this.dexoptsSupportedInDexMerger = dexoptsSupportedInDexMerger;
this.useWorkersWithDexbuilder = useWorkersWithDexbuilder;
this.desugarJava8 = desugarJava8;
+ this.desugarJava8Libs = desugarJava8Libs;
this.checkDesugarDeps = checkDesugarDeps;
this.useRexToCompressDexFiles = useRexToCompressDexFiles;
this.allowAndroidLibraryDepsWithoutSrcs = allowAndroidLibraryDepsWithoutSrcs;
@@ -1013,6 +1036,10 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
return desugarJava8;
}
+ public boolean desugarJava8Libs() {
+ return desugarJava8Libs;
+ }
+
public boolean checkDesugarDeps() {
return checkDesugarDeps;
}
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 18685069c4..11c95ab531 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
@@ -832,6 +832,17 @@ public final class AndroidRuleClasses {
.cfg(HostTransition.INSTANCE)
.exec()
.value(env.getToolsLabel("//tools/android:desugar_java8")))
+ .add(
+ attr("$java8_legacy_dex", LABEL)
+ .value(env.getToolsLabel("//tools/android:java8_legacy_dex")))
+ .add(
+ attr("$build_java8_legacy_dex", LABEL)
+ .cfg(HostTransition.INSTANCE)
+ .exec()
+ .value(env.getToolsLabel("//tools/android:build_java8_legacy_dex")))
+ .add(
+ attr("$desugared_java8_legacy_apis", LABEL)
+ .value(env.getToolsLabel("//tools/android:desugared_java8_legacy_apis")))
/* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(dexopts) -->
Additional command-line flags for the dx tool when generating classes.dex.
Subject to <a href="${link make-variables}">"Make variable"</a> substitution and
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 fc938b1b6e..6677f09a67 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
@@ -399,6 +399,9 @@ public final class DexArchiveAspect extends NativeAspectClass implements Configu
if (getAndroidConfig(ruleContext).checkDesugarDeps()) {
args.add("--emit_dependency_metadata_as_needed");
}
+ if (getAndroidConfig(ruleContext).desugarJava8Libs()) {
+ args.add("--desugar_supported_core_libs");
+ }
ruleContext.registerAction(
new SpawnAction.Builder()