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

Linker error while calling fortran subroutine from VC++

sumaj
Beginner
1,302 Views
Linker error while calling fortran subroutine from VC++ when executing the following program

The Fortran code is as follows

SUBROUTINE MULTIDRAIN ( IERR )
IMPLICIT NONE

INCLUDE 'in2.inc'
INCLUDE 'calc.inc'
INCLUDE 'coeff.inc'
INCLUDE 'fore.inc'
INCLUDE 'in1.inc'
INCLUDE 'inphor.inc'
INCLUDE 'print.inc'
INCLUDE 'prop.inc'
INCLUDE 'respm.inc'
INCLUDE 'unitconv.inc'

INTEGER COUNT
INTEGER I
INTEGER ICUM
INTEGER, INTENT (OUT) :: IERR

...
RETURN
END

I am calling this subroutine MULTIDRAIN in VC++ 8.0 as follows

//Declaration in header file
extern "C" { int _stdcall MULTIDRAIN(); }

//calling in .cpp file
UINT ThreadCtrlFunc(LPVOID pParam)
{

MULTIDRAIN();

ThreadExitCode = TRUE;
return 1;
}

I couldn't find which goes wrong. I repeatedly getting this Linker error. Please do help. Thanks in advance.

Error 60 error LNK2019: unresolved external symbol _MULTIDRAIN@0 referenced in function "unsigned int __cdecl ThreadCtrlFunc(void *)" (?ThreadCtrlFunc@@YAIPAX@Z) MainFrm.obj

Error 61 fatal error LNK1120: 1 unresolved externals c:\Program Files\MultiLateral 02 04\MultiLateral\Multilateral\Release\MultiLateral.exe 1
0 Kudos
5 Replies
TimP
Honored Contributor III
1,302 Views
Did you consult the documentation on C interoperability of your compiler? I'm guessing that you followed (partly) a recommendation for a Fortran compiler of 10 years ago or so, but your Fortran compiler may not be that old. Fortran compilers of the last year or so support iso_c_interop.
0 Kudos
anthonyrichards
New Contributor III
1,302 Views
Quoting - tim18
Did you consult the documentation on C interoperability of your compiler? I'm guessing that you followed (partly) a recommendation for a Fortran compiler of 10 years ago or so, but your Fortran compiler may not be that old. Fortran compilers of the last year or so support iso_c_interop.

For a start, in your C++ code, you declare MULTIDRAIN as if it were an Integer FUNCTION with no arguments, whereas you reference it as Void function with no arguments which assumes a SUBROUTINE on the Fortran side. On top ofthis your Fortran defines a SUBROUTINE taking one argument. Things are never going to match up in this situation. I think you should either change the C++ to match the Fortran Subroutine declaration, adding an argumentor declare the Fortran as a FUNCTION with no argument to match the C++.(Check the following C++ for correctness - I am not a regular C++ programmer)

extern "C" {_stdcall void MULTIDRAIN(int ERR); }

//calling in .cpp file
UINT ThreadCtrlFunc(LPVOID pParam)
{
int err;
MULTIDRAIN(err);

There remains the question of whether the Fortran code is compiled and linked into a .LIB or a .DLL. Ifthe latter it will need a DLLEXPORT directive on the Fortran side and on the C++ side you willto add __declspec(dllimport) to the extern declaration, as well as specifying the Library's location. Otherwise you should also add compiler directives to ensure the correct calling convention is used on the Fortran sideand that the argument is to be called by value to match the C++ 'int ERR'. If you use 'int* ERR' in the C++, then the argument is to be called by reference.
0 Kudos
Lorri_M_Intel
Employee
1,302 Views
Are you using CVF or Intel Fortran?

If you are using CVF, there's one more small change you need to make:

extern "C" {_stdcall void MULTIDRAIN(int *ERR); }

You MUST pass the integer by reference. Otherwise, this should work for you because the calling standard for CVF was very close to C's _stdcall

However. If you are using Intel Fortran, then you should change your declaration to this:

extern "C" {void MULTIDRAIN(int *ERR); }

Again, you MUST pass the integer by reference, but you don't need to put in the _stdcall directive

Both CVF and Intel Fortran have extensive documentation onmixed-language programming, especially with C.

- Lorri


0 Kudos
sumaj
Beginner
1,302 Views
Quoting - lorri_menard
Are you using CVF or Intel Fortran?

If you are using CVF, there's one more small change you need to make:

extern "C" {_stdcall void MULTIDRAIN(int *ERR); }

You MUST pass the integer by reference. Otherwise, this should work for you because the calling standard for CVF was very close to C's _stdcall

However. If you are using Intel Fortran, then you should change your declaration to this:

extern "C" {void MULTIDRAIN(int *ERR); }

Again, you MUST pass the integer by reference, but you don't need to put in the _stdcall directive

Both CVF and Intel Fortran have extensive documentation onmixed-language programming, especially with C.

- Lorri



Hi Lorri,

Thanks for the reply. Iam using Intel Fortran. I have changed the declaration to
extern "C" { int _cdecl MULTIDRAIN(); }
and now the problem has gone.
Thank you.
0 Kudos
sumaj
Beginner
1,302 Views
Quoting - anthonyrichards

For a start, in your C++ code, you declare MULTIDRAIN as if it were an Integer FUNCTION with no arguments, whereas you reference it as Void function with no arguments which assumes a SUBROUTINE on the Fortran side. On top ofthis your Fortran defines a SUBROUTINE taking one argument. Things are never going to match up in this situation. I think you should either change the C++ to match the Fortran Subroutine declaration, adding an argumentor declare the Fortran as a FUNCTION with no argument to match the C++.(Check the following C++ for correctness - I am not a regular C++ programmer)

extern "C" {_stdcall void MULTIDRAIN(int ERR); }

//calling in .cpp file
UINT ThreadCtrlFunc(LPVOID pParam)
{
int err;
MULTIDRAIN(err);

There remains the question of whether the Fortran code is compiled and linked into a .LIB or a .DLL. Ifthe latter it will need a DLLEXPORT directive on the Fortran side and on the C++ side you willto add __declspec(dllimport) to the extern declaration, as well as specifying the Library's location. Otherwise you should also add compiler directives to ensure the correct calling convention is used on the Fortran sideand that the argument is to be called by value to match the C++ 'int ERR'. If you use 'int* ERR' in the C++, then the argument is to be called by reference.

Hi,

Thanks for the reply. I have changed the declaration so that it returns int, as follows
extern "C" { int _cdecl MULTIDRAIN(); }
and now the problem has gone. Also, my Fortran code is compiled and linked as .lib file.
Thank you.
0 Kudos
Reply