Reputation: 2571
I'm proficient in C but not in Java and I'm trying to use Swig to call C from Java. Simple calls work fine but I haven't been able to exchange arrays with either the carrays.i
or the arrays_java.i
methods. There aren't any complete examples of either.
AMItest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "carrays.i"
%include "AMItest.h"
AMItest.h:
extern int AMItest(double *Array, int Start, int End);
AMItest.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include "AMItest.h"
int AMItest(double *Array, int Start, int End) {
if (End<=Start) {
fprintf(stderr, "Start must be lower than End\n");
return EDOM;
}
for (int i=0; i<=End-Start; i++)
Array[i]=sin(i/4.);
return 0;
}
main.java:
public class main {
public static void main(String argv[]) {
System.loadLibrary("AMItest_swig"); // File is libAMItest_swig.so
double[] myArray = new double[11];
System.out.println(AMItest.AMItest(myArray, 10, 20));
for (int i=0; i<myArray.length; i++)
System.out.print(myArray[i] + " ");
}
}
Compilation:
$ rm -f AMItest AMItest*.java SWIG*.java *.class *.o *.a *.so *_wrap.c
$ swig -java AMItest.i
$ gcc -fPIC -c AMItest.c AMItest_wrap.c -I/usr/lib/jvm/java-11-openjdk-amd64/include -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux
$ gcc -shared AMItest.o AMItest_wrap.o -W -o libAMItest_swig.so
$ javac main.java
main.java:7: error: incompatible types: double[] cannot be converted to SWIGTYPE_p_double
System.out.println(AMItest.AMItest(myArray, 10, 20));
Googling for SWIGTYPE_p_* errors
leads to surprisingly few (unhelpful) links. I've also tried using arrays_java.i
or adding this to the .i file:
%array_functions( double, double )
%include <typemaps.i>
%apply (double *OUTPUT, int, int) {(double *Array, int Start, int End)};
Is this a problem with my .i file or with my Java ?!?
Upvotes: 0
Views: 578
Reputation: 27106
Adapt your AMItest.i like so:
%module AMItest
%{
#include "AMItest.h"
%}
%include "arrays_java.i"
%apply double[] {double *};
%include "AMItest.h"
Sometimes a C function expects an array to be passed as a pointer... One of the ways to wrap this is to apply the Java array typemaps that come in the arrays_java.i library file ... The ANY size will ensure the typemap is applied to arrays of all sizes. You could narrow the typemap matching rules by specifying a particular array size. Now you can use a pure Java array and pass it to the C code.
see documentation here: http://www.swig.org/Doc4.0/SWIGDocumentation.html#Java_unbounded_c_arrays
Test
Using your provided example with the modified AMItest.i as shown above, you will get the following output when calling java main
:
0
0.0 0.24740395925452294 0.479425538604203 0.6816387600233342 0.8414709848078965 0.9489846193555862 0.9974949866040544 0.9839859468739369 0.9092974268256817 0.7780731968879213 0.5984721441039564
More Efficient Alternative for Large Arrays
In the case of an array of 11 double elements, you probably want to use the method shown above. But I do not want to conceal the alternative method shown in the SWIG documentation:
This approach is probably the most natural way to use arrays. However, it suffers from performance problems when using large arrays as a lot of copying of the elements occurs in transferring the array from the Java world to the C++ world. An alternative approach to using Java arrays for C arrays is to use an alternative SWIG library file carrays.i. This approach can be more efficient for large arrays as the array is accessed one element at a time.
Your example would require modification in two places like this:
AKITest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "carrays.i"
%array_functions(double, doubleArray);
%include "AMItest.h"
Your slightly modified main.java would look like this then:
public class main {
public static void main(String argv[]) {
System.loadLibrary("AMItest_swig"); // File is libAMItest_swig.so
int size = 11;
SWIGTYPE_p_double myArray = AMItest.new_doubleArray(size);
AMItest.AMItest(myArray, 10, 20);
for (int i=0; i<size; i++)
System.out.print(AMItest.doubleArray_getitem(myArray, i) + " ");
}
}
The result would be the same.
Upvotes: 1