How to work with javac incremental build in Android Tools without detecting changes that should cause recompilation?

My colleagues recently upgraded our Android tools to r19 and found problems with the new incremental build system that Google introduced. Incremental compilation seems like a difficult problem, and it seems that they do not solve it, so now we lose the APK if we are not careful.

I reported this issue to Google, but I wanted to know if anyone saw it, and if so, maybe they can lobby Google to fix it, so that engineering man watches don't look at assemblies that are broken due to bad build script.

Take a look here: https://code.google.com/p/android/issues/detail?id=31242

As a workaround, I modified Ant script to remove all class files before the -build-setup step in the Google Ant script.

+4
source share
1 answer

The problem described in this error is actually a long-standing limitation of most java compilers and tools related to .class files that are not sufficiently supported to allow tools to correctly calculate dependencies. Javac doesn't even go that far, and instead is recompiled only when the java file is newer than the corresponding .class file. It is by design, even.

The only true answer I can find is to delete all your class files with every creation, making your assemblies non-incremental. You can do this by adding this to your build.xml file:

<target name="-pre-compile" depends="-pre-compile-delete"/> <target name="-pre-compile-delete"> <!-- Workaround for https://code.google.com/p/android/issues/detail?id=31242 --> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <delete failonerror="false" dir="${out.classes.absolute.dir}"/> </do-only-if-manifest-hasCode> </target> 

The built-in JDK tool to solve this problem is a dependent task . It tries to traverse class files and delete files whose transitive dependencies are changed. However, as noted in the documentation, the dependency has some limitations, all of which again stem from class files that do not contain enough information to provide a complete dependency tree.

Instead, I suggest a simpler but reasonably reliable workaround using the dependet task . Instead of trying to get the minimum incremental compilation using the dependency task, we delete all class files if any of the sources / tanks is newer. We can recompile when this is not really necessary, but assemblies without any changes are still faster, and we do not accidentally skip compilation when necessary.

 <target name="-pre-compile" depends="-pre-compile-dependset" /> <target name="-pre-compile-dependset"> <!-- Alternative workaround for https://code.google.com/p/android/issues/detail?id=31242 --> <echo>Deleting all class files if newer sources (java or jars) are found...</echo> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <!-- The names of these properties suggest they are single directories, but --> <!-- some projects with Android.mk files treat them like paths (with multiple dirs). --> <!-- Massage these paths get all the files inside multiple dirs. --> <path id="project.all.sources.path"> <pathelement path="${source.absolute.dir}"/> <pathelement path="${gen.absolute.dir}"/> </path> <!-- convert project.all.sources.path to project.all.sources.list --> <pathconvert refid="project.all.sources.path" property="project.all.sources.list" pathsep="," dirsep="/"> <!-- Make the path elements relative to basedir and glob to match all files --> <!-- The result will look like: "src/**,gen/**" --> <chainedmapper> <filtermapper> <replacestring from="${basedir}/" to=""/> </filtermapper> <regexpmapper from="^(.*)" to="\1/**"/> </chainedmapper> </pathconvert> <dependset verbose="true"> <sources> <!-- merge the project own classpath and the tested project classpath --> <path refid="project.all.jars.path" /> <path refid="tested.project.classpath" /> <!-- All source files --> <fileset dir="${basedir}" includes="${project.all.sources.list}" /> </sources> <targets> <fileset dir="${out.classes.absolute.dir}"/> </targets> </dependset> </do-only-if-manifest-hasCode> </target> 

This solution is quite reliable, and I believe that it can be included in the sdk assembly in the end.

+3
source

Source: https://habr.com/ru/post/1413233/


All Articles