Search in sources :

Example 1 with MultidexMode

use of com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode in project bazel by bazelbuild.

the class AndroidBinary method dex.

/** Creates one or more classes.dex files that correspond to {@code proguardedJar}. */
private static DexingOutput dex(RuleContext ruleContext, AndroidSemantics androidSemantics, Artifact binaryJar, Artifact proguardedJar, boolean isBinaryJarFiltered, AndroidCommon common, @Nullable Artifact mainDexProguardSpec, JavaTargetAttributes attributes, Function<Artifact, Artifact> derivedJarFunction) throws InterruptedException, RuleErrorException {
    List<String> dexopts = ruleContext.getTokenizedStringListAttr("dexopts");
    MultidexMode multidexMode = getMultidexMode(ruleContext);
    if (!supportsMultidexMode(ruleContext, multidexMode)) {
        ruleContext.throwWithRuleError("Multidex mode \"" + multidexMode.getAttributeValue() + "\" not supported by this version of the Android SDK");
    }
    int dexShards = ruleContext.attributes().get("dex_shards", Type.INTEGER);
    if (dexShards > 1) {
        if (multidexMode == MultidexMode.OFF) {
            ruleContext.throwWithRuleError(".dex sharding is only available in multidex mode");
        }
        if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
            ruleContext.throwWithRuleError(".dex sharding is not available in manual multidex mode");
        }
    }
    Artifact mainDexList = ruleContext.getPrerequisiteArtifact("main_dex_list", Mode.TARGET);
    if ((mainDexList != null && multidexMode != MultidexMode.MANUAL_MAIN_DEX) || (mainDexList == null && multidexMode == MultidexMode.MANUAL_MAIN_DEX)) {
        ruleContext.throwWithRuleError("Both \"main_dex_list\" and \"multidex='manual_main_dex'\" must be specified.");
    }
    // Always OFF if finalJarIsDerived
    ImmutableSet<AndroidBinaryType> incrementalDexing = getEffectiveIncrementalDexing(ruleContext, dexopts, !Objects.equals(binaryJar, proguardedJar));
    Artifact inclusionFilterJar = isBinaryJarFiltered && Objects.equals(binaryJar, proguardedJar) ? binaryJar : null;
    if (multidexMode == MultidexMode.OFF) {
        // Single dex mode: generate classes.dex directly from the input jar.
        if (incrementalDexing.contains(AndroidBinaryType.MONODEX)) {
            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, derivedJarFunction, (Artifact) null);
            createDexMergerAction(ruleContext, "off", jarToDex, classesDex, (Artifact) null, dexopts);
            return new DexingOutput(classesDex, binaryJar, ImmutableList.of(classesDex));
        } else {
            // By *not* writing a zip we get dx to drop resources on the floor.
            Artifact classesDex = getDxArtifact(ruleContext, "classes.dex");
            AndroidCommon.createDexAction(ruleContext, proguardedJar, classesDex, dexopts, /* multidex */
            false, (Artifact) null);
            return new DexingOutput(classesDex, binaryJar, ImmutableList.of(classesDex));
        }
    } else {
        if (multidexMode == MultidexMode.LEGACY) {
            // For legacy multidex, we need to generate a list for the dexer's --main-dex-list flag.
            mainDexList = createMainDexListAction(ruleContext, androidSemantics, proguardedJar, mainDexProguardSpec);
        }
        Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip");
        if (dexShards > 1) {
            List<Artifact> shards = new ArrayList<>(dexShards);
            for (int i = 1; i <= dexShards; i++) {
                shards.add(getDxArtifact(ruleContext, "shard" + i + ".jar"));
            }
            Artifact javaResourceJar = createShuffleJarAction(ruleContext, incrementalDexing.contains(AndroidBinaryType.MULTIDEX_SHARDED), /*proguardedJar*/
            !Objects.equals(binaryJar, proguardedJar) ? proguardedJar : null, shards, common, inclusionFilterJar, dexopts, androidSemantics, attributes, derivedJarFunction, mainDexList);
            List<Artifact> shardDexes = new ArrayList<>(dexShards);
            for (int i = 1; i <= dexShards; i++) {
                Artifact shard = shards.get(i - 1);
                Artifact shardDex = getDxArtifact(ruleContext, "shard" + i + ".dex.zip");
                shardDexes.add(shardDex);
                if (incrementalDexing.contains(AndroidBinaryType.MULTIDEX_SHARDED)) {
                    // If there's a main dex list then the first shard contains exactly those files.
                    // To work with devices that lack native multi-dex support we need to make sure that
                    // the main dex list becomes one dex file if at all possible.
                    // Note shard here (mostly) contains of .class.dex files from shuffled dex archives,
                    // instead of being a conventional Jar file with .class files.
                    String multidexStrategy = mainDexList != null && i == 1 ? "minimal" : "best_effort";
                    createDexMergerAction(ruleContext, multidexStrategy, shard, shardDex, (Artifact) null, dexopts);
                } else {
                    AndroidCommon.createDexAction(ruleContext, shard, shardDex, dexopts, /* multidex */
                    true, (Artifact) null);
                }
            }
            CommandLine mergeCommandLine = CustomCommandLine.builder().addBeforeEachExecPath("--input_zip", shardDexes).addExecPath("--output_zip", classesDex).build();
            ruleContext.registerAction(new SpawnAction.Builder().setMnemonic("MergeDexZips").setProgressMessage("Merging dex shards for " + ruleContext.getLabel()).setExecutable(ruleContext.getExecutablePrerequisite("$merge_dexzips", Mode.HOST)).addInputs(shardDexes).addOutput(classesDex).setCommandLine(mergeCommandLine).build(ruleContext));
            if (incrementalDexing.contains(AndroidBinaryType.MULTIDEX_SHARDED)) {
                // Using the deploy jar for java resources gives better "bazel mobile-install" performance
                // with incremental dexing b/c bazel can create the "incremental" and "split resource"
                // APKs earlier (b/c these APKs don't depend on code being dexed here).  This is also done
                // for other multidex modes.
                javaResourceJar = binaryJar;
            }
            return new DexingOutput(classesDex, javaResourceJar, shardDexes);
        } else {
            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, 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
                // action that removes all non-.dex files before staging for apk building.
                // Create an artifact for the intermediate zip output that includes non-.dex files.
                Artifact classesDexIntermediate = AndroidBinary.getDxArtifact(ruleContext, "intermediate_classes.dex.zip");
                // Have the dexer generate the intermediate file and the "cleaner" action consume this to
                // generate the final archive with only .dex files.
                AndroidCommon.createDexAction(ruleContext, proguardedJar, classesDexIntermediate, dexopts, /* multidex */
                true, mainDexList);
                createCleanDexZipAction(ruleContext, classesDexIntermediate, classesDex);
            }
            return new DexingOutput(classesDex, binaryJar, ImmutableList.of(classesDex));
        }
    }
}
Also used : CustomCommandLine(com.google.devtools.build.lib.analysis.actions.CustomCommandLine) CommandLine(com.google.devtools.build.lib.analysis.actions.CommandLine) MultidexMode(com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode) MultimapBuilder(com.google.common.collect.MultimapBuilder) Builder(com.google.devtools.build.lib.analysis.actions.SpawnAction.Builder) NestedSetBuilder(com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder) RuleConfiguredTargetBuilder(com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder) DeployArchiveBuilder(com.google.devtools.build.lib.rules.java.DeployArchiveBuilder) AndroidBinaryType(com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidBinaryType) ArrayList(java.util.ArrayList) Artifact(com.google.devtools.build.lib.actions.Artifact)

Aggregations

MultimapBuilder (com.google.common.collect.MultimapBuilder)1 Artifact (com.google.devtools.build.lib.actions.Artifact)1 RuleConfiguredTargetBuilder (com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder)1 CommandLine (com.google.devtools.build.lib.analysis.actions.CommandLine)1 CustomCommandLine (com.google.devtools.build.lib.analysis.actions.CustomCommandLine)1 Builder (com.google.devtools.build.lib.analysis.actions.SpawnAction.Builder)1 NestedSetBuilder (com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder)1 AndroidBinaryType (com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidBinaryType)1 MultidexMode (com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode)1 DeployArchiveBuilder (com.google.devtools.build.lib.rules.java.DeployArchiveBuilder)1 ArrayList (java.util.ArrayList)1