This post is a really simple example to understand how to manage (from Java application) a C array of complex structure.
After reading Swig 3 documentation and searching on the net, I've finally succeed to create a little poc on how to return a list of struct.
proof of concept sample includes 4 functions:
- a function
sumitems
that accept an array of integer as parameter to calculate a sum (part of Swig3 documentation) - a function
populateSampleItem
that just write on a given simple structure - a function
populateItems
that update an existing array of struct - a function
buildItems
that create from scratch a result array of struct
source of this poc is available here : https://github.com/boly38/pocswig
this poc is widely inspirated from similar example from "Samuel Jacob's Weblog" post (thanks to him !)
First file to write is the C header
poc.h
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* (in) simple int array as parameter */ int sumitems(int *first, int nitems); /* simple structure */ typedef struct MyItem_t { int id; char *name; } MyItem; /* (in/out) simple struct as parameter (updated by the function) */ void populateSampleItem(MyItem *item); /* array of structure */ typedef struct MyItems_t { int count; // elements count MyItem *elements; // array of MyItem } MyItems; /* (in/out) array of structure as parameter (updated by the function) */ void populateItems(MyItems *items); /* (out) array of structure (generated by the function) */ MyItems *buildItems(); |
poc.c
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include <stdlib.h> #include <stdio.h> #include <string.h> #include "poc.h" int sumitems(int *first, int nitems) { int i, sum = 0; for (i = 0; i < nitems; i++) { sum += first[i]; } return sum; } void populateSampleItem(MyItem *item) { item->id = 1234; item->name = strdup("getSampleItem"); } void populateItems(MyItems *items) { int nb = items->count; items->elements = malloc(nb * sizeof(MyItem)); for (int j=nb-1;j>=0;j--) { items->elements[j].id = j; char elementName[80]; sprintf(elementName, "populateItems %d", j); items->elements[j].name = strdup(elementName); } } MyItems *buildItems() { printf("buildItems 14 elements"); int nb = 14; MyItems *items= malloc(sizeof(MyItems));; items->count = nb; items->elements = malloc(nb * sizeof(MyItem)); for (int j=nb-1;j>=0;j--) { items->elements[j].id = j; char elementName[80]; sprintf(elementName, "buildItems %d", j); items->elements[j].name = strdup(elementName); } return items; } |
And now to access this function from java, you will have to use Swig.
Swig use a specification file to setup how to map function/types/etc... This file is a
.i
file. Here is the file poc.i
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | %module swigpoc %include "arrays_java.i"; %apply int[] {int *}; %{ #include "poc.h" %} %include "poc.h"; %extend MyItems_t{ MyItem * getElement(int i) { return &$self->elements[i]; } } |
Line 3&4 define how to handle int array using swig facility,
Line 6 to 8 to tell to Swig to output include line into the target wrapper file.
Line 10 reuse as is the header file as specification (Swig MUST wrap all header file methods and structs to Java).
Line 11 to 15 to tell to Swig to append an extra function to help Java user to access to array element.
Now you will have to generate Java files! Use Swig :
rm -f *Item.java *.o *.dll swigpoc* swig -java poc.iYou could look at your directory, there is some new C and Java files:
poc_wrap.c, MyItem.java, MyItems.java, swigpoc.java swigpocJNI.java
Next step is to build up the DLL (shared library) (exemple under Cygwin):
1 2 3 4 5 6 | #!/bin/bash JAVA_HOME=/cygdrive/c//Programmes/Java/jdk1.8.0_112/ INCLUDES="-I$JAVA_HOME/include/ -I$JAVA_HOME/include/win32/" x86_64-w64-mingw32-gcc.exe -c poc.c poc_wrap.c $INCLUDES x86_64-w64-mingw32-gcc.exe $INCLUDES -shared -o poc.dll poc_wrap.o poc.o |
PocExample.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public class PocExample { static { System.out.println("load poc ..."); System.loadLibrary("poc"); System.out.println("load poc ... OK "); } public static void main(String args[]) { System.out.println("poc"); System.out.println("sumitems:"); int[] arrayB = new int[10000000]; // Array of 10-million integers for (int i=0; i<arrayB.length; i++) { // Set some values arrayB[i] = i; } int sum = swigpoc.sumitems(arrayB, 10000); System.out.println("SumB = " + sum); System.out.println("MyItem:"); MyItem myt = new MyItem(); swigpoc.populateSampleItem(myt); System.out.println("myt.name = " + myt.getName()); MyItems myts = new MyItems(); myts.setCount(10); swigpoc.populateItems(myts); for (int j=0; j<myts.getCount(); j++) { System.out.println(String.format("myts.element[%d].name = '%s'",j, myts.getElement(j).getName())); System.out.println(String.format("myts.element[%d].id = '%s'" ,j, myts.getElement(j).getId())); } MyItems rez = swigpoc.buildItems(); for (int k=0; k<rez.getCount(); k++) { System.out.println(String.format("rez.element[%d].name = '%s'",k, rez.getElement(k).getName())); System.out.println(String.format("rez.element[%d].id = '%s'" ,k, rez.getElement(k).getId())); } } } |
I let you execute that:
1 2 3 | #!/bin/bash JAVA_HOME=/cygdrive/c//Programmes/Java/jdk1.8.0_112/ $JAVA_HOME/bin/javac *.java && $JAVA_HOME/bin/java PocExample |
If you see something wrong, please tell me. Else hopes this helps!
Aucun commentaire:
Enregistrer un commentaire