@ncalexander

Building Fennec with Gradle and IntelliJ: first steps

Thu 23 October 2014 / tagged: android, build system, fennec, gradle, intellij

Developing Fennec with Eclipse has been working well for quite some time now, but Eclipse is officially no longer supported by Google and the new standard is to build with Gradle and to edit in Android Studio or IntelliJ. I recently landed Bug 1041395 and friends, which makes it easy to build Fennec with Gradle. Here is a companion demonstration screencast.

Instructions

Prerequisites

You need the Android Support Repository and Google Repository installed. These install local Maven repositories of SDK libraries that the Gradle build depends on. To install the repositories:

android update sdk --no-ui --filter "extra-google-m2repository,extra-android-m2repository"

You can also install the repositories manually: use the android tool and select them from the Extras section.

Test a build with Gradle

./mach build && ./mach package
cd $OBJDIR/mobile/android/gradle
./gradlew build

The debug APK will be at $OBJDIR/mobile/android/base/app/build/outputs/apk/app-debug.apk.

Test a build with IntelliJ

The $OBJDIR/mobile/android/gradle directory can be imported into IntelliJ as follows:

  • File > Import Project
  • [select $OBJDIR/mobile/android/gradle]
  • Import project from external model > Gradle
  • [select Use default Gradle wrapper]

When prompted, do not add any files to git. You may need to re-open the project, or restart IntelliJ, to pick up a compiler language-level change.

Technical overview

Caveats

  • The Gradle build will "succeed" but crash on start up if the object directory has not been properly packaged.
  • Changes to preprocessed source code and resources (namely, strings.xml.in and the accompanying DTD files) are not recognized.
  • There’s no support for editing JavaScript.

How the Gradle project is laid out

To the greatest extent possible, the Gradle configuration lives in the source directory. The only Gradle configuration that lives in the object directory is installed when building the mobile/android/gradle directory.

At the time of writing, their are three sub-modules: app, base, and thirdparty.

app is the Fennec wrapper; it generates the org.mozilla.fennec.R resource package. base is the Gecko code; it generates the org.mozilla.gecko.R resource package. Together, app and base address the "two package namespaces" that has plagued Fennec from day one.

Due to limitations in the Android Gradle plugin, all test code is shoved into the app module. (The issue is that, at the time of writing, there is no support for test-only APKs.) For no particular reason, the compiled C/C++ libraries are included in the app module; they could be included in the base module. I expect base to rebuilt slightly more frequently than app, so I’m hoping this choice will allow for faster incremental builds.

thirdparty is the external code we use in Fennec; it’s built as an Android library but uses no resources. It’s separate simply to allow the build system to cache the compiled and pre-dexed artifacts, hopefully allowing for faster incremental builds.

Recursive make backend details

The mobile/android/gradle directory writes the following into $OBJDIR/mobile/android/gradle:

  1. the Gradle wrapper;
  2. gradle.properties;
  3. symlinks to certain source and resource directories.

The Gradle wrapper is written to make it easy to build with Gradle from the object directory. The wrapper is intended to be checked into version control.

gradle.properties is the single source of per-object directory Gradle configuration, and provides the Gradle configuration access to configure/moz.build variables.

The symlinks are not necessary for the Gradle build itself, but they prevent nested directory errors and incorrect Java package scoping when the Gradle project is imported into IntelliJ. Because IntelliJ treats the Gradle project as authoritative, it’s not sufficient to fix these manually in IntelliJ after the initial import — IntelliJ reverts to the Gradle configuration after every build. Since there aren’t many symlinks, I’ve done them in the Makefile rather than at a higher level of abstraction (like a moz.build definition, or a custom build backend). In future, I expect to be able to remove all such symlinks by making our in-tree directory structures agree with what Gradle and IntelliJ expect.

Notes

Many thanks to ckitching for doing the first work on developing Fennec with IntelliJ. Thanks also to mhaigh for championing IntelliJ as the tool of choice for the Fennec front-end team, and to wesj for circulating updated IntelliJ usage notes.

Changes

  • Fri 14 Nov 2014: Included Maven repository prerequisites. Thanks to mcomella for reporting the underlying issue and to IRC user rogeliodh for the command line one-liner.
Nick Alexander

About Nick Alexander

Mathematician. Mozillian. Runner. Master of Disguise.