in src/com/facebook/buck/android/AndroidBinaryRule.java [1073:1176]
void addDexingSteps(
Set<String> classpathEntriesToDex,
ImmutableSet.Builder<String> secondaryDexDirectories,
ImmutableList.Builder<Step> steps,
String primaryDexPath,
Function<SourcePath, Path> sourcePathResolver) {
final Set<String> primaryInputsToDex;
final Optional<String> secondaryDexDir;
final Optional<String> secondaryInputsDir;
if (shouldSplitDex()) {
Optional<Path> proguardMappingFile = Optional.absent();
if (packageType.isBuildWithObfuscation()) {
proguardMappingFile = Optional.of(getPathForProGuardDirectory().resolve("mapping.txt"));
}
// DexLibLoader expects that metadata.txt and secondary jar files are under this dir
// in assets.
String magicSecondaryDexSubdir = "assets/secondary-program-dex-jars";
// Intermediate directory holding the primary split-zip jar.
String splitZipDir = getBinPath("__%s_split_zip__");
steps.add(new MakeCleanDirectoryStep(splitZipDir));
String primaryJarPath = splitZipDir + "/primary.jar";
String secondaryJarMetaDirParent = splitZipDir + "/secondary_meta/";
String secondaryJarMetaDir = secondaryJarMetaDirParent + magicSecondaryDexSubdir;
steps.add(new MakeCleanDirectoryStep(secondaryJarMetaDir));
String secondaryJarMeta = secondaryJarMetaDir + "/metadata.txt";
// Intermediate directory holding _ONLY_ the secondary split-zip jar files. This is
// important because SmartDexingCommand will try to dx every entry in this directory. It
// does this because it's impossible to know what outputs split-zip will generate until it
// runs.
String secondaryZipDir = getBinPath("__%s_secondary_zip__");
steps.add(new MakeCleanDirectoryStep(secondaryZipDir));
// Run the split-zip command which is responsible for dividing the large set of input
// classpaths into a more compact set of jar files such that no one jar file when dexed will
// yield a dex artifact too large for dexopt or the dx method limit to handle.
String zipSplitReportDir = getBinPath("__%s_split_zip_report__");
steps.add(new MakeCleanDirectoryStep(zipSplitReportDir));
SplitZipStep splitZipCommand = new SplitZipStep(
classpathEntriesToDex,
secondaryJarMeta,
primaryJarPath,
secondaryZipDir,
"secondary-%d.jar",
proguardMappingFile,
primaryDexSubstrings,
primaryDexClassesFile.transform(sourcePathResolver),
dexSplitMode.getDexSplitStrategy(),
dexSplitMode.getDexStore(),
zipSplitReportDir,
dexSplitMode.useLinearAllocSplitDex(),
linearAllocHardLimit);
steps.add(splitZipCommand);
// Add the secondary dex directory that has yet to be created, but will be by the
// smart dexing command. Smart dex will handle "cleaning" this directory properly.
String secondaryDexParentDir = getBinPath("__%s_secondary_dex__/");
secondaryDexDir = Optional.of(secondaryDexParentDir + magicSecondaryDexSubdir);
steps.add(new MkdirStep(secondaryDexDir.get()));
secondaryDexDirectories.add(secondaryJarMetaDirParent);
secondaryDexDirectories.add(secondaryDexParentDir);
// Adjust smart-dex inputs for the split-zip case.
primaryInputsToDex = ImmutableSet.of(primaryJarPath);
secondaryInputsDir = Optional.of(secondaryZipDir);
} else {
// Simple case where our inputs are the natural classpath directories and we don't have
// to worry about secondary jar/dex files.
primaryInputsToDex = classpathEntriesToDex;
secondaryDexDir = Optional.absent();
secondaryInputsDir = Optional.absent();
}
// Stores checksum information from each invocation to intelligently decide when dx needs
// to be re-run.
Path successDir = Paths.get(getBinPath("__%s_smart_dex__/.success"));
steps.add(new MkdirStep(successDir));
// Add the smart dexing tool that is capable of avoiding the external dx invocation(s) if
// it can be shown that the inputs have not changed. It also parallelizes dx invocations
// where applicable.
//
// Note that by not specifying the number of threads this command will use it will select an
// optimal default regardless of the value of --num-threads. This decision was made with the
// assumption that --num-threads specifies the threading of build rule execution and does not
// directly apply to the internal threading/parallelization details of various build commands
// being executed. For example, aapt is internally threaded by default when preprocessing
// images.
SmartDexingStep smartDexingCommand = new SmartDexingStep(
primaryDexPath,
primaryInputsToDex,
secondaryDexDir,
secondaryInputsDir,
successDir,
Optional.<Integer>absent(),
dexSplitMode.getDexStore(),
/* optimize */ PackageType.RELEASE.equals(packageType));
steps.add(smartDexingCommand);
}