Recent Changes‎ > ‎

Build changes in revision 14

posted Sep 26, 2011, 1:53 PM by Xavier Ducrohet   [ updated Nov 11, 2011, 1:33 PM ]
SDK Tools, revision 14, and ADT 14.0.0 will include many build related changes. We wanted to highlights the following three categories:
  • Lots of build performance improvements for Eclipse and Ant which received a major revamp.
  • Revamp of the library projects to support jar-based libraries. This also improves the Eclipse support.
  • Project setup files have be renamed to be more consistent with their intended purpose.
For more details, please read on.


General Build improvements
Build performance has recently starting to be an issue for larger apps and the revision 14 has several fixes to help. In this section, we’ll highlight the ones that are used by both Ant and Eclipse. The next two sections will outline Eclipse-specific and Ant-specific changes.

aapt performance with library projects.
A project that references libraries must generate the R class in its package for its own code, but it must also generate the same file in each of its libraries’ packages so that the library code can find their resources.
The previous implementation ran the same aapt command multiple times to generate all those files leading to long build time for large project where aapt can take a while to run. In r14 (requiring Platform-Tools r8), aapt is run only once to generate all the necessary files. This basically at least halves the aapt step for projects with libraries.

png processing in aapt.
When aapt packages the resources, its main goal is to compile the XML to binary format and to create a resource table with all the resource values (string, color, ids, etc...). Additionally, it processes the png files to optimize them (for instance, pre-processing of 9-patches).
Because the aapt process is not incremental, this means every build goes through all png files and processes them always. For large projects with numerous (and/or large) png this process could take a long time.
Revision 14 now processes the png files outside of the aapt packaging step and caches them. Only modified png files are re-processed. The cache is located in bin/res/


Eclipse build improvements

Change to the bin output folder.
While the Ant build system puts the output of javac in bin/classes/, the configuration of the Android projects in Eclipse uses bin/, like standard Java projects. This has always been a small problem because we put other files in there (like the apk and dex files), but also need to use this folder as the source of the dex step. Thankfully, dex would just ignore those files. Since we started putting resource items in there too (png crunch cache), we decided to change the project output (as far as the JDT is concerned) to bin/classes/. ADT still uses bin/ as its top-level output folder for Android specific files.
The visible side effect is that bin/ will now show up in the Package Explorer view (but not bin/classes/ as JDT hides the only output folder it knows about).

Improvements to aapt calls.
The aapt command is not incremental and can be long running for large projects. We’ve recently done improvements to help, such as delaying the resources packaging till launch or export in ADT 12 (see details), and more efficiently generating R.java when library projects are involved (see above).
However, because ADT loads the resources and parses most of the XML files in order to populate various UI wizards and in order to render layout, we can do one more optimization. We now detect whether R.java really needs to be regenerated and only run aapt if it is needed.
We already didn’t run aapt when a non XML file was changed (since no new ID are generated), but we now do the same thing for XML files. For instance, editing a string value will no longer trigger aapt. Same thing for a layout (unless you add a new @+id/foo reference!)


Ant build improvements
The Ant build system has been completely revamped in r14.

Build file clean up.
To start, we have slightly changed the content of the build.xml file that is created in the project folder, so those will have to be recreated using android update project. If you don’t, you’ll get an error at compile time telling you to update it.

If you have customizations in this file, make sure to make a copy first. If all you are doing is adding intermediary steps using -pre-build, -pre-compile, … there should be few changes required. We have changed some var names but this should be easy. Just port those targets into the new build.xml file.
If you have bigger changes, you’ll have to look at the new rules file (SDK/tools/ant/build.xml) to see what to do. Most custom tasks have slightly changed too.
In both cases though, make sure to update the version tag in the project’s build.xml file to read “custom” (see details in the file) so that the tools never clobber your changes (this is new in r14).

Build performance improvements.
The big changes in Ant, besides supporting the new type of library projects, and the build improvements mentioned above (aapt and png crunch cache) is that the new Ant build finally properly supports dependency check before doing any actions. This means that, while some steps (aapt, dex) are still not incremental, they, at least, won’t run if they don’t need to. In r13 and before, aidl compilation, resources ID generation, dex’ing, packaging, etc.. would happen all the time even if no file changed.
Note: renderscript compilation is not yet checking for file modifications and will run all the time. This will be fixed in r15.

The result should be much faster compilation times as developers work on their apps.

The following table shows a simple benchmark, compiling the ApiDemos sample (from Android 3.2) with r13 and r14.

  r13r14
Notes
 Clean build
24s
 25s 
 No touched files
 19s 1s Nothing is done.
 Touch string file
 19s 17s R.java is generated, res are packaged but png files are not processed. Dex runs.
 Touch png file
 19s 6s R.java is not generated, res are packaged, but only the touched png is processed. Dex does not run.
 Touch 1 Java file
 19s 11s R.java is not generated, res are not packaged. Dex runs.
 Touch res file in src/
 19s 3s Only the final packaging is updated.
 Touch native library
 19s 3s Only the final packaging is updated.
(Time as displayed by Ant after a successful build. Average of 3 runs.)

Note that actual build time gains will depend per project. The ratio of java files vs. resources files (and XML files vs. PNG files) in the project, as well as amount and types of file changed will impact actual build times. This benchmark is simply meant to show the impact of skipping some unnecessary steps.

As mentioned above the build rules have been completely revamped. We have merged the 3 previous rule files (for app, library and test projects) into a single file and have changed some of the existing targets to work more cohesively together, especially when a project needs to build other projects (such as library projects and tested app projects).

Here are some of the updated/new commands, along with possible combinations:
  • ant clean: cleans the project. If the all target is included first (ant all clean), other projects (such as tested project in the case of a test project or library projects) will also be cleaned.
  • ant debug: builds a debug package. Works on app, library and test projects, compiling dependencies as needed.
    • Use ant emma debug to build a test project while building the tested app with instrumentation turned on.
  • ant release: builds a release package
  • ant instrument: builds an instrumented debug package. This is generally called automatically when building a test app with code coverage (called on the tested app)
  • ant install: installs a built package. Must be used after a debug/release/instrument target. Using it alone will fail. For instance:
    • ant debug install
    • ant release install
  • ant installd: installs an already compiled debug package. Will fail if the apk is not already built.
  • ant installr: installs an already compiled release package. Will fail if the apk is not already built.
  • ant installi: installs an already compiled instrumented package. Will fail if the apk is not already built.
  • ant installt: installs an already compiled test package. Will fail if the apk is not already built. Also installs the apk of the tested app.
  • ant test: Runs the tests (for test projects).
    • Requires that the tested and test apks are installed already. To do all in a single call use (on the test app project):
      • ant debug install test
    • To run the test with code coverage use (on the test app):
      • ant emma debug install test

Library Project Revamp
Library projects were introduced to allow sharing of code and resources among projects.
If you are not familiar with library projects, I encourage you to read: http://developer.android.com/guide/developing/projects/index.html#LibraryProjects

As introduced, the library project relies on building the source code of the main project and of all library dependencies together as part of the build project for the main project. The library projects themselves don’t build anything that is used by projects using them.

Supporting Library Project is easy in Ant, but Eclipse (actually the JDT) requires that source code is located in a source folder under the project. To achieve this, ADT creates virtual source folders linking to the library source folders. Because library dependencies are controlled by the content of project.properties (formerly default.properties), ADT must dynamically add and remove these virtual source folders whenever a project is opened and closed.

While this mechanism works, the Eclipse implementation has proven both fragile and cumbersome. For instance, Eclipse does not deal well with having 2 representations of the same on-disk file (one under the library project and the other under the main project). The two versions will get out of sync, requiring manual refresh and both will show compilation errors, polluting the Problems view.

Additionally, source-based library prevents distribution of re-usable components unless one is willing to include the source code.

To fix all of these issues, we have decided to move to library projects generating a jar file that is directly used by other projects.

In order to implement this, we had to change the way resource IDs are generated. In a regular projects, resource IDs are generated as final static int. These constants then get inlined into the classes that use them. This means the compiled classes do not access the values stored in, say, R.layout.myui, but instead directly embed the value 0x000042.

To make the compiled classes not embed this value and instead access it from the R classes, library project will generate the resources IDs as static int only.
The resource IDs will still be generated as final static int in the final R class generated in the main project with the resources of the main projects and all required libraries.

For Ant users there are no changes in workflow. Building the main project will ensure the library project has been built and its output (a jar file) is there. Our Ant build improvements (see above) will make building the library project every time the main project is build an effective no-op.

For Eclipse users, the first time projects are opened, there will be an automated migration. The previous virtual folders (if any) will be removed, and a new classpath container is added to automatically contain the library jar files. In case the virtual source folders (named <libraryname>_src) are not removed, it is safe to remove them manually.

Warning: Generating IDs as non final in the library projects, means that the library code cannot treat these IDs as constants. This means, for example, that you can’t use res IDs in a switch statement.

At this time, library projects containing the jar file directly instead of the source code are not yet supported. We intend to add this support in r15.

Project setup
Android projects rely on some files to describe important build-time information. While Ant and Eclipse can have their own mechanism for storing this information, Android projects use custom files in order to be tools independent.
Since we introduced these files, they have been somewhat misnamed and we have finally taken the steps to rename them to better reflect their purpose.

default.properties which is the main project’s properties file containing information such as the build platform target and the library dependencies has been renamed project.properties.

build.properties which is used only by Ant to override some Ant-specific build properties has been renamed ant.properties. Eclipse uses its own .classpath to store similar information and ignores this file.

local.properties has not changed and is still used to link to the local SDK installation for Ant builds only.

To migrate to the new files, you can do the following:
  • Open the project in Eclipse running ADT 14.0, ADT will rename the files automatically.
  • run android update project -p … for Ant based projects.
  • Alternatively, you can rename the files manually.

We have more changes coming in r15 (some mentioned above). If you have any issues, please file bug reports at the Issue Tracker.

Comments