Compiling Android project from command line is slow

随声附和 提交于 2019-11-27 20:11:24
mav

I finally found a solution for this! It's a bit of a hack, but it works.

First, go to your ANDROID-SDK/platform-tools directory, then rename dx app to something else, like dextool, and finally create new dx file with contents:

#!/bin/sh
shift
dextool --dex --incremental --no-optimize $@

Replace "dextool" with the name you chose before. This will prepend (undocumented) --incremental attribute to every dex invocation, which will massively decrease build times by dexing only classes that have changed between builds. Now it looks like this:

[dx] Merged dex A (1 defs/11,3KiB) with dex B (359 defs/1253,2KiB). Result is 359 defs/1519,3KiB. Took 0,5s

0.5s instead of 20s is a huge difference!

Edit - few remarks:

  • you have to compile your project at least once before using this, because it uses previous classes.dex file
  • you can run into problems when using other Android toolchains than ant

UPDATE:

Google released SDK Tools 21.0, which renders above tweak absolete, because it does supports pre-dexing. Finally!

Even in 21.1.1 with the --incremental --no-optimize added in the original dex.bat it is slow, so I went on to figure something out, the result is: if you order the .jar files passed to dex by size you get better performance.

Watch https://code.google.com/p/android/issues/detail?id=79166 for updates, I hope they agree and this goes into vNext.

#!/usr/bin/perl
use strict;
use warnings;
#use Data::Dump qw(dump);
use List::Util qw(first), qw(sum);

# size of the argument, -s for files, -s on **/*.class for folders
sub size {
        if (-d $_) {
                # directory size is sum of all class files in the dir recursively
                # account for pre-dexing and compression with a 25% decrease
                return sum(map { size($_) * 0.25 } <$_/*.class>) || 0;
        }
        return -s $_; # use built-in size operator
}

my $dx_args_with_args =
   qr/^--(output|positions|(no-)?optimize-list|dump-(to|width|method)|num-threads|main-dex-list|input-list)$/;
my $nArgs = $#ARGV;
# last argument like --blah, those are for dx
my $lastArg = $nArgs - first { $ARGV[$nArgs - $_] =~ /^--/ } 0..$nArgs;
if ($lastArg != -1 && $ARGV[$lastArg] =~ /$dx_args_with_args/) {
        $lastArg += 1;
}

my @inputs = map { $_->[1] }
             sort { $a->[0] <=> $b->[0] }
             map { [size(), $_] }
             @ARGV[$lastArg + 1 .. $nArgs];

print join(" ", @ARGV[0..$lastArg], @inputs);

exit 0;

Usage

  • have Perl on your path
  • copy the above perl script to ANDROID-SDK/build-tools/v.v.v/dx.pl
  • rename dx in ANDROID-SDK/build-tools/v.v.v/
    Unix: rename dx to dx-orig
    Windows: rename dx.bat to dx-orig.bat
  • add a new replacement dx which calls through:
Windows: dx.bat
@echo off
setlocal
set args=%*
for /f "delims=" %%i in ('perl "%~dp0dx.pl" %args%') do set args=%%i
call "%~dp0dx-orig.bat" %args%
endlocal
Unix: dx
#!/bin/sh
dx-orig `perl dx.pl $@`
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!