Wrapper with c++ for comunication fortran-Java

Wrapper with c++ for comunication fortran-Java

Hello,

I have a big problem. I want to call a routine in Java from Fortran dll. I have the wrapper c++ that let me conect with fortran, but when I try to compile the dll with the wrapper in c++ and the fortran code I obtain some link errors, for example, it does't find the symbol netcal. Should I compile the two codes together?? How I must compile it? I use compaq visual. I show you the simply code that I have.

the file in c++ is:

#include

#include "clase.h"

extern "C" void netcal(long*a, long*b, long*c);

JNIEXPORT void JNICALL Java_clase_netcal

(JNIEnv *, jobject, jint a, jint b, jint c)

{

netcal(&a, &b, &c);

};

and the code in fortran is:

subroutine netcal(a,b,c)

integer, target, intent(in)::a,b

integer, target, intent(out)::c

c=a+b

return

end subroutine netcal

Thank you very much!!

Jara

6 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Jugoslav Dujic's picture

You need to tell the Fortran compiler to lowercase the name:

subroutine netcal(a,b,c) bind(C, name="netcal")

integer, target, intent(in)::a,b
integer, target, intent(out)::c

c=a+b

end subroutine netcal
Jugoslav www.xeffort.com
Antti Karanta's picture

You may already have noticed that you won't recieve the value written to out param c to Java the way you are calling it.

As Java does not have out parameters, you need to e.g. use a size 1 int array, something like this:

JNIEXPORT void JNICALL Java_clase_netcal
(JNIEnv *env, jobject, jint a, jint b, jintArray c)
{

long cval ;

netcal(&a, &b, &cval);

(*env)->SetIntArrayRegion( env, c, 0, 1, &cval ) ;
}

Corresponding method in class clase:

native void netcal( int a, int b, int[] c ) ;

If you have more functions you must access from Java, I highly recommend to use swig (www.swig.org) to generate the jni glue for you.

Also note that if you do not use extern(c) in your fortran routine, you will have to (at least on windows) include the appropriate calling convention to the c prototype of the func (__stdcall on windows). I think extern(c) automatically uses the appropriate calling convention to interoperate with c (i.e. __cdecl). Note, however, that if you call the same (Fortran) routine from your Fortran code, you need to use explicit interfaces (e.g. have your code in a module) as otherwise the calling Fortran code will use the wrong calling convention ( on windows __stdcall when the called function is using __cdecl) and this will mess up your stack.

Jugoslav Dujic's picture

Quoting Antti Karanta
Also note that if you do not use extern(c) in your fortran routine, you will have to (at least on windows) include the appropriate calling convention to the c prototype of the func (__stdcall on windows). I think extern(c) automatically uses the appropriate calling convention to interoperate with c (i.e. __cdecl). Note, however, that if you call the same (Fortran) routine from your Fortran code, you need to use explicit interfaces (e.g. have your code in a module) as otherwise the calling Fortran code will use the wrong calling convention ( on windows __stdcall when the called function is using __cdecl) and this will mess up your stack.

No, stdcall is not "default" for Windows (it is for Win32 API, but that's entirely different context). Intel Fortran uses __cdecl by default, and BIND(C) attribute is designed to pick up the right calling convention (the one used by the "companion C processor") in any case.

Jugoslav www.xeffort.com

Note the OP refers to CVF, not Intel Fortran.

Antti Karanta's picture

I must have expressed myself badly. I meant cdecl is the default for c compilers as you said.

But I seem to have been wrong about stdcall being the default for ifort compiled routines - it is indeed cdecl. We are using /Gm compiler option which changes it to stdcall. I stand corrected.

Login to leave a comment.