Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28528 Discussions

This should be fun - Java calling mixed lang dll

pecan204
Beginner
656 Views
Hoping there are some strong cross language programmers out there.

I am trying to run this example of a java class calling a dll with a c++ interface.

The first error I get is:
C:jdk1.4.1Jnijava-fortranJniDemo_r1.cpp(55) : error C2664: 'f90sub_' : cannot convert parameter 1 from 'long *' to 'int *'
Error executing cl.exe.

jniDemoCXF.dll - 1 error(s), 3 warning(s)

I am not certain how to correct in the mixed langage dll portion. I included the java files if there is an interest to look further.

Thanks for any help.
0 Kudos
13 Replies
Jugoslav_Dujic
Valued Contributor II
656 Views
I can't help much -- all I can say that the error says that int_A argument to Fortran is declared as int*, and in Java_JniDemo_cppsub int_A is declared as long*. Apparently, a jint is #defined or typedefed as long in jni.h. Since long and int are both 32-bit on 32-bit systems, just replace int* int_A with long* int_A in declaration of f90sub and the error should go away... of course, that doesn't mean it will work as well.

Jugoslav
0 Kudos
pecan204
Beginner
656 Views
That worked for the compile. Thanks

Working on the link now. Does anyone know if VF can do a mixed language DLL?

I know there are examples for a mixed language executable.

0 Kudos
Steven_L_Intel1
Employee
656 Views
Certainly CVF can handle a mixed language (Fortran/C) DLL. You do need to make sure that you have libraries specified the same for Fortran and C.

Steve
0 Kudos
pecan204
Beginner
656 Views
I tried it similar to the examples setup except I created a DLL project and another DLL project dependancy.

I get the following error. I don't see that it creates a .lib file. What controls that?

Linking...
LINK : fatal error LNK1181: cannot open input file ".F90sub_r1DebugF90sub_r1.lib"
Error executing link.exe.

jniDemo - 1 error(s), 0 warning(s)

Thanks for the help.

Ken
0 Kudos
Jugoslav_Dujic
Valued Contributor II
656 Views
.lib file will not be created if there isn't any DLLEXPORTed symbol.
0 Kudos
pecan204
Beginner
656 Views
I did include the export command in the fortran below so wouldn't you expect a .lib file.

!DEC$ ATTRIBUTES DLLEXPORT :: DLL_ROUT

Maybe CVF does not understand the C side export to Java?

JNIEXPORT void JNICALL Java_JniDemo_cppsub .....

Thanks
0 Kudos
Jugoslav_Dujic
Valued Contributor II
656 Views
OK, I downloaded that zip file. (I didn't manage to compile all since I don't have JDK).

Two^H^H^H... Three^H^H^H... FOUR issues:
1) In Project/Settings/Link/Output for f90 side, it should be "F90sub_r1.dll"

2) Well, you're dllexporting DLL_ROUT which doesn't exist -- a "thoughtful" copy & paste?

3) Name mangling will be the next issue when you fix these -- by default, CVF will export _F90SUB_R1@n and
C will try to import _f90sub_r1@n. You can use ALIAS directive in CVF to adjust that:
!DEC$ATTRIBUTES DLLEXPORT, DECORATE, ALIAS: "f90sub_r1":: f90sub_r1


4) You appear to be screwing the way string arguments are passed (str_A etc.). By default, when you write one string as Fortran argument, you have to write two in C. You're writing 1:1. That behaviour can be modified as well using STDCALL and REFERENCE attrigutes, but length must be passed separately (as you already do), i.e.

!DEC$ATTRIBUTES DLLEXPORT, DECORATE, STDCALL, REFERENCE, ALIAS: "f90sub_r1":: f90sub_r1


should be OK. (Actually, DECORATE & ALIAS are now unnecessary since STDCALL implies lowercase).

As you see, combinations of attributes are a bit tricky to get right (since one affects many things simultaneously) -- read the Mixed-language chapter (again? ;-)) carefully.

HTH
Jugoslav
0 Kudos
pecan204
Beginner
656 Views
Please disregard last post. I had mispecified the import subroutine name.

It should be !DEC$ ATTRIBUTES DLLEXPORT :: f90sub_r1
also in the .cpp file.

Both c++ and fortran files compile. The Fortran produces a .lib aand .dll file.

The JniDemo produces a .lib file but no .dll even though there is the link error below.

Any thoughts?

--------------------Configuration: jniDemo - Win32 Debug--------------------
Linking...
Creating library Debug/jniDemo.lib and object Debug/jniDemo.exp
JniDemo_r1.obj : error LNK2001: unresolved external symbol __imp__F90sub_r1@56
jniDemo : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

jniDemo - 2 error(s), 0 warning(s)
0 Kudos
Jugoslav_Dujic
Valued Contributor II
656 Views
See that uppercase "F" in __imp__F90sub_r1@56? Exported symbols are case-sensitive. C is case-sensitive as well. Make sure that you declare Fortran function in C code in the same way it is dllexported; if you want mixed-case symbols, you must use ALIAS attribute.

You can examine the actual exports from a dll using DUMPBIN command-line utility with /exports flag.
0 Kudos
pecan204
Beginner
656 Views
Thanks for the comments.

I went over the files again and implemented the suggested changes. I rearranged the str_A_len and str_B_len to be after the string variables for the hidden argument passing in the cpp file.

I get a 56 to 64 byte mismatch between the fortran amd c files furing the link. I am not sure which one is off.

I checked out dumpbin but it doesn't show much just the _F90SUB@64 if the ATTRIBUTES command is DLLEXPORT or F90SUB if it was suggested above. Is there away to see the individual variable sizes with some attribute selection and dumpbin?

Here is the error.

Linking...
Creating library Debug/JniDemo.lib and object Debug/JniDemo.exp
JniDemo.obj : error LNK2001: unresolved external symbol _F90SUB@56
JniDemo : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

JniDemo - 2 error(s), 0 warning(s)

Thanks the help. Not sure what next.

Ken

0 Kudos
Jugoslav_Dujic
Valued Contributor II
656 Views
Here are few correct ways -- pick one (I shortened the list to strings only):
=1======
SUBROUTINE F90sub(str_A, str_b)
!DEC$ATTRIBUTES DLLEXPORT: F90sub
CHARACTER(*):: str_A, str_b
---
extern "C" void _declspec(dllimport) __stdcall  
F90SUB(char* str_A, int len_str_A, char* str_B, int len_str_B)
=2======
SUBROUTINE F90sub(str_A, str_b)
!DEC$ATTRIBUTES DLLEXPORT, STDCALL: F90sub
CHARACTER(*):: str_A, str_b
---
extern "C" void _declspec(dllimport) __stdcall  
f90sub(char* str_A, int len_str_A, char* str_B, int len_str_B)
=3======
SUBROUTINE F90sub(str_A, str_b, len_str_A, len_str_B)
!DEC$ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE:: F90sub
!With REFERENCE, hidden length is not passed so you should
!pass it manually:
CHARACTER(len_str_A):: str_A
CHARACTER(len_str_B):: str_B
---
//Since len_ arguments are ordinary integers, they should 
//be passed by reference:
extern "C" void _declspec(dllimport) __stdcall  
f90sub(char* str_A, char* str_B, int* len_str_A, int* len_str_B)
=4======
SUBROUTINE F90sub(str_A, str_b, len_str_A, len_str_B)
!DEC$ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE, DECORATE, ALIAS: "f90SuB" :: F90sub
!With REFERENCE, hidden length is not passed so you should
!pass it manually:
CHARACTER(len_str_A):: str_A
CHARACTER(len_str_B):: str_B
---
extern "C" void _declspec(dllimport) __stdcall  
f90SuB(char* str_A, char* str_B, int* len_str_A, int* len_str_B)
=5======
SUBROUTINE F90sub(str_A, str_b, len_str_A, len_str_B)
!DEC$ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE,  ALIAS: "_f90SuB@16" :: F90sub
!With REFERENCE, hidden length is not passed so you should
!pass it manually:
CHARACTER(len_str_A):: str_A
CHARACTER(len_str_B):: str_B
---
extern "C" void _declspec(dllimport) __stdcall  
f90SuB(char* str_A, char* str_B, int* len_str_A, int* len_str_B)

etc. etc. -- combinations are infinite.

The hidden string length is passed by value, not by reference, so it should be int str_A_len, not int*.

@56 is simply the 4*(number of arguments). You cannot pass entities greater than 32 bytes anyway -- depending on reference/value, either the address (32 bit) or value of the variable (<=32 bit) is placed on the stack. Arrays are always passed by reference, and structures also in 99% cases.

Side note: do NOT use ALIAS to cheat on @56 (number of arguments) part -- this is a road to catastrophe. Use ALIAS only to change case.

Jugoslav
0 Kudos
Jugoslav_Dujic
Valued Contributor II
656 Views
Aaargh! Cancel! Sorry...

I've just read this in online help:

- If C or STDCALL is specified, and REFERENCE is specified for the argument:
On all systems, the string is passed with no length.

- If C or STDCALL is specified, and REFERENCE is specified for the routine (but REFERENCE is not specified for the argument, if any):
On all systems, the string is passed with the length.


I didn't know about the second issue. Thus, in samples 3-5, the line:
!DEC$ATTRIBUTES REFERENCE:: str_A, str_B
must be added on Fortran side.

Jugoslav
0 Kudos
pecan204
Beginner
656 Views
Thanks for the assistance Yugoslav.

I did get a reduced down version to link as a DLL.

I am trying to get the java to link to that now.

The reason I started with the longer sample was because it was already working on a solaris system. Thought it would be a few simple changes.

Will post the complete set if I can get it working.

Ken
0 Kudos
Reply