Bug 1444546 - Part 3: Use GENERATED_FILES for Android SDK bindings generation. r=froydnj,jchen

MozReview-Commit-ID: 2blmzKTvpj3

--HG--
extra : rebase_source : 0954b407ce6625510eadc67dd9989da949b22110
This commit is contained in:
Nick Alexander 2018-03-06 19:19:48 -08:00
Родитель 520b63c85e
Коммит 53a4852ffa
12 изменённых файлов: 172 добавлений и 137 удалений

Просмотреть файл

@ -94,8 +94,6 @@ dnl Configure an Android SDK.
dnl Arg 1: compile SDK version, like 23.
dnl Arg 2: target SDK version, like 23.
dnl Arg 3: list of build-tools versions, like "23.0.3 23.0.1".
dnl Arg 4: list of target lint versions, like "25.3.2 25.3.1" (note: we fall back to
dnl unversioned lint if this version is not found).
AC_DEFUN([MOZ_ANDROID_SDK],
[
@ -194,33 +192,6 @@ case "$target" in
;;
esac
AC_MSG_CHECKING([for Android lint classpath])
ANDROID_LINT_CLASSPATH=""
for version in $4; do
android_lint_versioned_jar="$ANDROID_SDK_ROOT/tools/lib/lint-$version.jar"
if test -e "$android_lint_versioned_jar" ; then
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $android_lint_versioned_jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/lint-checks-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/sdklib-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/repository-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/common-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/lint-api-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/manifest-merger-$version.jar"
break
fi
done
if test -z "$ANDROID_LINT_CLASSPATH" ; then
android_lint_unversioned_jar="$ANDROID_SDK_ROOT/tools/lib/lint.jar"
if test -e "$android_lint_unversioned_jar" ; then
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $android_lint_unversioned_jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/lint-checks.jar"
else
AC_MSG_ERROR([Unable to find android sdk's lint jar. This probably means that you need to update android.m4 to find the latest version of lint-*.jar and all its dependencies. (looked for $android_lint_versioned_jar and $android_lint_unversioned_jar)])
fi
fi
AC_MSG_RESULT([$ANDROID_LINT_CLASSPATH])
AC_SUBST(ANDROID_LINT_CLASSPATH)
MOZ_ARG_WITH_STRING(android-min-sdk,
[ --with-android-min-sdk=[VER] Impose a minimum Firefox for Android SDK version],
[ MOZ_ANDROID_MIN_SDK_VERSION=$withval ])

Просмотреть файл

@ -165,6 +165,10 @@ ifeq (.,$(DEPTH))
js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
accessible/xpcom/export: xpcom/xpidl/export
# The Android SDK bindings needs to build the Java generator code
# source code in order to write the SDK bindings.
widget/android/bindings/export: mobile/android/base/export
# .xpt generation needs the xpidl lex/yacc files
xpcom/xpidl/export: xpcom/idl-parser/xpidl/export

Просмотреть файл

@ -7,16 +7,16 @@ package org.mozilla.gecko.annotationProcessors;
/**
* Generate C++ bindings for SDK classes using a config file.
*
* java SDKProcessor <sdkjar> <configfile> <outdir> <fileprefix> <max-sdk-version>
* java SDKProcessor <sdkjar> <max-sdk-version> <outdir> [<configfile> <fileprefix>]+
*
* <sdkjar>: jar file containing the SDK classes (e.g. android.jar)
* <configfile>: config file for generating bindings
* <outdir>: output directory for generated binding files
* <fileprefix>: prefix used for generated binding files
* <max-sdk-version>: SDK version for generated class members (bindings will not be
* generated for members with SDK versions higher than max-sdk-version)
* <outdir>: output directory for generated binding files
* <configfile>: config file for generating bindings
* <fileprefix>: prefix used for generated binding files
*
* The config file is a text file following the .ini format:
* Each config file is a text file following the .ini format:
*
* ; comment
* [section1]
@ -226,93 +226,98 @@ public class SDKProcessor {
public static void main(String[] args) throws Exception {
// We expect a list of jars on the commandline. If missing, whinge about it.
if (args.length < 5) {
System.err.println("Usage: java SDKProcessor sdkjar configfile outdir fileprefix max-sdk-version");
if (args.length < 5 || args.length % 2 != 1) {
System.err.println("Usage: java SDKProcessor sdkjar max-sdk-version outdir [configfile fileprefix]+");
System.exit(1);
}
System.out.println("Processing platform bindings...");
String sdkJar = args[0];
String outdir = args[2];
String generatedFilePrefix = args[3];
sMaxSdkVersion = Integer.parseInt(args[4]);
final String sdkJar = args[0];
sMaxSdkVersion = Integer.parseInt(args[1]);
final String outdir = args[2];
LintCliClient lintClient = new LintCliClient();
final LintCliClient lintClient = new LintCliClient();
sApiLookup = ApiLookup.get(lintClient);
// Start the clock!
long s = System.currentTimeMillis();
for (int argIndex = 3; argIndex < args.length; argIndex += 2) {
final String configFile = args[argIndex];
final String generatedFilePrefix = args[argIndex + 1];
System.out.println("Processing bindings from " + configFile);
// Get an iterator over the classes in the jar files given...
// Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
// Start the clock!
long s = System.currentTimeMillis();
StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
headerFile.append(
"#ifndef " + generatedFilePrefix + "_h__\n" +
"#define " + generatedFilePrefix + "_h__\n" +
"\n" +
"#include \"mozilla/jni/Refs.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace java {\n" +
"namespace sdk {\n" +
"\n");
// Get an iterator over the classes in the jar files given...
// Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
implementationFile.append(
"#include \"" + generatedFilePrefix + ".h\"\n" +
"#include \"mozilla/jni/Accessors.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace java {\n" +
"namespace sdk {\n" +
"\n");
StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
headerFile.append(
"#ifndef " + generatedFilePrefix + "_h__\n" +
"#define " + generatedFilePrefix + "_h__\n" +
"\n" +
"#include \"mozilla/jni/Refs.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace java {\n" +
"namespace sdk {\n" +
"\n");
// Used to track the calls to the various class-specific initialisation functions.
ClassLoader loader = null;
try {
loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
SDKProcessor.class.getClassLoader());
} catch (Exception e) {
throw new RuntimeException(e.toString());
}
StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
implementationFile.append(
"#include \"" + generatedFilePrefix + ".h\"\n" +
"#include \"mozilla/jni/Accessors.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace java {\n" +
"namespace sdk {\n" +
"\n");
try {
final ClassInfo[] classes = getClassList(args[1]);
for (final ClassInfo cls : classes) {
System.out.println("Looking up: " + cls.name);
generateClass(Class.forName(cls.name, true, loader),
cls,
implementationFile,
headerFile);
// Used to track the calls to the various class-specific initialisation functions.
ClassLoader loader = null;
try {
loader = URLClassLoader.newInstance(new URL[]{new URL("file://" + sdkJar)},
SDKProcessor.class.getClassLoader());
} catch (Exception e) {
throw new RuntimeException(e.toString());
}
} catch (final IllegalStateException|IOException|ParseException e) {
System.err.println("***");
System.err.println("*** Error parsing config file: " + args[1]);
System.err.println("*** " + e);
System.err.println("***");
if (e.getCause() != null) {
e.getCause().printStackTrace(System.err);
try {
final ClassInfo[] classes = getClassList(configFile);
for (final ClassInfo cls : classes) {
System.out.println("Looking up: " + cls.name);
generateClass(Class.forName(cls.name, true, loader),
cls,
implementationFile,
headerFile);
}
} catch (final IllegalStateException | IOException | ParseException e) {
System.err.println("***");
System.err.println("*** Error parsing config file: " + configFile);
System.err.println("*** " + e);
System.err.println("***");
if (e.getCause() != null) {
e.getCause().printStackTrace(System.err);
}
System.exit(1);
return;
}
System.exit(1);
return;
implementationFile.append(
"} /* sdk */\n" +
"} /* java */\n" +
"} /* mozilla */\n");
headerFile.append(
"} /* sdk */\n" +
"} /* java */\n" +
"} /* mozilla */\n" +
"#endif\n");
writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
long e = System.currentTimeMillis();
System.out.println("SDK processing complete in " + (e - s) + "ms");
}
implementationFile.append(
"} /* sdk */\n" +
"} /* java */\n" +
"} /* mozilla */\n");
headerFile.append(
"} /* sdk */\n" +
"} /* java */\n" +
"} /* mozilla */\n" +
"#endif\n");
writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
long e = System.currentTimeMillis();
System.out.println("SDK processing complete in " + (e - s) + "ms");
}
private static int getAPIVersion(Class<?> cls, Member m) {

Просмотреть файл

@ -168,3 +168,5 @@ libs:: FennecJNIWrappers.cpp
endif # ifneq (multi,$(AB_CD))
endif # ifeq (,$(IS_LANGUAGE_REPACK))
export:: android_apks

Просмотреть файл

@ -5,6 +5,10 @@ apply plugin: 'kotlin-android'
apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle"
// The SDK binding generation tasks depend on the JAR creation task of the
// :annotations project.
evaluationDependsOn(':annotations')
// Non-official versions are like "61.0a1", where "a1" is the milestone.
// This simply strips that off, leaving "61.0" in this example.
def getAppVersionWithoutMilestone() {
@ -327,3 +331,33 @@ afterEvaluate {
// Bug 1353055 - Strip 'vars' debugging information to agree with moz.build.
apply from: "${topsrcdir}/mobile/android/gradle/debug_level.gradle"
android.libraryVariants.all configureVariantDebugLevel
// There's nothing specific to the :geckoview project here -- this just needs to
// be somewhere where the Android plugin is available so that we can fish the
// path to "android.jar".
task("generateSDKBindings", type: JavaExec) {
classpath project(':annotations').jar.archivePath
classpath project(':annotations').compileJava.classpath
// To use the lint APIs: "Lint must be invoked with the System property
// com.android.tools.lint.bindir pointing to the ANDROID_SDK tools
// directory"
systemProperties = [
'com.android.tools.lint.bindir': "${android.sdkDirectory}/tools",
]
main = 'org.mozilla.gecko.annotationProcessors.SDKProcessor'
args android.bootClasspath
args 16
args "${topobjdir}/widget/android/bindings"
// Configure the arguments at evaluation-time, not at configuration-time.
doFirst {
// From -Pgenerate_sdk_bindings_args=... on command line.
args project.generate_sdk_bindings_args.split(':')
}
workingDir "${topsrcdir}/widget/android/bindings"
dependsOn project(':annotations').jar
}

Просмотреть файл

@ -101,6 +101,16 @@ def gradle_android_app_tasks(build_config):
set_config('GRADLE_ANDROID_APP_TASKS', gradle_android_app_tasks)
@dependable
def gradle_android_generate_sdk_bindings_tasks():
'''Gradle tasks run by |mach android generate-sdk-bindings|.'''
return [
'geckoview:generateSDKBindings',
]
set_config('GRADLE_ANDROID_GENERATE_SDK_BINDINGS_TASKS', gradle_android_generate_sdk_bindings_tasks)
@depends(gradle_android_build_config, check_build_environment)
@imports(_from='itertools', _import='imap')
def gradle_android_app_apks(build_config, build_env):
@ -204,6 +214,7 @@ set_config('GRADLE_ANDROID_ARCHIVE_GECKOVIEW_TASKS', gradle_android_archive_geck
gradle_android_checkstyle_tasks,
gradle_android_findbugs_tasks,
gradle_android_archive_geckoview_tasks,
gradle_android_generate_sdk_bindings_tasks,
)
@imports(_from='itertools', _import='imap')
@imports(_from='itertools', _import='chain')

Просмотреть файл

@ -37,3 +37,7 @@ def android(verb, *args):
def assemble_app(dummy_output_file, *inputs):
return android('assemble-app')
def generate_sdk_bindings(dummy_output_file, *args):
return android('generate-sdk-bindings', *args)

Просмотреть файл

@ -8,6 +8,9 @@
// :omnijar project for more context.
evaluationDependsOn(':omnijar')
// The JNI wrapper generation tasks depend on the JAR creation task of the :annotations project.
evaluationDependsOn(':annotations')
task buildOmnijars(type:Exec) {
dependsOn rootProject.generateCodeAndResources

Просмотреть файл

@ -53,7 +53,6 @@ class MachCommands(MachCommandBase):
def android(self):
pass
@SubCommand('android', 'assemble-app',
"""Assemble Firefox for Android.
See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""")
@ -64,6 +63,25 @@ class MachCommands(MachCommandBase):
return ret
@SubCommand('android', 'generate-sdk-bindings',
"""Generate SDK bindings used when building GeckoView.""")
@CommandArgument('inputs', nargs='+', help='config files, like [/path/to/ClassName-classes.txt]+')
@CommandArgument('args', nargs=argparse.REMAINDER)
def android_generate_sdk_bindings(self, inputs, args):
import itertools
def stem(input):
# Turn "/path/to/ClassName-classes.txt" into "ClassName".
return os.path.basename(input).rsplit('-classes.txt', 1)[0]
bindings_inputs = list(itertools.chain(*((input, stem(input)) for input in inputs)))
bindings_args = '-Pgenerate_sdk_bindings_args={}'.format(':'.join(bindings_inputs))
ret = self.gradle(self.substs['GRADLE_ANDROID_GENERATE_SDK_BINDINGS_TASKS'] + [bindings_args] + args, verbose=True)
return ret
@SubCommand('android', 'test',
"""Run Android local unit tests.
See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-test""")

Просмотреть файл

@ -2080,7 +2080,7 @@ dnl ========================================================
case "$MOZ_BUILD_APP" in
mobile/android)
MOZ_ANDROID_SDK(23, 23, 26.0.2, 26.0.0 26.0.0-dev 25.3.2 25.3.1)
MOZ_ANDROID_SDK(23, 23, 26.0.2)
;;
esac

Просмотреть файл

@ -1,26 +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/.
# Bug 1099345 - The SDK's lint code (used by the code generator) does not enjoy
# concurrent access to a cache that it generates.
.NOTPARALLEL:
annotation_processor_jar_files := \
$(DEPTH)/build/annotationProcessors/annotationProcessors.jar \
$(ANDROID_LINT_CLASSPATH) \
$(NULL)
sdk_processor := \
$(JAVA) \
-Dcom.android.tools.lint.bindir='$(ANDROID_TOOLS)' \
-classpath $(subst $(NULL) ,:,$(strip $(annotation_processor_jar_files))) \
org.mozilla.gecko.annotationProcessors.SDKProcessor
# For the benefit of readers: the following pattern rule says that,
# for example, MediaCodec.cpp and MediaCodec.h can be produced from
# MediaCodec-classes.txt. This formulation invokes the SDK processor
# at most once.
%.cpp %.h: $(ANDROID_SDK)/android.jar %-classes.txt $(annotation_processor_jar_files)
$(sdk_processor) $(ANDROID_SDK)/android.jar $(srcdir)/$*-classes.txt $(CURDIR) $* 16

Просмотреть файл

@ -23,9 +23,6 @@ SOURCES += ['!%s.cpp' % stem for stem in generated]
EXPORTS += ['!%s.h' % stem for stem in generated]
# We'd like to add these to a future GENERATED_EXPORTS list, but for now we mark
# them as generated here and manually install them in Makefile.in.
GENERATED_FILES += [stem + '.h' for stem in generated]
# There is an unfortunate race condition when using generated SOURCES and
# pattern rules (see Makefile.in) that manifests itself as a VPATH resolution
@ -35,7 +32,19 @@ GENERATED_FILES += [stem + '.h' for stem in generated]
# to be built at export time, which is before MediaCodec.o needs them; and by
# the time MediaCodec.o is built, the source is in place and the VPATH
# resolution works as expected.
GENERATED_FILES += [f[1:] for f in SOURCES]
GENERATED_FILES += ['%s.h' % stem for stem in generated]
# The recursive make backend treats the first output specially: it's passed as
# an open FileAvoidWrite to the invoked script. That doesn't work well with
# the Gradle task that generates all of the outputs, so we add a dummy first
# output.
t = tuple(['sdk_bindings'] +
['%s.cpp' % stem for stem in generated] +
['%s.h' % stem for stem in generated])
GENERATED_FILES += [t]
GENERATED_FILES[t].script = '/mobile/android/gradle.py:generate_sdk_bindings'
GENERATED_FILES[t].inputs += ['%s-classes.txt' % stem for stem in generated]
FINAL_LIBRARY = 'xul'