From e24dc9a626d1548f67dc79b8f73c519c392bda33 Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Sun, 26 Feb 2006 10:21:31 +0000 Subject: Added five examples of GlueGen configuration files to the manual for supporting access to various C programming language constructs. Still need to add at least two more for concrete and somewhat complex examples which show up in JOGL. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/gluegen/trunk@18 a78bb65f-1512-4460-ba86-f6dc96a7bf27 --- doc/manual/example1/function.c | 3 + doc/manual/example1/function.cfg | 5 + doc/manual/example1/function.h | 1 + doc/manual/example1/gen.sh | 17 ++ doc/manual/example2/function.c | 17 ++ doc/manual/example2/function.cfg | 9 + doc/manual/example2/function.h | 3 + doc/manual/example2/gen.sh | 17 ++ doc/manual/example3/function.cfg | 16 ++ doc/manual/example3/function.h | 5 + doc/manual/example3/gen.sh | 17 ++ doc/manual/example4/function.c | 10 ++ doc/manual/example4/function.cfg | 12 ++ doc/manual/example4/function.h | 2 + doc/manual/example4/gen.sh | 17 ++ doc/manual/example5/function.c | 16 ++ doc/manual/example5/function.cfg | 9 + doc/manual/example5/function.h | 8 + doc/manual/example5/gen.sh | 17 ++ doc/manual/index.html | 371 ++++++++++++++++++++++++++++++++++++++- 20 files changed, 569 insertions(+), 3 deletions(-) create mode 100644 doc/manual/example1/function.c create mode 100644 doc/manual/example1/function.cfg create mode 100644 doc/manual/example1/function.h create mode 100644 doc/manual/example1/gen.sh create mode 100644 doc/manual/example2/function.c create mode 100644 doc/manual/example2/function.cfg create mode 100644 doc/manual/example2/function.h create mode 100644 doc/manual/example2/gen.sh create mode 100644 doc/manual/example3/function.cfg create mode 100644 doc/manual/example3/function.h create mode 100644 doc/manual/example3/gen.sh create mode 100644 doc/manual/example4/function.c create mode 100644 doc/manual/example4/function.cfg create mode 100644 doc/manual/example4/function.h create mode 100644 doc/manual/example4/gen.sh create mode 100644 doc/manual/example5/function.c create mode 100644 doc/manual/example5/function.cfg create mode 100644 doc/manual/example5/function.h create mode 100644 doc/manual/example5/gen.sh diff --git a/doc/manual/example1/function.c b/doc/manual/example1/function.c new file mode 100644 index 0000000..9a84189 --- /dev/null +++ b/doc/manual/example1/function.c @@ -0,0 +1,3 @@ +int one_plus(int a) { + return 1 + a; +} diff --git a/doc/manual/example1/function.cfg b/doc/manual/example1/function.cfg new file mode 100644 index 0000000..c604a40 --- /dev/null +++ b/doc/manual/example1/function.cfg @@ -0,0 +1,5 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native diff --git a/doc/manual/example1/function.h b/doc/manual/example1/function.h new file mode 100644 index 0000000..58976c1 --- /dev/null +++ b/doc/manual/example1/function.h @@ -0,0 +1 @@ +int one_plus(int a); diff --git a/doc/manual/example1/gen.sh b/doc/manual/example1/gen.sh new file mode 100644 index 0000000..6fb971e --- /dev/null +++ b/doc/manual/example1/gen.sh @@ -0,0 +1,17 @@ +#!/bin/ksh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/example2/function.c b/doc/manual/example2/function.c new file mode 100644 index 0000000..159ddb7 --- /dev/null +++ b/doc/manual/example2/function.c @@ -0,0 +1,17 @@ +float process_data(float* data, int n) { + int i; + float sum; + for (i = 0; i < n; i++) { + sum += data[i]; + } + return sum; +} + +float* global_data; +void set_global_data(float* data) { + global_data = data; +} + +float process_global_data(int n) { + return process_data(global_data, n); +} diff --git a/doc/manual/example2/function.cfg b/doc/manual/example2/function.cfg new file mode 100644 index 0000000..91d379b --- /dev/null +++ b/doc/manual/example2/function.cfg @@ -0,0 +1,9 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native + +# The semantics of set_global_data imply that +# only direct Buffers are legal +NioDirectOnly set_global_data diff --git a/doc/manual/example2/function.h b/doc/manual/example2/function.h new file mode 100644 index 0000000..af14bd2 --- /dev/null +++ b/doc/manual/example2/function.h @@ -0,0 +1,3 @@ +float process_data(float* data, int n); +void set_global_data(float* data); +float process_global_data(int n); diff --git a/doc/manual/example2/gen.sh b/doc/manual/example2/gen.sh new file mode 100644 index 0000000..3310b06 --- /dev/null +++ b/doc/manual/example2/gen.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/example3/function.cfg b/doc/manual/example3/function.cfg new file mode 100644 index 0000000..8ac334f --- /dev/null +++ b/doc/manual/example3/function.cfg @@ -0,0 +1,16 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native + +# strlen takes a string as argument +ArgumentIsString strlen 0 + +# strstr takes strings as arguments +ArgumentIsString strstr 0 1 +# it also returns a string +ReturnsString strstr + +CustomCCode /* Include string.h header */ +CustomCCode #include diff --git a/doc/manual/example3/function.h b/doc/manual/example3/function.h new file mode 100644 index 0000000..31ee673 --- /dev/null +++ b/doc/manual/example3/function.h @@ -0,0 +1,5 @@ +/* Give GlueGen a typedef for size_t */ +typedef int size_t; + +size_t strlen(const char* str); +char* strstr(const char* str1, const char* str2); diff --git a/doc/manual/example3/gen.sh b/doc/manual/example3/gen.sh new file mode 100644 index 0000000..6fb971e --- /dev/null +++ b/doc/manual/example3/gen.sh @@ -0,0 +1,17 @@ +#!/bin/ksh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/example4/function.c b/doc/manual/example4/function.c new file mode 100644 index 0000000..8666666 --- /dev/null +++ b/doc/manual/example4/function.c @@ -0,0 +1,10 @@ +#include +#include + +void* custom_allocate(int num_bytes) { + return malloc(num_bytes); +} + +void custom_free(void* data) { + free(data); +} diff --git a/doc/manual/example4/function.cfg b/doc/manual/example4/function.cfg new file mode 100644 index 0000000..feee635 --- /dev/null +++ b/doc/manual/example4/function.cfg @@ -0,0 +1,12 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native + +# The length of the returned ByteBuffer from custom_allocate is +# specified as the argument +ReturnValueCapacity custom_allocate {0} + +# custom_free will only ever receive a direct Buffer +NioDirectOnly custom_free diff --git a/doc/manual/example4/function.h b/doc/manual/example4/function.h new file mode 100644 index 0000000..8db77a1 --- /dev/null +++ b/doc/manual/example4/function.h @@ -0,0 +1,2 @@ +void* custom_allocate(int num_bytes); +void custom_free(void* data); diff --git a/doc/manual/example4/gen.sh b/doc/manual/example4/gen.sh new file mode 100644 index 0000000..6fb971e --- /dev/null +++ b/doc/manual/example4/gen.sh @@ -0,0 +1,17 @@ +#!/bin/ksh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/example5/function.c b/doc/manual/example5/function.c new file mode 100644 index 0000000..457b4a4 --- /dev/null +++ b/doc/manual/example5/function.c @@ -0,0 +1,16 @@ +static ScreenInfo default; +static int initialized = 0; + +ScreenInfo* default_screen_depth() { + if (!initialized) { + default.redBits = 8; + default.greenBits = 8; + default.blueBits = 8; + initialized = 1; + } + return &default; +} + +void set_screen_depth(ScreenInfo* info) { + /* Do something ... */ +} diff --git a/doc/manual/example5/function.cfg b/doc/manual/example5/function.cfg new file mode 100644 index 0000000..cb158ca --- /dev/null +++ b/doc/manual/example5/function.cfg @@ -0,0 +1,9 @@ +Package testfunction +Style AllStatic +JavaClass TestFunction +JavaOutputDir gensrc/java +NativeOutputDir gensrc/native + +# Tell GlueGen that default_screen_depth() returns a pointer to a +# single ScreenInfo +ReturnValueCapacity default_screen_depth sizeof(ScreenInfo) diff --git a/doc/manual/example5/function.h b/doc/manual/example5/function.h new file mode 100644 index 0000000..d845887 --- /dev/null +++ b/doc/manual/example5/function.h @@ -0,0 +1,8 @@ +typedef struct { + int redBits; + int greenBits; + int blueBits; +} ScreenInfo; + +ScreenInfo* default_screen_depth(); +void set_screen_depth(ScreenInfo* info); diff --git a/doc/manual/example5/gen.sh b/doc/manual/example5/gen.sh new file mode 100644 index 0000000..6fb971e --- /dev/null +++ b/doc/manual/example5/gen.sh @@ -0,0 +1,17 @@ +#!/bin/ksh + +JAVA=java +GLUEGEN_JAR=../../../build/gluegen.jar +ANTLR_JAR=../../../../../ANTLR/antlr-2.7.4/antlr.jar + +NAME=`uname` + +if [ $NAME="Windows*" ] ; then + SEP=\; +elif [ $NAME="CYGWIN*" ] ; then + SEP=\; +else + SEP=: +fi + +java -cp $GLUEGEN_JAR$SEP$ANTLR_JAR com.sun.gluegen.GlueGen -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h diff --git a/doc/manual/index.html b/doc/manual/index.html index cbeea8e..e2e0fbc 100755 --- a/doc/manual/index.html +++ b/doc/manual/index.html @@ -38,11 +38,19 @@ Chapter 2 - Using GlueGen Chapter 3 - Configuration File Examples
+ + TO DO: +
  • Example with XVisualInfo* return type
  • Example with GLXFBConfig* (e.g. glXChooseFBConfig) -
  • More...

Chapter 1 - Introduction

@@ -1290,8 +1298,11 @@ and TemporaryCVariableAssignment directives. (optional) Indicates that the specified C function which returns a char* or compatible type actually returns a null-terminated C string which should be exposed as a -java.lang.String. - +java.lang.String. NOTE: currently does not properly handle the case +where this storage needs to be freed by the end user. In these +situations the data should be returned as a direct ByteBuffer, the +ByteBuffer converted to a String using custom Java code, and the +ByteBuffer freed manually using another function bound to Java.
ReturnValueCapacity
Syntax: ReturnValueCapacity [C function name] @@ -1606,5 +1617,359 @@ the header. +

Chapter 3 - Configuration File Examples

+ +

Simplest possible example

+ +Files: + + +

This example shows the simplest possible usage of GlueGen; a +single routine taking as arguments and returning only primitive +types. The signature of the C function we are interested in binding is +

+ +
+  int one_plus(int a);
+
+ +

To bind this function to Java, we only need a configuration file +with very basic settings, indicating the style of glue code emission, +the package and class into which the glue code will be generated, and +the output directories for the Java and native code. The contents of +the configuration file are as follows:

+ +
+  Package testfunction
+  Style AllStatic
+  JavaClass TestFunction
+  JavaOutputDir   gensrc/java
+  NativeOutputDir gensrc/native
+
+ +

GlueGen can then be invoked with approximately the following +command line:

+ +
+  java -cp gluegen.jar:antlr.jar com.sun.gluegen.GlueGen \
+    -I. -Ecom.sun.gluegen.JavaEmitter -Cfunction.cfg function.h
+
+ +

The resulting Java and native code needs to be compiled, and the +application needs to load the native library for the Java binding +before attempting to invoke the native method by calling +System.load() or System.loadLibrary().

+ +

Arrays and buffers

+ +Files: + + +

This example shows how C primitive arrays are bound to Java. The +header file contains three functions to bind:

+ +
+  float process_data(float* data, int n);
+  void set_global_data(float* data);
+  float process_global_data(int n);
+
+ +

The semantics of process_data are that it takes in a +pointer to a set of primitive float values and the number +of elements in the array and performs some operation on them, +returning a floating-point value as the result. Afterward the passed +data is no longer referenced.

+ +

set_global_data, on the other hand, takes a pointer +to the data and stores it persistently in the C code. +process_global_data then accepts as argument the number +of elements to process from the previously-set global data, performs +this processing and returns a result. The global data may be accessed +again afterward. As an example, these kinds of semantics are used in +certain places in the OpenGL API.

+ +

From a Java binding standpoint, process_data may +accept data stored either inside the Java heap (in the form of a +float[] or non-direct FloatBuffer) or +outside the Java heap (in the form of a direct +FloatBuffer), because it does not access the data after +the function call has completed and therefore would not be affected if +garbage collection moved the data after the function call was +complete. However, set_global_data can cause the passed +data to be accessed after the function call is complete, if +process_global_data is called. Therefore the data passed +to set_global_data may not reside in the Java +garbage-collected heap, but must reside outside the heap in the form +of a direct FloatBuffer.

+ +

It is straightforward to take into account these differences in +semantics in the configuration file using the NioDirectOnly directive:

+ +
+  # The semantics of set_global_data imply that
+  # only direct Buffers are legal
+  NioDirectOnly set_global_data
+
+ +

Note the differences in the generated Java-side overloadings for +the two functions:

+ +
+  public static void process_data(java.nio.FloatBuffer data, int n) {...}
+  public static void process_data(float[] data, int data_offset, int n) {...}
+  public static void set_global_data(java.nio.FloatBuffer data) {...}
+
+ +

No overloading is produced for set_global_data taking +a float[], as it can not handle data residing in the Java +heap. Further, the generated glue code will verify that any +FloatBuffer passed to this routine is direct, throwing a +RuntimeException if not. The type of the exception thrown +in this and other cases may be changed with the RuntimeExceptionType directive. + +

String handling

+ +Files: + + +

This example shows how to pass and return C strings. The functions +involved are a bit contrived, as nobody would ever need to bind the C +library's string handling routines to Java, but they do illustrate +situations in which Java strings might need to be passed to C and C +strings returned to Java. As an example, both styles of function are +present in the OpenGL and OpenAL APIs.

+ +

The included source code exposes two functions to Java:

+ +
+  size_t strlen(const char* str);
+  char*  strstr(const char* str1, const char* str2);
+
+ +

Note that we might just as easily parse the C standard library's +string.h header file to pick up these function +declarations. However for the purposes of this example it is easier to +extract just the functions we need.

+ +

Note that the function.h header +file contains a typedef for size_t. This is needed +because GlueGen does not inherently know about this data type. An +equivalent data type for the purposes of this example is +int, so we choose to tell GlueGen to use that data type +in place of size_t while generating glue code.

+ +

The following directive in the configuration file tells GlueGen +that strlen takes a string as argument 0 (the first +argument):

+ +
+  ArgumentIsString strlen 0
+
+ +

The following directive tells GlueGen that strstr +takes two strings as its arguments:

+ +
+  ArgumentIsString strstr 0 1
+
+ +

Finally, the following directive tells GlueGen that +strstr returns a string instead of an array of bytes: +

+ +
+  ReturnsString strstr
+
+ +

We also use the CustomCCode directive +to cause the string.h header file to be #included in the +generated glue code:

+ +
+  CustomCCode /* Include string.h header */
+  CustomCCode #include <string.h>
+
+ +

Now the bindings of these two functions to Java look as expected: +

+ +

+  public static native int strlen(java.lang.String str);
+  public static native java.lang.String strstr(java.lang.String str1,
+                                               java.lang.String str2);
+
+ +Note that the ReturnsString directive +does not currently correctly handle the case where the +char* returned from C needs to be explicitly freed. As an +example, a binding of the C function strdup using a +ReturnsString directive would cause a C heap memory leak. + +

Memory allocation

+ +Files: + + +

This example shows how memory allocation is handled when binding C +to Java. It gives the example of a custom memory allocator being bound +to Java; this is a construct that at least at one point was present in +OpenGL in the NV_vertex_array_range extension.

+ +

The two functions we are exposing to Java are as follows:

+
+  void* custom_allocate(int num_bytes);
+  void  custom_free(void* data);
+
+ +

The Java-side return type of custom_allocate will +necessarily be a ByteBuffer, as that is the only useful +way of interacting with arbitrary memory produced by C. The question +is how to inform the glue code generator of the size of the returned +sequence of memory. The semantics of custom_allocate are +obvious to the programmer; the incoming num_bytes +argument specifies the amount of returned memory. We tell GlueGen this +fact using the ReturnValueCapacity +directive:

+ +
+  # The length of the returned ByteBuffer from custom_allocate is
+  # specified as the argument
+  ReturnValueCapacity custom_allocate {0}
+
+ +

Note that we name incoming argument 0 with the MessageFormat +specifier "{0}" rather than the explicit name of the parameter +("num_bytes") for generality, in case the header file is changed +later.

+ +

Because custom_free will only ever receive Buffers +produced by custom_allocate, we use the NioDirectOnly directive to prevent +accidental usage with the wrong kind of Buffer:

+ +
+  # custom_free will only ever receive a direct Buffer
+  NioDirectOnly custom_free
+
+ +

The generated Java APIs for these functions are as follows:

+ +
+  public static java.nio.ByteBuffer custom_allocate(int num_bytes) {...}
+  public static void custom_free(java.nio.Buffer data) {...}
+
+ +

Ingoing and outgoing structs

+ +Files: + + +

This example shows how GlueGen provides access to C structs and +supports both passing them to and returning them from C functions. The +header file defines a sample data structure that might describe the +bit depth of a given screen:

+ +
+  typedef struct {
+    int redBits;
+    int greenBits;
+    int blueBits;
+  } ScreenInfo;
+
+ +

Two functions are defined which take and return this data type: +

+ +
+  ScreenInfo* default_screen_depth();
+  void set_screen_depth(ScreenInfo* info);
+
+ +

The semantics of default_screen_depth() are that it +returns a pointer to some static storage which does not need to be +freed, which describes the default screen depth. +set_screen_depth() is a hypothetical function which would +take a newly-allocated ScreenInfo and cause the primary +display to switch to the specified bit depth.

+ +

The only additional information we need to tell GlueGen, beyond +that in the header file, is how much storage is returned from +default_screen_depth(). Note the semantic ambiguity, +where it might return a pointer to a single ScreenInfo or +a pointer to an array of ScreenInfos. We tell GlueGen +that the return value is a single value with the ReturnValueCapacity directive, +similarly to the memory allocation example +above:

+ +
+  # Tell GlueGen that default_screen_depth() returns a pointer to a
+  # single ScreenInfo
+  ReturnValueCapacity default_screen_depth sizeof(ScreenInfo)
+
+ +

Note that if default_screen_depth had returned +newly-allocated storage, it would be up to the user to expose a +free() function to Java and call it when necessary.

+ +

GlueGen automatically generates a Java-side +ScreenInfo class which supports not only access to any +such objects returned from C, but also allocation of new +ScreenInfo structs which can be passed (persistently) +down to C. The Java API for the ScreenInfo class looks like this:

+ +
+  public abstract class ScreenInfo {
+    public static ScreenInfo create();
+    public abstract ScreenInfo redBits(int val);
+    public abstract int redBits();
+    ...
+  }
+
+ +

The create() method allocates a new ScreenInfo struct +which may be passed, even persistently, out to C. Its C-heap storage +will be automatically reclaimed when the Java-side ScreenInfo object +is no longer reachable, as it is backed by a direct New I/O +ByteBuffer. The fields of the struct are exposed as +methods which supply both getters and setters.

+ + + + + + + + + + + + -- cgit v1.2.3