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

Problem call C++ subroutine from Fortran

Thomann__Gary
Novice
852 Views

I am trying to call a C++ subroutine from fortran.  This should not be hard and there have been posts about it before.  I think I have read all them and also read the Intel literature.  I am using Visual Studio 2019 Parallel Studio 2020 with just Fortran.  I am using the VS IDE, not a command line.  I have a solution with two projects in it, one fortran and one C++.  The fortran project has two files, testF.f and adModule.f.  They are shown below, testF.f first

      program tryadd     

     USE first_try_mod

      implicit none

      real X1

      real Y1

      real Z1

C      external firstadd !$pragma C( firstadd )

      x1 = 1.0

      y1 = 4.0

      z1 = 5.0

      call FIRSTADD (X1,Y1,Z1 )

C      write( *,"z1 = ")

      end program tryadd

Then the module file

      MODULE first_try_Mod

         interface

C         subroutine TESTADD( X1,Y1,Z1) bind(C,name='TESTADD')

         subroutine TESTADD( X1,Y1,Z1)

         !DEC$ ATTRIBUTES C, REFERENCE, ALIAS : '_TESTADD' :: TESTADD

         !DEC$ ATTRIBUTES REFERENCE :: X1,Y1,Z1

C         subroutine testadd() bind(C,name='testadd')

C         real, value :: X1

C         real, value :: Y1

C         real, value :: Z1

         real :: X1

         real :: Y1

         real :: Z1

         end subroutine TESTADD

         end interface

C

      END MODULE first_try_Mod

You can see some things commented out; I have tried about a hundred different things and commented what I am not presently trying.

The C++ project has two files, testC.h and testC.cpp as shown below, 1 line header first

void TESTADD (float *X1, float *Y1, float *Z1);

testC.cpp next

#include <windows.h>

#include <iostream>

using namespace std;

extern "C"

{

void TESTADD (float *X1, float *Y1, float *Z1);

void TESTADD (float *X1, float *Y1, float *Z1

// __declspec(dllexport) void testadd (float *x1, float *y1, float *z1);

// __declspec(dllexport) void testadd (float *x1, float *y1, float *z1

)

{

      *Z1 = *Y1 + *X1;

}

}

 

For each one of the hundred things I have tried when I build I get the error

fatal error LNK1561: entry point must be defined

Can anybody tell me a solution to this?

0 Kudos
16 Replies
gib
New Contributor II
852 Views

Use Cinteroperability to declare the subroutine parameters, e.g.

use_iso_c_binding

real(c_float) :: X1

Stick with the bind(C,name=...) method, but make the name agree with respect to case (C is case-sensitive).  If you really want to call the C++ function TESTADD, then you'll need (the Fortran name is irrelevant):

subroutine testadd( X1,Y1,Z1) bind(C,name='TESTADD')

use_iso_c_binding

real(c_float) :: X1, Y1, Z1

You are passing the arguments by reference, not by value, so don't use "value".  Why not use free format, .f90?

On the C side, you want:

extern "C"

{

void TESTADD (float *X1, float *Y1, float *Z1);

{

      *Z1 = *Y1 + *X1;

}

}

 

0 Kudos
Thomann__Gary
Novice
852 Views

ok thanks, I will try it

0 Kudos
gib
New Contributor II
852 Views

Sorry, I just noticed that your main program does this:

 call FIRSTADD (X1,Y1,Z1 )

but your subroutine is called TESTADD.  You can change the subroutine name to FIRSTADD without changing anything else - the "name" clause will take care of the C linkage.

0 Kudos
mecej4
Honored Contributor III
852 Views

G.Thomann wrote:

For each one of the hundred things I have tried when I build I get the error

    fatal error LNK1561: entry point must be defined

Can anybody tell me a solution to this?

That's probably caused by attempting to compile and link the C source by itself into an EXE. What is the nature of the C++ project? Library? EXE?

A related question: have you configured the dependence of the Fortran project on the C++ library?

0 Kudos
Steve_Lionel
Honored Contributor III
853 Views

I think you also need:

extern "C"

before the declarations of TESTADD in the C++ code, otherwise you're going to get C++ name mangling.

0 Kudos
gib
New Contributor II
853 Views

@Steve  Does he need to move 'extern "C"' up to the top of the program?

Unless what he's showing is not his actual code, the problem is that his main program is calling FIRSTADD, not TESTADD.

0 Kudos
Steve_Lionel
Honored Contributor III
853 Views

That's certainly one of the issues. But I admit I missed that extern "C" was there bracketing the declarations, so that part should be ok. 

In the Fortran code, I see that the use of BIND(C) has been commented out and the non-standard directives used instead, which is not something I would recommend. With BIND(C) as shown, the interface looks correct to me, and it would be inappropriate to use VALUE, since the prototype in C++ accepts the arguments by reference.

0 Kudos
Thomann__Gary
Novice
853 Views

Thank you for all the comments.  Call the wrong subroutine name from the fortran code was dumb.  Unfortunately fixing that did not change anything.  Nor did any of the suggested fixes, I still always get the 1561 error.  For the C++ project I have tried building both a lib and a dll.  On possible thing is the question from mecej4:

Have you configured the dependence of the Fortran project on the C++ library?

How do I do that?

0 Kudos
Steve_Lionel
Honored Contributor III
853 Views

Attach a ZIP of your Visual Studio solution with projects and let us see what you actually did.

0 Kudos
FortranFan
Honored Contributor II
853 Views

Thomann, Gary wrote:

Thank you for all the comments.  Call the wrong subroutine name from the fortran code was dumb.  Unfortunately fixing that did not change anything.  Nor did any of the suggested fixes, I still always get the 1561 error.  For the C++ project I have tried building both a lib and a dll.  On possible thing is the question from mecej4:

Have you configured the dependence of the Fortran project on the C++ library?

How do I do that?

Here, you can try the Visual Studio Solution and Microsoft C++ DLL project along with Intel Fortran Console Application project in the attached zip file.

You'll see the code is as follows:

#include <iostream>
using namespace std;

extern "C" {
  void TestAdd(float *X1, float *Y1, float *Z1);
}
 
void TestAdd(float *X1, float *Y1, float *Z1)
{
   *Z1 = *Y1 + *X1;
   return;
}
module first_try_Mod

   use, intrinsic :: iso_c_binding, only : c_float

   implicit none

   interface

      subroutine TestAdd( X1, Y1, Z1) bind(C, name="TestAdd")
      ! void TestAdd(float *X1, float *Y1, float *Z1);

         import :: c_float

         implicit none

         ! Argument list
         real(c_float), intent(inout) :: X1
         real(c_float), intent(inout) :: Y1
         real(c_float), intent(inout) :: Z1

      end subroutine

   end interface

end module first_try_Mod
program TryAdd

   use, intrinsic :: iso_c_binding, only : c_float
   use first_try_mod, only : TestAdd

   implicit none

   real(c_float) :: X1, Y1, Z1

   x1 = 1.0_c_float
   y1 = 4.0_c_float
   z1 = 5.0_c_float

   call TestAdd(X1, Y1, Z1)

   print *, "z1 = ", z1

end program TryAdd

You can unzip to a folder, open the solution, build it (F6 key), and hit Ctrl-F5 hot key to execute to get the following:

 z1 =  5.000000
Press any key to continue . . .

 

0 Kudos
Thomann__Gary
Novice
853 Views

Thanks Steve, here is a zip file with the whole tree

0 Kudos
Steve_Lionel
Honored Contributor III
853 Views

This is a mess.

Your C++ project is building a DLL, but it exports no symbols. You have told VS that your C++ project is dependent on the Fortran project, when it should be the other way around,. The Fortran project has no "subsystem" defined - I am not sure how you managed that, but I note that the project type is "Application" and not "Console Application". I also note that the C++ project is building into the Fortran project's output folder, which is usually a bad move, as VS may delete one project's outputs before building the other project.

Start over. Create a blank Visual Studio solution. Add a Fortran Console Application and a C++ Static Library project. Add the proper sources to the respective projects. Right click the Fortran project, select Build Dependencies > Project Dependencies. Check the box for the C++ project. (This will work when the C++ project is a static library, but not when it's a DLL.

I think this should take care of it.

0 Kudos
Thomann__Gary
Novice
853 Views

Thank you very much Steve.  I can believe it is a mess; it is hard to learn something when you crash full speed into it.  I believe it would be helpful to have more tutorial info and some examples including solution files for calling C++ from Fortran.  I have certainly had a hard time with it, although that seems to happen with everything I do.

I am a consultant (and used to work for) a company that makes a large simulation program, with Fortran used for the models.  I am interested to see if C++ could help with parts of the models.

Again, thank you for looking at this!  I will try again.

0 Kudos
Steve_Lionel
Honored Contributor III
853 Views

The Intel Parallel Studio XE for Windows Samples Bundle (filter by Windows) contains examples of Fortran calling into C (with some text about differences between C and C++), as well as C calling Fortran. You may find these worth a study.

Normally, the way you get a Fortran project to link to the library from another project is to set the Project Dependencies such that the executable project is dependent on the library project. That works fine for Fortran-Fortran (and in that case also makes any compiled modules in the library project visible to the executable), and works for Fortran-C where the C/C++ project is a static library, but Microsoft broke this when the C/C++ project is a DLL - in that case you have to manually add the library to the parent project (can do it as if it were a source file, or use the Linker property pages.)

You should also study the Fortran standard's C interoperability features, which got expanded in Fortran 2018 and are fully supported by the current Intel Fortran.

0 Kudos
FortranFan
Honored Contributor II
853 Views

Thomann, Gary wrote:

.. I can believe it is a mess; it is hard to learn something when you crash full speed into it.  I believe it would be helpful to have more tutorial info and some examples including solution files for calling C++ from Fortran.  I have certainly had a hard time with it, although that seems to happen with everything I do.

I am a consultant (and used to work for) a company that makes a large simulation program, with Fortran used for the models.  I am interested to see if C++ could help with parts of the models.

Again, thank you for looking at this!  I will try again.

Will it be possible for you to take a look at Quote #11 above and try it out and provide your feedback here please?

You have a fully worked out example in Quote #11 of the very specific scenario you have presented in this thread including your own code structure and a C++ DLL and a Fortran main project.

0 Kudos
JohnNichols
Valued Contributor III
853 Views

Thomann, Gary wrote:

Thank you very much Steve.  I can believe it is a mess; it is hard to learn something when you crash full speed into it.  I believe it would be helpful to have more tutorial info and some examples including solution files for calling C++ from Fortran.  I have certainly had a hard time with it, although that seems to happen with everything I do.

I am a consultant (and used to work for) a company that makes a large simulation program, with Fortran used for the models.  I am interested to see if C++ could help with parts of the models.

Again, thank you for looking at this!  I will try again.

Dear Gary:

This is not the place to complain about the state of the world or the fact that HAL has taken a holiday or that Heinlein was correct in his statement about non-mathematicians - if this eludes you then I am sorry.  

The type of problem that you are talking about interests a very limited subset of the "known" world of computer programmers and most these programmer's days are limited to PYTHON or JAVA or some such thing.  If you join this smaller limited set of programmers, here, then you are dealing with new programs and versions that are often poorly documented or not documented.  You are now an Eagle Scout and you do not need to ask if I flip the Registry Entry to show the version of windows on my desktop will I open a flaw in the firewall.  (I was asked that this week) 

If you want an extreme example of this problem download the original AUTOLISP manual and try and write a program.  Lisp's learning curve is straight up and very very hard. At that stage there was no Amazon and it took 12 weeks to get the Winston and Horn book shipped from MIT. I

The Internet gives you all the data you need - but there is no librarian -- instead there are volunteers like this forum to answer your questions to the best of their ability.  I understand this group -- I am not really a part of it -- I just hope they can solve some of my problems.  And i enjoy the banter

So it is best to be polite and stick to specific questions.  If you understand 42 as the answer then you understand these people. 

Good hunting 

John

 

0 Kudos
Reply