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

Calling a C++ dll from a main program in Fortran

iberpar
Beginner
1,428 Views

I'm trying to compile a simple code in Fortran that calls a C++ function which gives the value of two reals. To do so, I have followed the steps:

1. Open an empty console project in C++, add a .h and .cpp files.

(file.h)

#pragma once
#if __cplusplus
extern "C"
{
_declspec(dllexport) void change_(float* a, float* b);
}
#endif

(.cpp)

#include "file.h"
#include <iostream>
#include <stdio.h>

extern "C" void change_(float* a, float* b) {
*a = 5.0;
*b = 6.0;
}

2. Change the project to a .dll type in order to compile it, .lib and .dll were generated.

3. Open a new empty console project in Fortran and add the main code.

(.f90)

program fprog
   real a,b
   a=1.0
   b=2.0
   print*,'Fortran variables:'
   print*,'a=',a
   print*,'b=',b

   call change(a,b)
   print*,'C++ variables:'
   print*,'a=',a
   print*,'b=',b

   stop
end

3. Add the .lib into the source foulder, select the dependency between both projects and compile it, but I get linkage errors.

error LNK2019: unresolved exernal symbol CHANGE which was referred in the funci¢n MAIN__

fatal error LNK1120: 1 unresolved externals

 

0 Kudos
1 Solution
MWind2
New Contributor III
1,405 Views

I am not so good at fortran interfaces, but one problem I see is in the dll:

// cxdll.h
#ifdef CXDLL_EXPORTS
#define CXDLL_API __declspec(dllexport)
#else
#define CXDLL_API __declspec(dllimport)
#endif

// This class is exported from the dll

extern "C" CXDLL_API void change(float *, float *);
//cxdll.cpp
// cxdll.cpp : Defines the exported functions for the DLL.
//

#include "pch.h"
#include "framework.h"
#include "cxdll.h"


#ifdef __cplusplus 
extern "C" {
#endif
    // This is an example of an exported function.
    CXDLL_API void change(float* a, float* b) {
        *a = 5.0;
        *b = 6.0;
    }


#ifdef __cplusplus
}
#endif

 

and in fortran:

program fcxdll

    implicit none
interface 
     subroutine change (f1, f2) BIND(C, name='change') 
        use, intrinsic :: ISO_C_BINDING  
        implicit none 
        type (real) :: f1 
        type (real) :: f2
     end subroutine change
end interface 
    ! Variables
     real a,b
     a=1.0
     b=2.0
    ! Body of fcxdll
    print*,'Fortran variables:'
    print*,'a=',a
    print*,'b=',b
    call change(a,b)
    print*,'C++ variables:'
    print*,'a=',a
    print*,'b=',b
    stop
    
    end program fcxdll

 I was using VS2019 and had to put some thngs in fortran project for pre link event:

Additional Dependencies .\$(PlatformName)\$(ConfigurationName)\cxdll.lib
and
Build Events->Pre-Link Event copy ..\$(PlatformName)\$(ConfigurationName)\cxdll.* .\$(PlatformName)\$(ConfigurationName)

View solution in original post

0 Kudos
3 Replies
mecej4
Honored Contributor III
1,410 Views

The name decoration for Fortran external names is compiler-dependent. You seem to be using the conventions of GFortran in your source code, but you are using Ifort to compile.

Change the name in the C file from change_ to CHANGE .

0 Kudos
MWind2
New Contributor III
1,406 Views

I am not so good at fortran interfaces, but one problem I see is in the dll:

// cxdll.h
#ifdef CXDLL_EXPORTS
#define CXDLL_API __declspec(dllexport)
#else
#define CXDLL_API __declspec(dllimport)
#endif

// This class is exported from the dll

extern "C" CXDLL_API void change(float *, float *);
//cxdll.cpp
// cxdll.cpp : Defines the exported functions for the DLL.
//

#include "pch.h"
#include "framework.h"
#include "cxdll.h"


#ifdef __cplusplus 
extern "C" {
#endif
    // This is an example of an exported function.
    CXDLL_API void change(float* a, float* b) {
        *a = 5.0;
        *b = 6.0;
    }


#ifdef __cplusplus
}
#endif

 

and in fortran:

program fcxdll

    implicit none
interface 
     subroutine change (f1, f2) BIND(C, name='change') 
        use, intrinsic :: ISO_C_BINDING  
        implicit none 
        type (real) :: f1 
        type (real) :: f2
     end subroutine change
end interface 
    ! Variables
     real a,b
     a=1.0
     b=2.0
    ! Body of fcxdll
    print*,'Fortran variables:'
    print*,'a=',a
    print*,'b=',b
    call change(a,b)
    print*,'C++ variables:'
    print*,'a=',a
    print*,'b=',b
    stop
    
    end program fcxdll

 I was using VS2019 and had to put some thngs in fortran project for pre link event:

Additional Dependencies .\$(PlatformName)\$(ConfigurationName)\cxdll.lib
and
Build Events->Pre-Link Event copy ..\$(PlatformName)\$(ConfigurationName)\cxdll.* .\$(PlatformName)\$(ConfigurationName)

0 Kudos
iberpar
Beginner
1,390 Views

Thank you for your answers, it worked by changing the function name from change_ to change and adding the Bind C interface into the main Fortran code. 

In addition, I had to move the dll to the executabe foulder to make it accesible and set the Fortran project as startup one, if not I was getting a message window saying that the .dll is not a Win32 valid application.

0 Kudos
Reply