Trouble linking an Intel Visual Fortran Program to a C++ function

436 Views Asked by At

I am trying to link a very simple C++ function to a very simple Intel Visual Fortran program.

Fortran program looks like this In a file called VFTestBed.f90):

 program VFTestBed

 integer pInteger

 pInteger = 11

 call SimpleTest1( pInteger )

 end program

Fortran interface block looks like this (in a file called interfaces.f90):

MODULE INTERFACES

interface

subroutine SimpleTest1( pInteger) 

!DEC$ATTRIBUTES DECORATE, ALIAS: "SimpleTest1"

integer pInteger

end subroutine SimpleTest1

end interface

END MODULE

C++ function looks like this (in a file called cppresponder.cpp):

#include <windows.h>
#include <sstream>

void SimpleTest1(int pInteger);

void SimpleTest1(  int pInteger)

{

      std::string pString = "";
      std::string pTitle = "";

      std::string pName = "SimpleTest1\0";

   pString = "Integer was entered.";
   pTitle = "In Routine: " + pName;

   MessageBoxA(NULL, pString.c_str(), pTitle.c_str(), MB_OK |    MB_ICONINFORMATION);

}        

I have researched this problem on Google and tried many dozens of permutations and combinations of various settings, declares, decorations, etc. all to no avail. Indeed, many of the posts were long and quite convoluted and often didn't seem to come to a successful conclusion.

Among other things I have tried:

  1. making the C++ code a .LIB
  2. making the C++ code a .DLL
  3. using various forms of !DEC$ATTRIBUTES DECORATE, ALIAS: "SimpleTest1"
  4. using BIND(C, ...)
  5. using plain aliases
  6. using decorated aliases
  7. used DUMPBIN to see the symbols in the .DLL
  8. using the preamble extern "C"
  9. compiling as C code (disables all the C++ constructs)

and a whole lot of other things. I've tried all the things that supposedly worked for other posters with absolutely no luck.

No matter what I do, I get a linker error message LNK2019 about an unresolved external symbol _SIMPLETEST1 referenced in function _MAIN__

As per the Intel site, I have added in CppResponder.DLL just like adding in a source file.

If it matters, I am using Visual Studio Enterprise 2017 and Intel Parallel Studio XE 2016 Update 4 composer Edition for Windows, all running on a 64 bit Windows 8.1 machine.

Assuming that Intel Fortran can indeed call a C++ function (I'm assuming it can) then I must be missing a switch or setting somewhere. I've set up both the Fortran and C++ projects with the defaults that Visual Studio provided. Both projects were setup as Release | x86.

Surely, this really can't be that hard of a thing to do. I've spent about 12 hours on this and have nothing to show for it. I have decades of experience with Fortran but am fairly new to C++.

Has anyone done this before and would be willing to walk me through how you did it?

Thanks in advance,

Bob Kiser

2

There are 2 best solutions below

2
On

cppresponder.cpp

#include <iostream>

extern "C" void simpletest_(int* i){
    std::cout << "cpp " << *i << '\n';
}

VFTestBed.cpp

 program VFTestBed

 integer pInteger

 pInteger = 11

 call simpletest(pInteger)

 end program

compilation:

g++ -c cppresponder.cpp; gfortran -c VFTestBed.f90; gfortran -o test.o cppresponder.o VFTestBed.o -l stdc++

exec:

./test.o

output

>cpp 11

You may also need these compiler switches

 g++ -c -Wpadded -Wpacked -malign-double -mpreferred-stack-boundary=8 cppresponder.cpp; gfortran -c -malign-double VFTestBed.f90
0
On

My thanks to the responders above. I tried their suggestions but didn't get anywhere.

But after a lot more grief, I did find something that worked.

Fortran:

program VFTestBed

use INTERFACES

integer pInteger

pInteger = 11

call SimpleTest1( pInteger )

end program



MODULE INTERFACES

interface

subroutine SimpleTest1( pInteger)

!DEC$ ATTRIBUTES  ALIAS:'?SimpleTest1@@YGXPAH@Z' :: SimpleTest1

integer pInteger

end subroutine SimpleTest1

end interface

END MODULE

and on the C++ side:

#define WIN32_DEFAULT_LIBS
#include <windows.h>
#include <iostream>
#include <sstream>


__declspec(dllexport) void SimpleTest1(int* pInteger);

void SimpleTest1(int* pInteger)

{

    std::string pString = "";
    std::string pTitle = "";

    std::string pName = "SimpleTest1\0";

    pString = "Integer entered = " + std::to_string(*pInteger);
    pTitle = "In Routine: " + pName;

    MessageBoxA(NULL, pString.c_str(), pTitle.c_str(), MB_OK |    MB_ICONINFORMATION);


}

The notable changes:

  1. added __declspec(dllexport)
  2. changed int to int*
  3. added the #define WIN32_DEFAULT_LIBS
  4. changed from a .DLL to a .LIB
  5. used DUMPBIN to figure out the C++ name decoration
  6. in the main program added USE INTERFACES
  7. in the interface added: !DEC$ ATTRIBUTES ALIAS:'?SimpleTest1@@YGXPAH@Z' :: SimpleTest1

So, all of that to get less than 30 lines of code to compile, link and run! Sheesh!

15+ hours of my life I'll never get back.

Anyway, it is solved and I hope that I have saved some future reader from all the grief I went through. I hope that someone somewhere finds this useful.