diff options
author | 2018-02-07 15:48:56 -0800 | |
---|---|---|
committer | 2018-02-07 15:50:49 -0800 | |
commit | e066095f837d482c31beb5520bc018a6dd744db2 (patch) | |
tree | 8fb377e32dd6be7f8b33cc29940198787423001a /src/main/java/com/google | |
parent | beb66e0fb63ce5cff2da8faa58ff9a55887affb3 (diff) |
Hooks to support core library desugaring in Android builds
RELNOTES: None.
PiperOrigin-RevId: 184909685
Diffstat (limited to 'src/main/java/com/google')
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() |