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));
}
}
}
Aggregations