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 /src/java/com/jogamp/gluegen/structgen | |
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)
Diffstat (limited to 'src/java/com/jogamp/gluegen/structgen')
3 files changed, 163 insertions, 62 deletions
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(); +} |