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

Calling a dll made with Fortran by C

patuco
Beginner
7,018 Views
Hi,
i am getting crazy tying to find out where or why is teh problem in the program I'm doing. If someone could help me, it would be great.
Ill explain you my problem:
i am doing some test to try out how the jni of javaworks. i implemented a dumy program which only purpose is to call a Frotran dll which has to show on the screen the typical Hello world. I did the C++ wrapper using the visual studio .net. Ive already accomplished the communication between the wrapper and Java. in a second stage I try to do the same but with the wrapper calling the fortran dll, and here is where the problems occur: the function called by the wrapper located in the fortran dll is not "found":
ReadValue error LNK2019: smbolo externo _PRINTER@0 sin resolver al que se hace referencia en la funcin "long __stdcall Java_ReadValue_getValue(struct JNIEnv_ *,class _jobject *)" (?Java_ReadValue_getValue@@YGJPAUJNIEnv_@@PAV_jobject@@@Z)
The Fortran code is as follows:
INTEGER FUNCTION PRINTER()
!decs attributes c :: PRINTER
!MS$ATTRIBUTES DLLEXPORT,STDCALL,ALIAS:'PRINTER'::PRINTER
WRITE(6,'("-- FORTRAN funcion printer --")')
PRINTER=2
END
as you can observed is quite obvious.
So as the wrapper:

#include "stdafx.h"

#include "stdio.h"

#include "ReadValue.h"

#include "jni.h"

extern "C" __stdcall int PRINTER();

// i even try with : extern "C" __cdecl int PRINTER();

JNIEXPORT jint JNICALL Java_ReadValue_getValue(JNIEnv * env, jobject jobj)

{

printf("-- A ver si funciona la referencia -- ");

int result = PRINTER();

printf(" -- valor de retorno ke leyo del archivo -- ",result);

return result;

}

Anyone can help me?? Thanks.

0 Kudos
78 Replies
Jugoslav_Dujic
Valued Contributor II
2,478 Views
!DEC$ATTRIBUTES syntax is a bit difficult to get right -- and you got it wrong :-). Here we go:


  • all symbols have prepended an underscore (unless overriden with ALIAS, see below)

  • stdcall symbols (CVF default) have @n appended. cdecl symbols (IVF default) don't.

  • both !DEC$ATTRIBUTES STDCALL and !DEC$ATTRIBUTES C imply lowercase symbols (unless overriden with ALIAS, see below) and call by value.

  • ALIAS: specifies the exact exported symbol name, unless combined with DECORATE

  • ALIAS, DECORATE in combination specifies that the case (upper/lower) is to be used from alias, but decoration (_ ... @n) appended.

  • You always need extern "C" when calling from C++.



So, any of the following (and more) combinations will work:
extern "C" __cdecl int printer()
!DEC$ATTRIBUTES DLLEXPORT, C:: PRINTER
--
extern "C" __cdecl int PRINTER()
!DEC$ATTRIBUTES DLLEXPORT, C, DECORATE, ALIAS: "PRINTER":: PRINTER
--
extern "C" __stdcall int Printer()
!DEC$ATTRIBUTES DLLEXPORT, STDCALL, DECORATE, ALIAS: "Printer":: PRINTER
--
extern "C" __stdcall int Printer()
!DEC$ATTRIBUTES DLLEXPORT, STDCALL, ALIAS: "_Printer@0":: PRINTER
--


HTH
Jugoslav
0 Kudos
patuco
Beginner
2,478 Views
Thanks a lot Jugoslav,
ive tryed your suggestions but no one works.
The fact is thatI need the fortran function to be exported in orther to be called. The problem im facing with is that the !DEC$ATTRIBUTES command does not export it, or at least is unabel to see by using the dependancy walker. Apart from that, the .net is still complaining about the linkage. I am not an expert using it, so i do not know if the problem could be related with the association of the .lib into the project.
The source code i'm working right now is as follows:
INTEGER FUNCTION PRINTER()
!MS$ATTRIBUTES DLLEXPORT,STDCALL,ALIAS:'_printer@n'::PRINTER
WRITE(6,'("-- FORTRAN funcion printer --")')
PRINTER=2
END
and the wrapper:

extern

"C" __stdcall int _printer();

JNIEXPORT jint JNICALL Java_ReadValue_getValue(JNIEnv * env, jobject jobj)

{

printf("-- A ver si funciona la referencia -- ");

int result = _printer();

printf(" -- valor de retorno ke leyo del archivo -- ",result);

return result;

}

Any idea?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
I didn't mean (@n) literally -- n is 4* the number of arguments, in this case zero (0). I suggest using DECORATE attribute, as it will take care about such details. Also, you don't need the leading underscore in C declaration -- the underscore is assumed by both Fortran and C compilers and now you're declaring "__printer@0" instead of "_printer@0"

I don't see how it's possible that it doesn't get exported. If nothing is exported, you wouldn't get the .lib file produced at all.

Jugoslav
0 Kudos
patuco
Beginner
2,478 Views

ok, thanks for thetip, but as i commented you, no function is being exported (take a look in the attachedment). Coulb it berelated with the !DEC and the !ms

INTEGER FUNCTION PRINTER()
!DEC$ATTRIBUTES DLLEXPORT, STDCALL, DECORATE, ALIAS: "Printer":: PRINTER
WRITE(6,'("-- FORTRAN funcion printer --")')
PRINTER=2
END

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
I have no clue. As I said, you wouldn't get a .lib if you don't have any exports.

I noticed that Dependency Walker shows that you're looking at fROtran.dll is it misspelled all the way or you're just loking at a wrong dll?

Jugoslav
0 Kudos
patuco
Beginner
2,478 Views

hi, i was performing some tests with the fortran code.

this is the version, the library is built from:

INTEGER FUNCTION Printer()
!MS$ATTRIBUTES DLLEXPORT, C, ALIAS: '_Printer':: Printer
WRITE(6,'("-- FORTRAN funcion printer --")')
PRINTER=2
END

the question is the wrapper call because it is keeping giving me back the linkage error??????

extern

"C" _stdcall int _Printer();

JNIEXPORT jint JNICALL Java_ReadValue_getValue(JNIEnv * env, jobject jobj)

{

printf("-- A ver si funciona la referencia -- ");

int result = _Printer();

printf(" -- valor de retorno ke leyo del archivo -- ",result);

return result;

}

the .lib is added on the project (to avoid this reply):

Project->Properties->Link->Input

aditional dependencies: fortran.lib

Any idea?

0 Kudos
patuco
Beginner
2,478 Views
yes it is a misspell :) i'm maintaining it because i is not so important in this stage. don't you agree?.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
Please go back and read my first post. Don't just randomly insert attributes and underscores. This time you have C versus STDCALL and the extra underscore in C version. Try this:

!MS$ATTRIBUTES DLLEXPORT, C, DECORATE, ALIAS: 'Printer':: Printer
extern "C" __cdecl int Printer();

Jugoslav
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
As for the misspell, I don't mind as long as it's consistent. However, you mentioned "fORtran.lib" but you appear to be using "fROtran.dll" -- which one is right?

Are you sure you have the f**tran.lib in the same directory as f**tran.dll, with the same timestamp?

Jugoslav
0 Kudos
patuco
Beginner
2,478 Views

ok let's reorganized everything.

the names i am using are frotan.dll and frotan.lib when i created the fortran library i didnt pay attention on it.

the reason im using the command !MS$ATTRIBUTES is, as i comment you before, because is the only way the dependancy is showing me the exported functions and subroutines.

With the option DECORATE i have the problem my compiler does not recognize it (i have to use the Microsoft Developer Studio).So the command i am using is:

!MS$ATTRIBUTES DLLEXPORT, C, ALIAS: "Printer":: PRINTER

After taking a look in the dependancy walker, i can read the function Printer (as we expected). All files, included .lib and .dll, are in ALL thedirectories created by the .net for the wrapper

now im trying to call this funct from the wrapper

extern

"C" _cdecl int Printer();

and in the function:

JNIEXPORT jint JNICALL Java_ReadValue_getValue(JNIEnv * env, jobject jobj)

{

printf("-- CALLING THE NATIVE -- ");

int result = Printer();

But im continuing becoming the same link error.

So i think the properties of the project are wrong configured. I know i have to add the .lib to teh project havent I?But maye im doing it wrong. Could you hep me, please?

Before that i made some test in linux and they work correctly but one of the restrictions is the program should be executed in windows andthe way of working withthe wrapper is a bit different. Instead of using two different libraries, only one is used. But as i told you, the requirements are different.

Message Edited by patuco on 02-07-2006 01:19 AM

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
You're using CVF6.1 or even older, right? That's >6 years old.

Since DECORATE is not available, the only decoration for C function is the underscore, so the attributes line should be:
!MS$ATTRIBUTES DLLEXPORT, C, ALIAS: "_Printer":: PRINTER

If you have the .lib, and the function is correctly exported, the only issue you have is mismatch in symbol naming. With the above line substituted, it should (finally) work.
0 Kudos
patuco
Beginner
2,478 Views

Thanks a lot Jugoslav,

finally it works. The problem was in the underscores in the wrapper.

Thanks a lot for helping me and thetimeyou've spend with this.

The code used was:

!MS$ATTRIBUTES DLLEXPORT, C, ALIAS: "_Printer":: PRINTER

extern

"C" _cdecl int Printer();

By the way, last comment, as i read in your first post about the parameters, if i have to call a function/subroutine with parameters the command in Fortran should look like this ?

!MS$ATTRIBUTES DLLEXPORT, C, ALIAS: _Printer@n:: PRINTER

and as you said yesterday, being the n the number of parameters.

Take care

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
cdecl (!DEC$ATTRIBUTES C) routines never have @n appended -- only stdcall ones. With the latter, n is generally equal to 4*number of arguments (but it can get complicated with string arguments or if larger structures are passed by value). You can take a look at e.g. DFWIN.f90 or Kernel32.f90 (I'm not sure when the former was split into smaller ones) from compiler's Include folder to see how it's done for Windows API routines (which are stdcall).
0 Kudos
patuco
Beginner
2,478 Views

Hi there,

I add another question that is related with the last one in the fact of using the dll, but not in the same way.

The point is that the fortran code is getting and changing some values of common variables of it, that the front- end need to show the results. In order to accomplish it, some functions, like getvalue or setvalue have been implemented in fortran, being the return value as follows:

INTEGER FUNCTION GETVALUE()
!MS$ATTRIBUTES DLLEXPORT,C,ALIAS:'_Getvalue'::GETVALUE
INCLUDE 'common.lvg'
GETVALUE=NUM_MAX
END FUNCTION

The wapper does the assignment as follows:

int result = Getvalue();

printf(" -- Fin C llama a fortran para get -- %i -- ",result);

I think im not considering some fact of fortranor communication between dlls. Am I?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
And the question is...?

There are several ways to pass the data, the simplest being argument passing, like:
SUBROUTINE GetValues(iVal1, rVal2, aVal3)
integer, intent(out):: iVal1
real, intent(out):: rVal2
real, intent(out):: aVal3(*)
!DEC$ATTRIBUTES C, REFERENCE, ALIAS: "_GetValues":: GetValues
INCLUDE "common.lvg"
iVal1 = NUM_MAX
rVal2 = Foo
DO i = 1,nn
aVal3(i) = Bar(i)
END DO
END SUBROUTINE

extern "C" void GetValues(int*, float*, float*)
...
float rResult3[...]
GetValues(&iResult1, &rResult2, rResult3)
0 Kudos
patuco
Beginner
2,478 Views

it is just a question about declaring the extern functions in the wrapper:

anyone knows whichare the differences between:

extern "c" int Printer();

extern "c" __declspec(dllexport) int Printer();

?????

ive read about the parameter __declspec but i do not understand it as i would like.

Thanks,

Take care

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
__declspec(dllexport/dllimport) is the same as !DEC$ATTRIBUTES DLLEXPORT/DLLIMPORT - for exporting and importing symbols in dll.

__declspec(dllimport) can be omitted; a function can be imported without that attribute.
0 Kudos
patuco
Beginner
2,478 Views

Hi,

i have a problem with the conversion of a char* to string i do not get where the mistake is in the code of the native function:

JNIEXPORT jstring JNICALL Java_Main_get_1name(JNIEnv *env, jobject jobj, jint param)

{

char buf = (char*)malloc(max_char);

//Call the function in fortran

strcpy(buf, Getname(param +1));

return (*env)->NewStringUTF(env, buf);

}

anyone knows why?

Message Edited by patuco on 02-07-2006 01:20 AM

0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,478 Views
I don't speak Spanish, but it seems that the C++ compiler doesn't know what "JNIEnv" is -- maybe it's misspelled (wrong case?), or you have to #include appropriate header file.
0 Kudos
patuco
Beginner
2,374 Views

it was a problem related with pointers, i mean ,instead of using (*env), i tested with env-> and it worked

Message Edited by patuco on 02-07-2006 01:21 AM

0 Kudos
Reply