Calling Fortran from C++-CLI

612 views Asked by At

I have a fortran subroutine, FortranShake, and a C++ main function, HandShakingTest.cpp. I'm trying to call a fortran subroutine from CLR C++.

I'm getting two batches of errors. Let's call them ERROR(1) and ERROR(2). I'd really appreciate if you could help me understand why these errors are happening.

When I try to compile with the following: cl /clr HandShakingTest.cpp

I get the following ERROR(1):

HandShakingTest.obj : error LNK2028: unresolved token (0A00030A) "extern "C" void __c
ecl FortranShake(int &)" (?FortranShake@@$$J0YAXAAH@Z) referenced in function "int __
lrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@Sys
em@@@Z)
HandShakingTest.obj : error LNK2019: unresolved external symbol "extern "C" void __cd
cl FortranShake(int &)" (?FortranShake@@$$J0YAXAAH@Z) referenced in function "int __c
rcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@Syst
m@@@Z)
HandShakingTest.exe : fatal error LNK1120: 2 unresolved externals

I then used the following commands to compile instead:

ifort /c FortranShake.f //Which compiles fine
cl /c /clr HandShakingTest.cpp //compiles fine
cl /o test HandShakingTest.obj FortranShake.obj //ERROR(2) occurs

ERROR(2) consists of:

MSVCRT.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(cla
ss type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMT.lib(typin
fo.obj)
MSVCRT.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_i
nfo::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defin
ed in LIBCMT.lib(typinfo.obj)
MSVCRT.lib(merr.obj) : error LNK2005: __matherr already defined in LIBCMT.lib(_matherr
_.obj)
LINK : warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; use /NOD
EFAULTLIB:library
HandShakingTest.obj : error LNK2028: unresolved token (0A00030A) "extern "C" void __cd
ecl FortranShake(int &)" (?FortranShake@@$$J0YAXAAH@Z) referenced in function "int __c
lrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@Syst
em@@@Z)
HandShakingTest.obj : error LNK2019: unresolved external symbol "extern "C" void __cde
cl FortranShake(int &)" (?FortranShake@@$$J0YAXAAH@Z) referenced in function "int __cl
rcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@Syste
m@@@Z)
libifcoremt.lib(for_main.obj) : error LNK2019: unresolved external symbol _MAIN__ refe
renced in function _main
test.exe : fatal error LNK1120: 3 unresolved externals

Here's the HandShakingTest.cpp:

#include "stdio.h"
#include <stdlib.h>
#include <Windows.h>
#using <System.DLL>
#using <System.Windows.Forms.DLL>

using namespace std;
using namespace System;
using namespace System::IO;
using namespace System::Diagnostics;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;

extern "C" {void FortranShake(int&);}

int main(array<System::String ^> ^args)
{
    Process^ testHand = gcnew Process();
    testHand->StartInfo->UseShellExecute = false;
    testHand->StartInfo->RedirectStandardInput = true;
    testHand->StartInfo->RedirectStandardOutput = true;
    testHand->StartInfo->ErrorDialog = true;

    int numDebug = 0;
    String^ returnedDebug = "Nothing";

    FortranShake(numDebug);

    StreamReader^ FromHandProcess = testHand->StandardOutput;
    StreamWriter^ ToHandProcess = testHand->StandardInput;

    String^ Line;

    Line = FromHandProcess ->ReadLine();

    if (Line->Equals("Enter Hand") )
    {
        Console::WriteLine(L"Hand Started!");
    }
    ToHandProcess ->WriteLine(numDebug.ToString());
    returnedDebug = FromHandProcess ->ReadLine();

    MessageBox::Show(returnedDebug);

    return 0;
}

Here is the Fortran Subroutine:

  SUBROUTINE FortranShake(GP_DEBUG)
  IMPLICIT DOUBLE PRECISION (A-H,O-Z)
  INN = 5

  WRITE(06,'(a)') 'Enter Hand'

  READ(INN,*) GP_DEBUG
  GP_DEBUG = GP_DEBUG + 55
  WRITE(06,*) GP_DEBUG

  RETURN
  END
1

There are 1 answers

0
IanH On

Your first error is actually a linker error - without the /c command line switch you are compiling and linking in one step. No Fortran code or object code has been provided.

Your second error is because:

  • You have specified (through omission) mismatching runtime libraries for the C++ and the Fortran. You need to decide whether you want to use static linking (the default for the current (as of today, but not necessarily as of next month...) release of Intel Fortran on windows) or dynamic linking (the default for the MS C++ compiler). Perhaps add /MD to the ifort command line, which specifies dynamic linking.

  • Without compiler options or directives to the contrary, the equivalent identifier for the Fortran procedure in C code as generated by that Fortran compiler is an upper case variant of the Fortran procedure's name - i.e. in the C++ code call the procedure FORTRANSHAKE. If you can write your Fortran code to the F2003 standard, you should use the C interoperability features of that language (BIND(C,...)) to control the C binding name of the Fortran procedure and ensure calling conventions, etc align.

  • The dummy argument of the Fortran subroutine has the DOUBLE PRECISION type specifier, which is equivalent to double in the C++ for this combination of compilers, not int. Again, F2003 introduces features that can make this alignment of argument types more robust.