diff options
author | Sven Gothel <[email protected]> | 2014-05-11 03:03:36 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-05-11 03:03:36 +0200 |
commit | 1e53a38eb06aa8ff50660fdf7bd8570b27f27c56 (patch) | |
tree | f061dfb77af5b4c1f27da78b4dbd1881b400abc3 | |
parent | 598da96b3d2ffc3e0915f73749cbafa5fa5cea90 (diff) |
Bug 923: Remove dependency of CStruct annotation processor _generation_ and generated_class_user due to Java8 issues.
Java8's annotation processor as embedded within javac does not allow
referencing not-yet existing generated classes in a class source code
which will produce these generated classes via the annotation process.
Example:
+++
import com.jogamp.gluegen.structgen.CStruct;
public class Lala {
@CStruct(name="RenderingConfig", header="TestStruct01.h")
public RenderingConfig config;
}
+++
Above example illustrates that the type 'RenderingConfig'
does not exist at time of processing the annotation.
The type will be created via the annotation process itself.
Even though we pass '-proc:only', i.e. skip java compilation,
Java8's annotation processing via javac fails in such case.
We see this as a bug within javac's annotation processing itself!
+++
This workaround splits the annotation process and using the class as
generated by the former.
To allow this to work, CStruct receives a new field 'jname'
allowing to enforce the java-name of the structure
using a dummy field type like boolean.
@CStruct(name="RenderingConfig", jname="RenderingConfig", header="TestStruct01.h")
public boolean dummy;
Further more CStruct can be annotated on the package, i.e. 'package-info.java',
avoiding the dependency problem altogether.
To support multiple header files and types,
'CStructs' has been introduced using an array of 'CStruct'.
@CStructs({@CStruct(name="RenderingConfig", header="TestStruct01.h"), @CStruct(name="Pixel", header="TestStruct02.h")})
package com.jogamp.gluegen.test.junit.structgen;
Tests:
- Build w/ Java7 and Java8
- Validated 'major version 50' (Java 6) class files (OK)
15 files changed, 453 insertions, 206 deletions
diff --git a/make/build-test.xml b/make/build-test.xml index bccc534..2bf2e37 100644 --- a/make/build-test.xml +++ b/make/build-test.xml @@ -114,7 +114,23 @@ <echo message=" test.base.dir ${test.base.dir}"/> <echo message=" build_t.gen ${build_t.gen}"/> - <!-- Annotation Processor Only - First --> + <!-- Javac of Annotation Processor dependencies - First --> + <javac destdir="${build_t.java}" + fork="yes" + includeAntRuntime="false" + memoryMaximumSize="${javac.memorymax}" + encoding="UTF-8" + source="${target.sourcelevel}" + target="${target.targetlevel}" + bootclasspath="${target.rt.jar}" + debug="${javacdebug}" debuglevel="${javacdebuglevel}"> + <classpath refid="junit.compile.classpath"/> + <compilerarg value="-proc:none"/> + <src path="${test.base.dir}/com/jogamp/junit/util"/> + </javac> + + <!-- Annotation Processor - Second --> + <mkdir dir="${build_t.gen}/classes/com/jogamp/gluegen/test/junit/structgen"/> <javac destdir="${build_t.java}" fork="yes" includeAntRuntime="false" @@ -129,9 +145,10 @@ <compilerarg value="-J-Djogamp.gluegen.structgen.debug"/> <compilerarg value="-J-Djogamp.gluegen.structgen.output=${build_t.gen}/classes"/> <src path="${test.base.dir}/com/jogamp/gluegen/test/junit/structgen"/> + <src path="${build_t.gen}/classes/com/jogamp/gluegen/test/junit/structgen" /> </javac> - <!-- Javac Only - Second --> + <!-- Javac All - Third --> <javac destdir="${build_t.java}" fork="yes" includeAntRuntime="false" diff --git a/make/scripts/check-java-major-version.sh b/make/scripts/check-java-major-version.sh index 6b1711c..49c0445 100755 --- a/make/scripts/check-java-major-version.sh +++ b/make/scripts/check-java-major-version.sh @@ -10,9 +10,10 @@ function dump_version() { function dump_versions() { cd $1 #dump_version jogamp.common.Debug - for i in `find . -name '*.class'` ; do - dump_version `echo $i | sed -e 's/\//./g' -e 's/\.class//g'` - done + javap -v `find . -name '*.class'` | grep -e '^Classfile' -e 'major version' + #for i in `find . -name '*.class'` ; do + # dump_version `echo $i | sed -e 's/\//./g' -e 's/\.class//g'` + #done cd $TDIR } diff --git a/make/scripts/make.gluegen.all.linux-x86_64.sh b/make/scripts/make.gluegen.all.linux-x86_64.sh index 8c62cd0..60e35d6 100755 --- a/make/scripts/make.gluegen.all.linux-x86_64.sh +++ b/make/scripts/make.gluegen.all.linux-x86_64.sh @@ -27,7 +27,7 @@ export TARGET_RT_JAR=/opt-share/jre1.6.0_30/lib/rt.jar #export JOGAMP_JAR_CODEBASE="Codebase: *.jogamp.org" export JOGAMP_JAR_CODEBASE="Codebase: *.goethel.localnet" -# BUILD_ARCHIVE=true \ +BUILD_ARCHIVE=true \ ant \ -Drootrel.build=build-x86_64 \ $* 2>&1 | tee make.gluegen.all.linux-x86_64.log diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh index 947755f..f518668 100755 --- a/make/scripts/runtest.sh +++ b/make/scripts/runtest.sh @@ -119,7 +119,8 @@ function onetest() { #onetest com.jogamp.common.os.TestElfReader01 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.PCPPTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter 2>&1 | tee -a $LOG -onetest com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter 2>&1 | tee -a $LOG +#onetest com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p2LoadJNIAndImplLib 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.structgen.TestStructGen01 2>&1 | tee -a $LOG +onetest com.jogamp.gluegen.test.junit.structgen.TestStructGen02 2>&1 | tee -a $LOG diff --git a/make/scripts/setenv-build-jogl-x86_64.sh b/make/scripts/setenv-build-jogl-x86_64.sh index c0746e9..8994365 100644 --- a/make/scripts/setenv-build-jogl-x86_64.sh +++ b/make/scripts/setenv-build-jogl-x86_64.sh @@ -26,15 +26,25 @@ if [ -z "$ANT_PATH" ] ; then exit fi -if [ -e /opt-linux-x86_64/jre7 -a -e /opt-linux-x86_64/j2se7 ] ; then - J2RE_HOME=/opt-linux-x86_64/jre7 - JAVA_HOME=/opt-linux-x86_64/j2se7 +if [ -e /opt-linux-x86_64/jre8 -a -e /opt-linux-x86_64/j2se8 ] ; then + J2RE_HOME=/opt-linux-x86_64/jre8 + JAVA_HOME=/opt-linux-x86_64/j2se8 PATH=$J2RE_HOME/bin:$JAVA_HOME/bin:$PATH export J2RE_HOME JAVA_HOME FOUND_JAVA=1 fi if [ -z "$FOUND_JAVA" ] ; then + if [ -e /opt-linux-x86_64/jre7 -a -e /opt-linux-x86_64/j2se7 ] ; then + J2RE_HOME=/opt-linux-x86_64/jre7 + JAVA_HOME=/opt-linux-x86_64/j2se7 + PATH=$J2RE_HOME/bin:$JAVA_HOME/bin:$PATH + export J2RE_HOME JAVA_HOME + FOUND_JAVA=1 + fi +fi + +if [ -z "$FOUND_JAVA" ] ; then if [ -e /opt-linux-x86_64/jre6 -a -e /opt-linux-x86_64/j2se6 ] ; then J2RE_HOME=/opt-linux-x86_64/jre6 JAVA_HOME=/opt-linux-x86_64/j2se6 diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index ec8757c..3f4fa9e 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -836,69 +836,74 @@ public class JavaEmitter implements GlueEmitter { } } - String structClassPkg = cfg.packageForStruct(name); - PrintWriter writer = null; - PrintWriter newWriter = null; + final String structClassPkg = cfg.packageForStruct(name); + final PrintWriter javaWriter; + final PrintWriter jniWriter; try { - writer = openFile( - cfg.javaOutputDir() + File.separator + - CodeGenUtils.packageAsPath(structClassPkg) + - File.separator + containingTypeName + ".java", containingTypeName); - CodeGenUtils.emitAutogeneratedWarning(writer, this); - if (needsNativeCode) { - String nRoot = cfg.nativeOutputDir(); - if (cfg.nativeOutputUsesJavaHierarchy()) { - nRoot += File.separator + CodeGenUtils.packageAsPath(cfg.packageName()); + javaWriter = openFile(cfg.javaOutputDir() + File.separator + + CodeGenUtils.packageAsPath(structClassPkg) + + File.separator + containingTypeName + ".java", containingTypeName); + if( null == javaWriter ) { + // suppress output if openFile deliberately returns null. + return; + } + CodeGenUtils.emitAutogeneratedWarning(javaWriter, this); + if (needsNativeCode) { + String nRoot = cfg.nativeOutputDir(); + if (cfg.nativeOutputUsesJavaHierarchy()) { + nRoot += File.separator + CodeGenUtils.packageAsPath(cfg.packageName()); + } + jniWriter = openFile(nRoot + File.separator + containingTypeName + "_JNI.c", containingTypeName); + CodeGenUtils.emitAutogeneratedWarning(jniWriter, this); + emitCHeader(jniWriter, containingTypeName); + } else { + jniWriter = null; } - newWriter = openFile(nRoot + File.separator + containingTypeName + "_JNI.c", containingTypeName); - CodeGenUtils.emitAutogeneratedWarning(newWriter, this); - emitCHeader(newWriter, containingTypeName); - } } catch(Exception e) { - throw new RuntimeException("Unable to open files for emission of struct class", e); + throw new RuntimeException("Unable to open files for emission of struct class", e); } - writer.println(); - writer.println("package " + structClassPkg + ";"); - writer.println(); - writer.println("import java.nio.*;"); - writer.println(); + javaWriter.println(); + javaWriter.println("package " + structClassPkg + ";"); + javaWriter.println(); + javaWriter.println("import java.nio.*;"); + javaWriter.println(); - writer.println("import " + cfg.gluegenRuntimePackage() + ".*;"); - writer.println("import " + DynamicLookupHelper.class.getPackage().getName() + ".*;"); - writer.println("import " + Buffers.class.getPackage().getName() + ".*;"); - writer.println("import " + MachineDescriptionRuntime.class.getName() + ";"); - writer.println(); + javaWriter.println("import " + cfg.gluegenRuntimePackage() + ".*;"); + javaWriter.println("import " + DynamicLookupHelper.class.getPackage().getName() + ".*;"); + javaWriter.println("import " + Buffers.class.getPackage().getName() + ".*;"); + javaWriter.println("import " + MachineDescriptionRuntime.class.getName() + ";"); + javaWriter.println(); List<String> imports = cfg.imports(); for (String str : imports) { - writer.print("import "); - writer.print(str); - writer.println(";"); + javaWriter.print("import "); + javaWriter.print(str); + javaWriter.println(";"); } - writer.println(); + javaWriter.println(); List<String> javadoc = cfg.javadocForClass(containingTypeName); for (String doc : javadoc) { - writer.println(doc); + javaWriter.println(doc); } - writer.print("public class " + containingTypeName + " "); + javaWriter.print("public class " + containingTypeName + " "); boolean firstIteration = true; List<String> userSpecifiedInterfaces = cfg.implementedInterfaces(containingTypeName); for (String userInterface : userSpecifiedInterfaces) { if (firstIteration) { - writer.print("implements "); + javaWriter.print("implements "); } firstIteration = false; - writer.print(userInterface); - writer.print(" "); - } - writer.println("{"); - writer.println(); - writer.println(" StructAccessor accessor;"); - writer.println(); - writer.println(" private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal();"); - writer.println(); + javaWriter.print(userInterface); + javaWriter.print(" "); + } + javaWriter.println("{"); + javaWriter.println(); + javaWriter.println(" StructAccessor accessor;"); + javaWriter.println(); + javaWriter.println(" private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal();"); + javaWriter.println(); // generate all offset and size arrays - generateOffsetAndSizeArrays(writer, containingTypeName, structType, null); /* w/o offset */ + generateOffsetAndSizeArrays(javaWriter, containingTypeName, structType, null); /* w/o offset */ for (int i = 0; i < structType.getNumFields(); i++) { final Field field = structType.getField(i); final Type fieldType = field.getType(); @@ -917,14 +922,14 @@ public class JavaEmitter implements GlueEmitter { field + "\" in type \"" + name + "\")"); } - generateOffsetAndSizeArrays(writer, fieldName, fieldType, field); + generateOffsetAndSizeArrays(javaWriter, fieldName, fieldType, field); } else if (fieldType.isArray()) { Type baseElementType = field.getType().asArray().getBaseElementType(); if(!baseElementType.isPrimitive()) break; - generateOffsetAndSizeArrays(writer, fieldName, null, field); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, fieldName, null, field); /* w/o size */ } else { JavaType externalJavaType = null; try { @@ -936,7 +941,7 @@ public class JavaEmitter implements GlueEmitter { } if (externalJavaType.isPrimitive()) { // Primitive type - generateOffsetAndSizeArrays(writer, fieldName, null, field); /* w/o size */ + generateOffsetAndSizeArrays(javaWriter, fieldName, null, field); /* w/o size */ } else { // FIXME LOG.log(WARNING, "Complicated fields (field \"{0}\" of type \"{1}\") not implemented yet", new Object[]{field, name}); @@ -946,27 +951,27 @@ public class JavaEmitter implements GlueEmitter { } } } - writer.println(); - - writer.println(" public static int size() {"); - writer.println(" return "+containingTypeName+"_size[mdIdx];"); - writer.println(" }"); - writer.println(); - writer.println(" public static " + containingTypeName + " create() {"); - writer.println(" return create(Buffers.newDirectByteBuffer(size()));"); - writer.println(" }"); - writer.println(); - writer.println(" public static " + containingTypeName + " create(java.nio.ByteBuffer buf) {"); - writer.println(" return new " + containingTypeName + "(buf);"); - writer.println(" }"); - writer.println(); - writer.println(" " + containingTypeName + "(java.nio.ByteBuffer buf) {"); - writer.println(" accessor = new StructAccessor(buf);"); - writer.println(" }"); - writer.println(); - writer.println(" public java.nio.ByteBuffer getBuffer() {"); - writer.println(" return accessor.getBuffer();"); - writer.println(" }"); + javaWriter.println(); + + javaWriter.println(" public static int size() {"); + javaWriter.println(" return "+containingTypeName+"_size[mdIdx];"); + javaWriter.println(" }"); + javaWriter.println(); + javaWriter.println(" public static " + containingTypeName + " create() {"); + javaWriter.println(" return create(Buffers.newDirectByteBuffer(size()));"); + javaWriter.println(" }"); + javaWriter.println(); + javaWriter.println(" public static " + containingTypeName + " create(java.nio.ByteBuffer buf) {"); + javaWriter.println(" return new " + containingTypeName + "(buf);"); + javaWriter.println(" }"); + javaWriter.println(); + javaWriter.println(" " + containingTypeName + "(java.nio.ByteBuffer buf) {"); + javaWriter.println(" accessor = new StructAccessor(buf);"); + javaWriter.println(" }"); + javaWriter.println(); + javaWriter.println(" public java.nio.ByteBuffer getBuffer() {"); + javaWriter.println(" return accessor.getBuffer();"); + javaWriter.println(" }"); for (int i = 0; i < structType.getNumFields(); i++) { final Field field = structType.getField(i); @@ -983,12 +988,12 @@ public class JavaEmitter implements GlueEmitter { FunctionSymbol funcSym = new FunctionSymbol(fieldName, funcType); MethodBinding binding = bindFunction(funcSym, containingType, containingCType, machDescJava); binding.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis - writer.println(); + javaWriter.println(); // Emit public Java entry point for calling this function pointer JavaMethodBindingEmitter emitter = new JavaMethodBindingEmitter(binding, - writer, + javaWriter, cfg.runtimeExceptionType(), cfg.unsupportedExceptionType(), true, @@ -1008,7 +1013,7 @@ public class JavaEmitter implements GlueEmitter { // Emit private native Java entry point for calling this function pointer emitter = new JavaMethodBindingEmitter(binding, - writer, + javaWriter, cfg.runtimeExceptionType(), cfg.unsupportedExceptionType(), false, @@ -1029,7 +1034,7 @@ public class JavaEmitter implements GlueEmitter { // Emit (private) C entry point for calling this function pointer CMethodBindingEmitter cEmitter = new CMethodBindingEmitter(binding, - newWriter, + jniWriter, structClassPkg, containingTypeName, true, // FIXME: this is optional at this point @@ -1052,12 +1057,12 @@ public class JavaEmitter implements GlueEmitter { field + "\" in type \"" + name + "\")"); } - writer.println(); - generateGetterSignature(writer, false, fieldType.getName(), capitalizeString(fieldName)); - writer.println(" {"); - writer.println(" return " + fieldType.getName() + ".create( accessor.slice( " + + javaWriter.println(); + generateGetterSignature(javaWriter, false, fieldType.getName(), capitalizeString(fieldName)); + javaWriter.println(" {"); + javaWriter.println(" return " + fieldType.getName() + ".create( accessor.slice( " + fieldName+"_offset[mdIdx], "+fieldName+"_size[mdIdx] ) );"); - writer.println(" }"); + javaWriter.println(" }"); } else if (fieldType.isArray()) { @@ -1070,18 +1075,18 @@ public class JavaEmitter implements GlueEmitter { String capitalized = capitalizeString(fieldName); // Setter - writer.println(); - generateSetterSignature(writer, false, containingTypeName, capitalized, paramType+"[]"); - writer.println(" {"); - writer.print (" accessor.set" + capitalizeString(paramType) + "sAt(" + fieldName+"_offset[mdIdx], val);"); - writer.println(" return this;"); - writer.println(" }"); - writer.println(); + javaWriter.println(); + generateSetterSignature(javaWriter, false, containingTypeName, capitalized, paramType+"[]"); + javaWriter.println(" {"); + javaWriter.print (" accessor.set" + capitalizeString(paramType) + "sAt(" + fieldName+"_offset[mdIdx], val);"); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + javaWriter.println(); // Getter - generateGetterSignature(writer, false, paramType+"[]", capitalized); - writer.println(" {"); - writer.print (" return accessor.get" + capitalizeString(paramType) + "sAt(" + fieldName+"_offset[mdIdx], new " +paramType+"["+fieldType.asArray().getLength()+"]);"); - writer.println(" }"); + generateGetterSignature(javaWriter, false, paramType+"[]", capitalized); + javaWriter.println(" {"); + javaWriter.print (" return accessor.get" + capitalizeString(paramType) + "sAt(" + fieldName+"_offset[mdIdx], new " +paramType+"["+fieldType.asArray().getLength()+"]);"); + javaWriter.println(" }"); } else { JavaType javaType = null; @@ -1111,40 +1116,40 @@ public class JavaEmitter implements GlueEmitter { ", sizeDenominator "+sizeDenominator); } - writer.println(); + javaWriter.println(); // Setter - generateSetterSignature(writer, false, containingTypeName, capFieldName, javaTypeName); - writer.println(" {"); + generateSetterSignature(javaWriter, false, containingTypeName, capFieldName, javaTypeName); + javaWriter.println(" {"); if( fieldTypeNativeSizeFixed ) { - writer.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val);"); + javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val);"); } else { - writer.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); + javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); } - writer.println(" return this;"); - writer.println(" }"); - writer.println(); + javaWriter.println(" return this;"); + javaWriter.println(" }"); + javaWriter.println(); // Getter - generateGetterSignature(writer, false, javaTypeName, capFieldName); - writer.println(" {"); - writer.print (" return "); + generateGetterSignature(javaWriter, false, javaTypeName, capFieldName); + javaWriter.println(" {"); + javaWriter.print (" return "); if( fieldTypeNativeSizeFixed ) { - writer.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx]);"); + javaWriter.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx]);"); } else { - writer.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); + javaWriter.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());"); } - writer.println(" }"); + javaWriter.println(" }"); } } } } - emitCustomJavaCode(writer, containingTypeName); - writer.println("}"); - writer.flush(); - writer.close(); + emitCustomJavaCode(javaWriter, containingTypeName); + javaWriter.println("}"); + javaWriter.flush(); + javaWriter.close(); if (needsNativeCode) { - newWriter.flush(); - newWriter.close(); + jniWriter.flush(); + jniWriter.close(); } } @Override @@ -1415,17 +1420,15 @@ public class JavaEmitter implements GlueEmitter { /** * @param filename the class's full filename to open w/ write access * @param simpleClassName the simple class name, i.e. w/o package name - * @return a {@link PrintWriter} instance to write the class source file + * @return a {@link PrintWriter} instance to write the class source file or <code>null</code> to suppress output! * @throws IOException */ protected PrintWriter openFile(String filename, String simpleClassName) throws IOException { //System.out.println("Trying to open: " + filename); - File file = new File(filename); - String parentDir = file.getParent(); - if (parentDir != null) - { - File pDirFile = new File(parentDir); - pDirFile.mkdirs(); + final File file = new File(filename); + final String parentDir = file.getParent(); + if (parentDir != null) { + new File(parentDir).mkdirs(); } return new PrintWriter(new BufferedWriter(new FileWriter(file))); } diff --git a/src/java/com/jogamp/gluegen/structgen/CStruct.java b/src/java/com/jogamp/gluegen/structgen/CStruct.java index 9d57196..be72cd8 100644 --- a/src/java/com/jogamp/gluegen/structgen/CStruct.java +++ b/src/java/com/jogamp/gluegen/structgen/CStruct.java @@ -33,21 +33,32 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * - * @author Michael Bien - * @author Sven Gothel, et.al. + * @author Michael Bien, et al. */ -@Target(value = {ElementType.FIELD, ElementType.LOCAL_VARIABLE}) +@Target(value = {ElementType.TYPE, ElementType.PACKAGE, ElementType.FIELD, ElementType.LOCAL_VARIABLE}) @Retention(value = RetentionPolicy.SOURCE) public @interface CStruct { /** * Relative path to the header file. + * <p> + * Mandatory. + * </p> */ String header(); /** * The name of the struct. + * <p> + * Mandatory for {@link ElementType.TYPE} and {@link ElementType.PACKAGE} annotations + * otherwise optional. + * </p> */ String name() default "_default_"; + + /** + * The optional java name of the struct. + */ + String jname() default "_default_"; + } diff --git a/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java b/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java index ee761a3..7b24967 100644 --- a/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java +++ b/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java @@ -30,12 +30,20 @@ package com.jogamp.gluegen.structgen; import com.jogamp.common.util.PropertyAccess; import com.jogamp.gluegen.GlueGen; import com.jogamp.gluegen.JavaEmitter; + +import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.io.Reader; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; + import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; @@ -76,11 +84,11 @@ import jogamp.common.Debug; * * @author Michael Bien, et al. */ -@SupportedAnnotationTypes(value = {"com.jogamp.gluegen.structgen.CStruct"}) +@SupportedAnnotationTypes(value = {"com.jogamp.gluegen.structgen.CStruct", "com.jogamp.gluegen.structgen.CStructs"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) public class CStructAnnotationProcessor extends AbstractProcessor { private static final String DEFAULT = "_default_"; - private static final boolean DEBUG; + static final boolean DEBUG; static { Debug.initSingleton(); @@ -131,71 +139,96 @@ public class CStructAnnotationProcessor extends AbstractProcessor { public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { final String user_dir = System.getProperty("user.dir"); - final Set<? extends Element> elements = env.getElementsAnnotatedWith(CStruct.class); - - for (Element element : elements) { - - final String packageName = eltUtils.getPackageOf(element).toString(); + final Set<? extends Element> cStructsElements = env.getElementsAnnotatedWith(CStructs.class); + for (Element structsElement : cStructsElements) { + final String packageName = eltUtils.getPackageOf(structsElement).toString(); + final CStructs cstructs = structsElement.getAnnotation(CStructs.class); + if( null != cstructs ) { + final CStruct[] cstructArray = cstructs.value(); + for(CStruct cstruct : cstructArray) { + processCStruct(cstruct, structsElement, packageName, user_dir); + } + } + } - try { - final CStruct struct = element.getAnnotation(CStruct.class); - final String headerRelPath = struct.header(); - final Element enclElement = element.getEnclosingElement(); + final Set<? extends Element> cStructElements = env.getElementsAnnotatedWith(CStruct.class); + for (Element structElement : cStructElements) { + final String packageName = eltUtils.getPackageOf(structElement).toString(); + final CStruct cstruct = structElement.getAnnotation(CStruct.class); + if( null != cstruct ) { + processCStruct(cstruct, structElement, packageName, user_dir); + } + } + return true; + } - System.err.println("CStruct: "+struct+", package "+packageName+", header "+headerRelPath); - if(DEBUG) { - System.err.println("CStruct.0: user.dir: "+user_dir); - System.err.println("CStruct.0: element: "+element+", .simpleName "+element.getSimpleName()); - System.err.println("CStruct.0: enclElement: "+enclElement+", .simpleName "+enclElement.getSimpleName()+", .package "+eltUtils.getPackageOf(enclElement).toString()); + private void processCStruct(final CStruct struct, final Element element, final String packageName, final String user_dir) { + try { + final String headerRelPath = struct.header(); + final Element enclElement = element.getEnclosingElement(); + final boolean isPackageOrType = null == enclElement; + + System.err.println("CStruct: "+struct+", package "+packageName+", header "+headerRelPath); + if(DEBUG) { + System.err.println("CStruct.0: user.dir: "+user_dir); + System.err.println("CStruct.0: element: "+element+", .simpleName "+element.getSimpleName()); + System.err.print("CStruct.0: isPackageOrType "+isPackageOrType+", enclElement: "+enclElement); + if( !isPackageOrType ) { + System.err.println(", .simpleName "+enclElement.getSimpleName()+", .package "+eltUtils.getPackageOf(enclElement).toString()); + } else { + System.err.println(""); } + } + if( isPackageOrType && struct.name().equals(DEFAULT) ) { + throw new IllegalArgumentException("CStruct annotation on package or type must have name specified: "+struct+" @ "+element); + } - final File headerFile; - { - File f = locateSource(packageName, headerRelPath); + final File headerFile; + { + File f = locateSource(packageName, headerRelPath); + if( null == f ) { + f = locateSource("", headerRelPath); if( null == f ) { - f = locateSource("", headerRelPath); - if( null == f ) { - // bail out - throw new RuntimeException("Could not locate header "+headerRelPath+", package "+packageName); - } + // bail out + throw new RuntimeException("Could not locate header "+headerRelPath+", package "+packageName); } - headerFile = f; } + headerFile = f; + } - final String root; - { - String root0 = headerFile.getAbsolutePath(); - root0 = root0.substring(0, root0.length()-headerFile.getName().length()-1); - root = root0.substring(0, root0.length()-packageName.length()) +".."; - } - System.err.println("CStruct: "+headerFile+", abs: "+headerFile.isAbsolute()+", root "+root); - - generateStructBinding(element, struct, root, packageName, headerFile); - } catch (IOException ex) { - throw new RuntimeException("IOException while processing!", ex); + final String rootOut, headerParent; + { + final String root0 = headerFile.getAbsolutePath(); + headerParent = root0.substring(0, root0.length()-headerFile.getName().length()-1); + rootOut = headerParent.substring(0, headerParent.length()-packageName.length()) + ".."; } + System.err.println("CStruct: "+headerFile+", abs: "+headerFile.isAbsolute()+", headerParent "+headerParent+", rootOut "+rootOut); + + generateStructBinding(element, struct, isPackageOrType, rootOut, packageName, headerFile, headerParent); + } catch (IOException ex) { + throw new RuntimeException("IOException while processing!", ex); } - return true; } - private void generateStructBinding(Element element, CStruct struct, String root, String pakage, File header) throws IOException { + private void generateStructBinding(Element element, CStruct struct, boolean isPackageOrType, String rootOut, String pakage, File header, String headerParent) throws IOException { final String declaredType = element.asType().toString(); - final String structName = struct.name().equals(DEFAULT) ? declaredType : struct.name(); - - if( generatedStructs.contains(structName) ) { - messager.printMessage(Kind.WARNING, "struct "+structName+" already defined elsewhere.", element); + final boolean useStructName = !struct.name().equals(DEFAULT); + final String structName = useStructName ? struct.name() : declaredType; + final boolean useJavaName = !struct.jname().equals(DEFAULT); + + final String finalType = useJavaName ? struct.jname() : ( !isPackageOrType ? declaredType : structName ); + System.err.println("CStruct: Generating struct accessor for struct: "+structName+" -> "+finalType+" [struct.name "+struct.name()+", struct.jname "+struct.jname()+", declaredType "+declaredType+"]"); + if( generatedStructs.contains(finalType) ) { + messager.printMessage(Kind.NOTE, "struct "+structName+" already defined elsewhere, skipping.", element); return; } - System.out.println("generating struct accessor for struct: "+structName); - - generatedStructs.add(structName); final boolean outputDirAbs; { final File outputDirFile = new File(outputPath); outputDirAbs = outputDirFile.isAbsolute(); } - final String outputPath1 = outputDirAbs ? outputPath : root + File.separator + outputPath; + final String outputPath1 = outputDirAbs ? outputPath : rootOut + File.separator + outputPath; final String config = outputPath1 + File.separator + header.getName() + ".cfg"; final File configFile = new File(config); if(DEBUG) { @@ -209,7 +242,8 @@ public class CStructAnnotationProcessor extends AbstractProcessor { writer = new FileWriter(configFile); writer.write("Package "+pakage+"\n"); writer.write("EmitStruct "+structName+"\n"); - if(!struct.name().equals(DEFAULT)) { + if( finalType != structName ) { + // We allow renaming the structType to the element's declaredType (FIELD annotation only) writer.write("RenameJavaType " + struct.name()+" " + declaredType +"\n"); } } finally { @@ -217,16 +251,23 @@ public class CStructAnnotationProcessor extends AbstractProcessor { writer.close(); } } - - // TODO: Handle exceptions .. suppressed by Gluegen.main(..) ? - GlueGen.main( - // "-I"+path+"/build/", - "-O" + outputPath1, - "-E" + AnnotationProcessorJavaStructEmitter.class.getName(), - "-C" + config, - header.getPath()); + final List<String> cfgFiles = new ArrayList<String>(); + cfgFiles.add(config); + final List<String> includePaths = new ArrayList<String>(); + includePaths.add(headerParent); + includePaths.add(outputPath1); + final Reader reader; + final String filename = header.getPath(); + try { + reader = new BufferedReader(new FileReader(filename)); + } catch (FileNotFoundException ex) { + throw new RuntimeException("input file not found", ex); + } + new GlueGen().run(reader, filename, AnnotationProcessorJavaStructEmitter.class, + includePaths, cfgFiles, outputPath1, false /* copyCPPOutput2Stderr */); configFile.delete(); + generatedStructs.add(finalType); } public static class AnnotationProcessorJavaStructEmitter extends JavaEmitter { @@ -234,14 +275,17 @@ public class CStructAnnotationProcessor extends AbstractProcessor { @Override protected PrintWriter openFile(String filename, String simpleClassName) throws IOException { + if( generatedStructs.contains(simpleClassName) ) { + System.err.println("skipping -> " + simpleClassName); + return null; + } + // look for recursive generated structs... keep it DRY if( !simpleClassName.endsWith("32") && !simpleClassName.endsWith("64") ) { - - System.out.println("generating -> " + simpleClassName); + System.err.println("generating -> " + simpleClassName); generatedStructs.add(simpleClassName); } - return super.openFile(filename, simpleClassName); } diff --git a/src/java/com/jogamp/gluegen/structgen/CStructs.java b/src/java/com/jogamp/gluegen/structgen/CStructs.java new file mode 100644 index 0000000..1023d3e --- /dev/null +++ b/src/java/com/jogamp/gluegen/structgen/CStructs.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010, Michael Bien. All rights reserved. + * Copyright (c) 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Michael Bien nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Michael Bien BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jogamp.gluegen.structgen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Multiple {@link CStruct} elements + */ +@Target(value = {ElementType.TYPE, ElementType.PACKAGE, ElementType.FIELD, ElementType.LOCAL_VARIABLE}) +@Retention(value = RetentionPolicy.SOURCE) +public @interface CStructs { + + /** + * Multiple {@link CStruct} elements. + */ + CStruct[] value(); +} diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/BuildStruct01.java b/src/junit/com/jogamp/gluegen/test/junit/structgen/BuildStruct01.java new file mode 100644 index 0000000..7824e55 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/BuildStruct01.java @@ -0,0 +1,34 @@ +package com.jogamp.gluegen.test.junit.structgen; + +import com.jogamp.gluegen.structgen.CStruct; + +/** + * Class simply triggering CStruct annotation processor to generate the types 'RenderingConfig' etc. + * <p> + * Due to Java8 issues, see Bug 923, + * using {@link package-info} is more elegant to kick-off the annotation processor. + * </p> + */ +public class BuildStruct01 { + + // APT is only triggered for fields, + // hence we use unused fields in this unit test! + + // @CStruct(name="RenderingConfig", header="TestStruct01.h") + // MyRenderingConfig config; + + // @CStruct(header="TestStruct01.h") + // MyRenderingConfig config; + + /** + * Java8: We cannot use type 'RenderingConfig' yet (bug?) even if not compiling. + * Hence we force the type-name via 'jname' and use a dummy variable! + */ + @CStruct(name="RenderingConfig", jname="RenderingConfig", header="TestStruct01.h") + boolean dummy1; + + @CStruct(name="Pixel", jname="Pixel", header="TestStruct02.h") + boolean dummy2; + + public static void initSingleton() {} +} diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStruct02.h b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStruct02.h new file mode 100644 index 0000000..64fda78 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStruct02.h @@ -0,0 +1,14 @@ +// +// TestStruct02.h +// + +#include "TestStruct01.h" + +typedef struct { + float r, g, b, a; +} Col4f; + +typedef struct { + Col4f color; + Vec3f pos; +} Pixel; diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java index 23b1624..74f0552 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java +++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java @@ -1,26 +1,23 @@ package com.jogamp.gluegen.test.junit.structgen; -import com.jogamp.gluegen.structgen.CStruct; import com.jogamp.junit.util.JunitTracer; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; - import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestStructGen01 extends JunitTracer { - // APT is only triggered for fields, - // hence we use unused fields in this unit test! - - // @CStruct(name="RenderingConfig", header="TestStruct01.h") - // MyRenderingConfig config; - - @CStruct(header="TestStruct01.h") - RenderingConfig config0; - + @BeforeClass + public static void init() { + // Enforce dependency, + // i.e. CStruct annotation processor to generate the types 'RenderingConfig' etc. + BuildStruct01.initSingleton(); + } + @Test public void test01() { RenderingConfig config = RenderingConfig.create(); @@ -46,10 +43,10 @@ public class TestStructGen01 extends JunitTracer { cam_orig.setY(1); cam_orig.setZ(2); } - + public static void main(String args[]) { String tstname = TestStructGen01.class.getName(); org.junit.runner.JUnitCore.main(tstname); } - + } diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java new file mode 100644 index 0000000..a8f0e52 --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java @@ -0,0 +1,51 @@ +package com.jogamp.gluegen.test.junit.structgen; + +import com.jogamp.junit.util.JunitTracer; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestStructGen02 extends JunitTracer { + + @BeforeClass + public static void init() { + // Enforce dependency, + // i.e. CStruct annotation processor to generate the types 'RenderingConfig' etc. + BuildStruct01.initSingleton(); + } + + @Test + public void test01() { + final Pixel pixel = Pixel.create(); + final Col4f color = pixel.getColor(); + color.setR(1f); + color.setG(2f); + color.setB(3f); + color.setA(4f); + final Vec3f pos = pixel.getPos(); + pos.setX(0.5f); + pos.setY(0.6f); + pos.setZ(0.7f); + + Pixel pixel2 = Pixel.create(pixel.getBuffer()); + final Col4f color2 = pixel2.getColor(); + Assert.assertEquals(color.getR(), color2.getR(), 0.0001f); + Assert.assertEquals(color.getG(), color2.getG(), 0.0001f); + Assert.assertEquals(color.getB(), color2.getB(), 0.0001f); + Assert.assertEquals(color.getA(), color2.getA(), 0.0001f); + final Vec3f pos2 = pixel2.getPos(); + Assert.assertEquals(pos.getX(), pos2.getX(), 0.0001f); + Assert.assertEquals(pos.getY(), pos2.getY(), 0.0001f); + Assert.assertEquals(pos.getZ(), pos2.getZ(), 0.0001f); + } + + public static void main(String args[]) { + String tstname = TestStructGen02.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/package-info.java b/src/junit/com/jogamp/gluegen/test/junit/structgen/package-info.java new file mode 100644 index 0000000..d009c5f --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/package-info.java @@ -0,0 +1,15 @@ +/** + * Package scope generation of {@link CStruct}s + * avoiding Java8 issues w/ annotation processing + * where the generated class is not yet available. + * <p> + * See Bug 923. + * </p> + * @see BuildStruct01 + */ +@CStructs({@CStruct(name="RenderingConfig", header="TestStruct01.h"), @CStruct(name="Pixel", header="TestStruct02.h")}) +package com.jogamp.gluegen.test.junit.structgen; + +import com.jogamp.gluegen.structgen.CStructs; +import com.jogamp.gluegen.structgen.CStruct; + diff --git a/test/junit/com/jogamp/gluegen/StructAccessorTest.java b/test/junit/com/jogamp/gluegen/StructAccessorTest.java index 4d1bffd..6c8d0e8 100644 --- a/test/junit/com/jogamp/gluegen/StructAccessorTest.java +++ b/test/junit/com/jogamp/gluegen/StructAccessorTest.java @@ -3,14 +3,14 @@ * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR @@ -20,12 +20,12 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ - + package com.jogamp.gluegen; import java.io.File; @@ -35,15 +35,18 @@ import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.List; import java.util.Locale; + import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; -import junit.framework.Assert; + import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Test; + import static java.lang.System.*; import static com.jogamp.gluegen.BuildUtil.*; |