Bug 1444546 - Part 2: Build annotationProcessors with Gradle. r=jchen
authorNick Alexander <nalexander@mozilla.com>
Thu, 22 Feb 2018 16:11:14 -0800
changeset 471392 d8c9882a3b3ca27904d6169567829e79c458e567
parent 471391 591fee0c3b322d74664a20dd8472d727a1d5546e
child 471393 731eb2e4b5579cc727068d346a32a67d79ec6756
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjchen
bugs1444546
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1444546 - Part 2: Build annotationProcessors with Gradle. r=jchen We want annotationProcessors to be compiled and archived into a JAR at build time, ready to generate JNI wrappers. (That is, until we turn the whole thing into a real annotation processor.) But even if we do use a real annotation processor, we still need to generate SDK bindings, which is less clearly expressed as an annotation processor. (It's more of a build step.) Gradle provides a huge number of ways to organize build logic to achieve this: see https://docs.gradle.org/current/userguide/organizing_build_logic.html. Unfortunately, the best such way -- putting the code into $topsrcdir/buildSrc -- has key disadvantages: 1) it pollutes the top-level $topsrcdir, and there's no way to change the location of buildSrc (https://github.com/gradle/gradle/issues/2472); 2) it's complicated to have a dependent project (mobile/android/annotations) expose its code via a buildSrc project; 3) using buildSrc at all appears to conflict with the Android-Gradle plugin version that we are using. Therefore, this commit does something much simpler: it adds a Java-only project and uses the resulting Gradle "Jar" task and archive output as input to the existing Gradle "generate JNI wrappers" task. MozReview-Commit-ID: 2OyYLPneE1M
build/annotationProcessors/Makefile.in
build/annotationProcessors/moz.build
build/moz.build
config/recurse.mk
mobile/android/annotations/build.gradle
mobile/android/gradle/with_gecko_binaries.gradle
settings.gradle
deleted file mode 100644
--- a/build/annotationProcessors/Makefile.in
+++ /dev/null
@@ -1,10 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/rules.mk
-
-# Include Android specific java flags, instead of what's in rules.mk.
-include $(topsrcdir)/config/android-common.mk
-
-export:: annotationProcessors.jar
deleted file mode 100644
--- a/build/annotationProcessors/moz.build
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-jar = add_java_jar('annotationProcessors')
-jar.sources += [
-    'AnnotationInfo.java',
-    'AnnotationProcessor.java',
-    'classloader/AnnotatableEntity.java',
-    'classloader/ClassWithOptions.java',
-    'classloader/IterableJarLoadingURLClassLoader.java',
-    'classloader/JarClassIterator.java',
-    'CodeGenerator.java',
-    'SDKProcessor.java',
-    'utils/AlphabeticAnnotatableEntityComparator.java',
-    'utils/GeneratableElementIterator.java',
-    'utils/Utils.java',
-]
-jar.extra_jars += CONFIG['ANDROID_LINT_CLASSPATH'].split()
--- a/build/moz.build
+++ b/build/moz.build
@@ -19,19 +19,16 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         CONFIGURE_SUBST_FILES += ['win64/cargo-linker.bat']
 else:
     DIRS += ['unix']
 
 CRAMTEST_MANIFESTS += [
     'tests/cram/cram.ini',
 ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
-    DIRS += ['annotationProcessors']
-
 DEFINES['ACCEPTED_MAR_CHANNEL_IDS'] = CONFIG['ACCEPTED_MAR_CHANNEL_IDS']
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     PYTHON_UNITTEST_MANIFESTS += [
         'compare-mozconfig/python.ini',
     ]
 
 if CONFIG['ENABLE_TESTS'] or CONFIG['MOZ_DMD']:
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -160,19 +160,16 @@ recurse:
 	@$(RECURSED_COMMAND)
 	$(LOOP_OVER_DIRS)
 
 ifeq (.,$(DEPTH))
 # Interdependencies for parallel export.
 js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
 accessible/xpcom/export: xpcom/xpidl/export
 
-# The widget binding generator code is part of the annotationProcessors.
-widget/android/bindings/export: build/annotationProcessors/export
-
 # .xpt generation needs the xpidl lex/yacc files
 xpcom/xpidl/export: xpcom/idl-parser/xpidl/export
 
 # CSS2Properties.webidl needs ServoCSSPropList.py from layout/style
 dom/bindings/export: layout/style/export
 
 ifdef ENABLE_CLANG_PLUGIN
 $(filter-out config/host build/unix/stdc++compat/% build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target
new file mode 100644
--- /dev/null
+++ b/mobile/android/annotations/build.gradle
@@ -0,0 +1,11 @@
+buildDir "${topobjdir}/gradle/build/mobile/android/annotations"
+
+apply plugin: 'java'
+
+dependencies {
+    compile 'com.android.tools.lint:lint:25.3.1'
+    compile 'com.android.tools.lint:lint-checks:25.3.1'
+}
+
+sourceCompatibility = JavaVersion.VERSION_1_8
+targetCompatibility = JavaVersion.VERSION_1_8
--- a/mobile/android/gradle/with_gecko_binaries.gradle
+++ b/mobile/android/gradle/with_gecko_binaries.gradle
@@ -114,62 +114,67 @@ ext.configureLibraryVariantWithJNIWrappe
     // ...WithPrepareIntermediateJars..., so we make the consuming moz.build
     // system invoke this target directly, and force the
     // ...WithPrepareIntermediateJars... dependency.  The real consumer of the
     // JNI wrappers is the moz.build system, which always builds geckoview to
     // consume from Fennec, so that dependency likely adds less to the build time.
     def jarTask = tasks["transformClassesAndResourcesWithPrepareIntermediateJarsFor${variant.name.capitalize()}"]
     def output = jarTask.outputs.files.find({ it.absolutePath.contains('/classes.jar') })
 
+    def annotationProcessorsJarTask = project(':annotations').jar
+
     def wrapperTask
     if (System.env.IS_LANGUAGE_REPACK == '1') {
         // Single-locale l10n repacks set `IS_LANGUAGE_REPACK=1` and don't
         // really have a build environment.
         wrapperTask = task("generateJNIWrappersFor${module}${variant.name.capitalize()}")
     } else {
         wrapperTask = task("generateJNIWrappersFor${module}${variant.name.capitalize()}", type: JavaExec) {
-            classpath "${topobjdir}/build/annotationProcessors/annotationProcessors.jar"
+            classpath annotationProcessorsJarTask.archivePath
         
             // Configure the classpath at evaluation-time, not at
             // configuration-time: see above comment.
             doFirst {
                 classpath variant.javaCompile.classpath
                 // Include android.jar.
                 classpath variant.javaCompile.options.bootClasspath
             }
     
             main = 'org.mozilla.gecko.annotationProcessors.AnnotationProcessor'
             args module
             args output
             
             workingDir "${topobjdir}/mobile/android/base"
             
             dependsOn jarTask
+            dependsOn annotationProcessorsJarTask
         }
     }
 
     if (module == 'Generated') {
         tasks["bundle${variant.name.capitalize()}"].dependsOn wrapperTask
     } else {
         tasks["assemble${variant.name.capitalize()}"].dependsOn wrapperTask
     }
 }
 
 ext.configureApplicationVariantWithJNIWrappers = { variant, module ->
     def jarTask = tasks["bundleAppClasses${variant.name.capitalize()}"]
     def output = jarTask.outputs.files.find({ it.absolutePath.contains('/classes.jar') })
 
+    def annotationProcessorsJarTask = project(':annotations').jar
+
     def wrapperTask
     if (System.env.IS_LANGUAGE_REPACK == '1') {
         // Single-locale l10n repacks set `IS_LANGUAGE_REPACK=1` and don't
         // really have a build environment.
         wrapperTask = task("generateJNIWrappersFor${module}${variant.name.capitalize()}")
     } else {
         wrapperTask = task("generateJNIWrappersFor${module}${variant.name.capitalize()}", type: JavaExec) {
-            classpath "${topobjdir}/build/annotationProcessors/annotationProcessors.jar"
+            classpath annotationProcessorsJarTask.archivePath
         
             // Configure the classpath at evaluation-time, not at
             // configuration-time: see above comment.
             doFirst {
                 classpath variant.javaCompile.classpath
                 // Include android.jar.
                 classpath variant.javaCompile.options.bootClasspath
             }
@@ -177,11 +182,13 @@ ext.configureApplicationVariantWithJNIWr
             main = 'org.mozilla.gecko.annotationProcessors.AnnotationProcessor'
             args module
             args output
         
             workingDir "${topobjdir}/mobile/android/base"
     
             // This forces bundling, which isn't usually part of the assemble* process.
             dependsOn jarTask
+
+            dependsOn annotationProcessorsJarTask
         }
     }
 }
--- a/settings.gradle
+++ b/settings.gradle
@@ -9,36 +9,39 @@ proc.consumeProcessOutput(standardOutput
 proc.waitFor()
 
 // Only show the output if something went wrong.
 if (proc.exitValue() != 0) {
     throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${proc.exitValue()}:\n\n${standardOutput.toString()}")
 }
 
 import groovy.json.JsonSlurper
+
 def slurper = new JsonSlurper()
 def json = slurper.parseText(standardOutput.toString())
 
 if (json.substs.MOZ_BUILD_APP != 'mobile/android') {
     throw new GradleException("Building with Gradle is only supported for Fennec, i.e., MOZ_BUILD_APP == 'mobile/android'.")
 }
 
 // Set the Android SDK location.  This is the *least specific* mechanism, which
 // is unfortunate: we'd prefer to use the *most specific* mechanism.  That is,
 // local.properties (first 'sdk.dir', then 'android.dir') and then the
 // environment variable ANDROID_HOME will override this.  That's unfortunate,
 // but it's hard to automatically arrange better.
 System.setProperty('android.home', json.substs.ANDROID_SDK_ROOT)
 
+include ':annotations'
 include ':app'
 include ':geckoview'
 include ':geckoview_example'
 include ':omnijar'
 include ':thirdparty'
 
+project(':annotations').projectDir = new File("${json.topsrcdir}/mobile/android/annotations")
 project(':app').projectDir = new File("${json.topsrcdir}/mobile/android/app")
 project(':geckoview').projectDir = new File("${json.topsrcdir}/mobile/android/geckoview")
 project(':geckoview_example').projectDir = new File("${json.topsrcdir}/mobile/android/geckoview_example")
 project(':omnijar').projectDir = new File("${json.topsrcdir}/mobile/android/app/omnijar")
 project(':thirdparty').projectDir = new File("${json.topsrcdir}/mobile/android/thirdparty")
 
 // The Gradle instance is shared between settings.gradle and all the
 // other build.gradle files (see