mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
f0ca31be3a
Add a BuildFlag annotation, which when specified for classes, will wrap generated code in `#ifdef` or `#ifndef` blocks. This functionality is used for conditionally excluding generated code when NIghtly becomes Beta, without the need to regenerate bindings. MozReview-Commit-ID: L2NFM8CHKqF --HG-- extra : rebase_source : 6ebc82d11fd1aa4aeb57a46262e678480d23de83
182 lines
7.2 KiB
Java
182 lines
7.2 KiB
Java
/* 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/. */
|
|
|
|
package org.mozilla.gecko.annotationProcessors;
|
|
|
|
import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
|
|
import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
|
|
import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
|
|
import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
|
|
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.util.Arrays;
|
|
import java.util.Iterator;
|
|
|
|
public class AnnotationProcessor {
|
|
public static final String GENERATED_COMMENT =
|
|
"// GENERATED CODE\n" +
|
|
"// Generated by the Java program at /build/annotationProcessors at compile time\n" +
|
|
"// from annotations on Java methods. To update, change the annotations on the\n" +
|
|
"// corresponding Java methods and rerun the build. Manually updating this file\n" +
|
|
"// will cause your build to fail.\n" +
|
|
"\n";
|
|
|
|
private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
|
|
private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
|
|
private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT);
|
|
|
|
public static void main(String[] args) {
|
|
// We expect a list of jars on the commandline. If missing, whinge about it.
|
|
if (args.length < 2) {
|
|
System.err.println("Usage: java AnnotationProcessor outprefix jarfiles ...");
|
|
System.exit(1);
|
|
}
|
|
|
|
final String OUTPUT_PREFIX = args[0];
|
|
final String SOURCE_FILE = OUTPUT_PREFIX + "JNIWrappers.cpp";
|
|
final String HEADER_FILE = OUTPUT_PREFIX + "JNIWrappers.h";
|
|
final String NATIVES_FILE = OUTPUT_PREFIX + "JNINatives.h";
|
|
|
|
System.out.println("Processing annotations...");
|
|
|
|
// We want to produce the same output as last time as often as possible. Ordering of
|
|
// generated statements, therefore, needs to be consistent.
|
|
final String[] jars = Arrays.copyOfRange(args, 1, args.length);
|
|
Arrays.sort(jars);
|
|
|
|
// Start the clock!
|
|
long s = System.currentTimeMillis();
|
|
|
|
// Get an iterator over the classes in the jar files given...
|
|
Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(jars);
|
|
|
|
headerFile.append(
|
|
"#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" +
|
|
"#define " + getHeaderGuardName(HEADER_FILE) + "\n" +
|
|
"\n" +
|
|
"#ifndef MOZ_PREPROCESSOR\n" +
|
|
"#include \"mozilla/jni/Refs.h\"\n" +
|
|
"#endif\n" +
|
|
"\n" +
|
|
"namespace mozilla {\n" +
|
|
"namespace java {\n" +
|
|
"\n");
|
|
|
|
implementationFile.append(
|
|
"#ifndef MOZ_PREPROCESSOR\n" +
|
|
"#include \"" + HEADER_FILE + "\"\n" +
|
|
"#include \"mozilla/jni/Accessors.h\"\n" +
|
|
"#endif\n" +
|
|
"\n" +
|
|
"namespace mozilla {\n" +
|
|
"namespace java {\n" +
|
|
"\n");
|
|
|
|
nativesFile.append(
|
|
"#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" +
|
|
"#define " + getHeaderGuardName(NATIVES_FILE) + "\n" +
|
|
"\n" +
|
|
"#ifndef MOZ_PREPROCESSOR\n" +
|
|
"#include \"" + HEADER_FILE + "\"\n" +
|
|
"#include \"mozilla/jni/Natives.h\"\n" +
|
|
"#endif\n" +
|
|
"\n" +
|
|
"namespace mozilla {\n" +
|
|
"namespace java {\n" +
|
|
"\n");
|
|
|
|
while (jarClassIterator.hasNext()) {
|
|
generateClass(jarClassIterator.next());
|
|
}
|
|
|
|
implementationFile.append(
|
|
"} /* java */\n" +
|
|
"} /* mozilla */\n");
|
|
|
|
headerFile.append(
|
|
"} /* java */\n" +
|
|
"} /* mozilla */\n" +
|
|
"#endif // " + getHeaderGuardName(HEADER_FILE) + "\n");
|
|
|
|
nativesFile.append(
|
|
"} /* java */\n" +
|
|
"} /* mozilla */\n" +
|
|
"#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n");
|
|
|
|
writeOutputFile(SOURCE_FILE, implementationFile);
|
|
writeOutputFile(HEADER_FILE, headerFile);
|
|
writeOutputFile(NATIVES_FILE, nativesFile);
|
|
|
|
long e = System.currentTimeMillis();
|
|
System.out.println("Annotation processing complete in " + (e - s) + "ms");
|
|
}
|
|
|
|
private static void generateClass(final ClassWithOptions annotatedClass) {
|
|
// Get an iterator over the appropriately generated methods of this class
|
|
final GeneratableElementIterator methodIterator
|
|
= new GeneratableElementIterator(annotatedClass);
|
|
final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
|
|
|
|
if (!methodIterator.hasNext() && innerClasses.length == 0) {
|
|
return;
|
|
}
|
|
|
|
final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass);
|
|
generatorInstance.generateClasses(innerClasses);
|
|
|
|
// Iterate all annotated members in this class..
|
|
while (methodIterator.hasNext()) {
|
|
AnnotatableEntity aElementTuple = methodIterator.next();
|
|
switch (aElementTuple.mEntityType) {
|
|
case METHOD:
|
|
generatorInstance.generateMethod(aElementTuple);
|
|
break;
|
|
case NATIVE:
|
|
generatorInstance.generateNative(aElementTuple);
|
|
break;
|
|
case FIELD:
|
|
generatorInstance.generateField(aElementTuple);
|
|
break;
|
|
case CONSTRUCTOR:
|
|
generatorInstance.generateConstructor(aElementTuple);
|
|
break;
|
|
}
|
|
}
|
|
|
|
headerFile.append(generatorInstance.getHeaderFileContents());
|
|
implementationFile.append(generatorInstance.getWrapperFileContents());
|
|
nativesFile.append(generatorInstance.getNativesFileContents());
|
|
|
|
for (ClassWithOptions innerClass : innerClasses) {
|
|
generateClass(innerClass);
|
|
}
|
|
}
|
|
|
|
private static String getHeaderGuardName(final String name) {
|
|
return name.replaceAll("\\W", "_");
|
|
}
|
|
|
|
private static void writeOutputFile(final String name,
|
|
final StringBuilder content) {
|
|
FileOutputStream outStream = null;
|
|
try {
|
|
outStream = new FileOutputStream(name);
|
|
outStream.write(content.toString().getBytes());
|
|
} catch (IOException e) {
|
|
System.err.println("Unable to write " + name + ". Perhaps a permissions issue?");
|
|
e.printStackTrace(System.err);
|
|
} finally {
|
|
if (outStream != null) {
|
|
try {
|
|
outStream.close();
|
|
} catch (IOException e) {
|
|
System.err.println("Unable to close outStream due to "+e);
|
|
e.printStackTrace(System.err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|