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

Interoperability: Fortran to C++

Maia__Nycholas
Beginner
3,752 Views

I would like to develop a Fortran Static Library that include a custom subroutine that takes a long time to complete.
This static library will be linked in my C++ application statically too.

My goal is monitoring that current status of this subroutine in my C++ application in real-time.
So, for each step of a "fortran loop", I would like to send the loop index to my C++ application.

I'm new in Fortran world, so I was thinking that this task could be something like this:

My C++ header:

extern "C" void fortran_status(int* value);

My Fortran-90 file:

module my_interfaces
    use iso_c_binding
        interface
            subroutine fortran_status(progress_value) bind(C, name = 'fortran_status')
                use, intrinsic :: iso_c_binding
                integer(c_int), intent(out) :: progress_value
            end subroutine fortran_status
        end interface
end module my_interfaces

    
! My long calc subroutine
subroutine my_long_calc(progress_value) BIND(C, name = 'my_long_calc')
    use, intrinsic :: ISO_C_BINDING
    use my_interfaces
    implicit none

    EXTERNAL fortran_status
    
    integer (C_INT), INTENT(INOUT) :: progress_value
    integer (C_INT) :: count
    
    
    do count = 0, 5    
        progress_value = progress_value + 1
        
        ! Send 'progress_value' to a C++ function:
        call fortran_status(progress_value)
        
        ! Wait 1 second:
        call sleep(1)
    end do
    
end subroutine my_long_calc


This code gives me a compile-time error:
 

error #6406: Conflicting attributes or multiple declaration of name.   [FORTRAN_STATUS]       C:\Users\lamar\Desktop\Lib1_interface\Lib1.f90    18 

   

I'm using Microsoft Visual Studio 2019 with Intel Visual Fortran (Windows 10 x64).

How could I monitoring that subroutine status? Or get the fortran loop index in my C++ application?

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
3,752 Views

Confused... You say you are using Intel Visual Fortran but you seem to be using gfortran instead. The two do not mix. I can't help you with gfortran issues.

Your sources build and run fine (with some warning messages by MSVC) using Microsoft Visual C++ and Intel Visual Fortran. (I am a bit confused about the MSVC messages, but I ignored them.)

D:\Projects>ifort -c sub.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.0.4.245 Build 20190417
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

D:\Projects>cl main.cpp sub.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.21.27702.2 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\ostream(258): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\ostream(249): note: while compiling class template member function 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(int)'
main.cpp(11): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(int)' being compiled
main.cpp(11): note: see reference to class template instantiation 'std::basic_ostream<char,std::char_traits<char>>' being compiled
Microsoft (R) Incremental Linker Version 14.21.27702.2
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj
sub.obj

D:\Projects>main.exe
Monitoring Fortran subroutine...
Fortran current status = 0
Fortran current status = 1
Fortran current status = 2
Fortran current status = 3
Fortran current status = 4
Fortran current status = 5

D:\Projects>

 

View solution in original post

0 Kudos
14 Replies
Steve_Lionel
Honored Contributor III
3,752 Views

Just remove the EXTERNAL declaration - it conflicts with the interface and is unnecessary.

0 Kudos
Maia__Nycholas
Beginner
3,752 Views

Thank you, Steve!

Could you help me to complete this code example?

Here is my full C++ code:
 

#include <iostream>

extern "C" {
    void my_long_calc(void);
    void fortran_status(int* value);
}

void fortran_status(int* value)
{
    std::cout << "Fortran current status = " << *value << std::endl;
}

int main (void)
{
    std::cout << "Monitoring Fortran subroutine..." << std::endl;

    my_long_calc();

    return 0;
}

 

And  here is my full Fortran-90 code:

module my_interfaces
    use iso_c_binding
        interface
            subroutine fortran_status(progress_value) bind(C, name = 'fortran_status')
                use, intrinsic :: iso_c_binding
                integer(c_int), intent(out) :: progress_value
            end subroutine fortran_status
        end interface
end module my_interfaces

    
! My long calc subroutine
subroutine my_long_calc(progress_value) BIND(C, name = 'my_long_calc')
    use, intrinsic :: ISO_C_BINDING
    use my_interfaces
    implicit none
    
    integer (C_INT), INTENT(INOUT) :: progress_value
    integer (C_INT) :: count
    
    do count = 0, 5    
        progress_value = progress_value + 1
        
        ! Send 'progress_value' to a C++ function:
        call fortran_status(progress_value)
        
        ! Wait 1 second:
        call sleep(1)
    end do
    
end subroutine my_long_calc

I compile the fortran code to a Static Library (Lib2.lib) x86 bits using Visual Studio 2019 / Visual Fortran.
Now I'm trying to link the C++ code with Fortran Static Lib using MingW g++:
 

g++ -Wall -L. .\Lib2.lib -lgfortran .\main.cpp -o app.exe

I got this linker error:
 

undefined reference to `my_long_calc'

What I have to do?

I'm would like to see this terminal output:
 

Monitoring Fortran subroutine...

Fortran current status = 0
Fortran current status = 1
Fortran current status = 2
​​​​​​​Fortran current status = 3
​​​​​​​Fortran current status = 4
​​​​​​​Fortran current status = 5

Could you help me?


Thank you,

0 Kudos
Maia__Nycholas
Beginner
3,752 Views

UPDATE 1:
Now this changed Fortran code compiles and it work well ONLY if I'm using MingW g++ (x86).

Fortran code:

 

module my_interfaces
  use iso_c_binding
  interface
    subroutine fortran_status(progress_value) bind(C, name = 'fortran_status')
      use, intrinsic :: iso_c_binding
      integer(c_int), intent(out) :: progress_value
    end subroutine fortran_status
  end interface
end module my_interfaces


! My long calc subroutine
subroutine my_long_calc() BIND(C, name = 'my_long_calc')
  use, intrinsic :: ISO_C_BINDING
  use my_interfaces
  implicit none

  integer (C_INT) :: progress_value
  integer (C_INT) :: count

  progress_value = 0

  do count = 0, 5
    progress_value = count
    
    ! Send 'progress_value' to a C++ function:
    call fortran_status(progress_value)

    ! Wait 1 second:
    call sleep(1)
  end do
end subroutine my_long_calc



C++ Code:

 

#include <iostream>

extern "C" {
    void my_long_calc(void);
    void fortran_status(int* value);
}


void fortran_status(int* value)
{
    std::cout << "Fortran current status = " << *value << std::endl;
}


int main (void)
{
    std::cout << "Monitoring Fortran subroutine..." << std::endl;
    my_long_calc();
    return 0;
}



Compile c++:
 

g++ -Wall -c .\main.cpp

Compile fortran:
 

gfortran -c .\gfortran.f90

Link all together:
 

g++ .\main.o .\gfortran.o -o app.exe -lgfortran

The problem now is that I need to use Visual Studio 2019 and Visual Fortran to develop my Fortran Code.
And I would like to compile all Fortran code to a single static library (*.lib) file using Visual Studio.

What I need to change to get to link the *.lib file (from Visual Fortran) using the MingW g++ command?

I was thinking to use something like this: 

g++ main.cpp my_lib.lib -o app.exe

But I got this linker error: 

undefined reference to my_long_calc

What I need to do?

0 Kudos
Steve_Lionel
Honored Contributor III
3,753 Views

Confused... You say you are using Intel Visual Fortran but you seem to be using gfortran instead. The two do not mix. I can't help you with gfortran issues.

Your sources build and run fine (with some warning messages by MSVC) using Microsoft Visual C++ and Intel Visual Fortran. (I am a bit confused about the MSVC messages, but I ignored them.)

D:\Projects>ifort -c sub.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.0.4.245 Build 20190417
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

D:\Projects>cl main.cpp sub.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.21.27702.2 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\ostream(258): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\ostream(249): note: while compiling class template member function 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(int)'
main.cpp(11): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(int)' being compiled
main.cpp(11): note: see reference to class template instantiation 'std::basic_ostream<char,std::char_traits<char>>' being compiled
Microsoft (R) Incremental Linker Version 14.21.27702.2
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj
sub.obj

D:\Projects>main.exe
Monitoring Fortran subroutine...
Fortran current status = 0
Fortran current status = 1
Fortran current status = 2
Fortran current status = 3
Fortran current status = 4
Fortran current status = 5

D:\Projects>

 

0 Kudos
Maia__Nycholas
Beginner
3,752 Views

Thanks Steve!

Yes, I was trying to mix these 2 compilers: Visual Fortran (Visual Studio) + MingW g++.
The main idea is to develop a cross-plataform application...so I would like to write a Fortran code that can be compile in Windows and Linux environment.

Well, about the code above...I compiled it in Visual Fortran and linked well using QT Creator (qmake). Works good on Windows!
Thanks for your help...

Now I'm trying to send a Fortran string to my C++ application...
I started from this fortran/c++ example that is running, and I tried to change only the Interface to send a fortran string...but it's not working...

Please, could you help me?
https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/815905


Steve! Thank you so much!

0 Kudos
Steve_Lionel
Honored Contributor III
3,752 Views

I am unsure how Intel Fortran-compiled sources work when mixed with g++ in MingW. It's not a combination I would recommend. You're doing well to use Fortran's C interoperability features and, done correctly, it should be portable (that is the whole idea of those features!)

I answered your string issue in the other thread.

0 Kudos
FortranFan
Honored Contributor III
3,752 Views

Maia, Nycholas wrote:

..

The problem now is that I need to use Visual Studio 2019 and Visual Fortran to develop my Fortran Code.
And I would like to compile all Fortran code to a single static library (*.lib) file using Visual Studio.

What I need to change to get to link the *.lib file (from Visual Fortran) using the MingW g++ command? ..

@Maia, Nycholas.

Note on Windows, instead of a static library, you can work with a dynamic library (DLL) i.e., you can compile using Intel Fortran and link your Fortran code as a DLL, either from the command line or using Visual Studio (preferably) and consume it from a C++ program built using GCC and MinGW.  See an example below using the command line - note the same idea holds true using Visual Studio.  If this looks an option for you i.e., working with a DLL, you can check whether the same approach using a "shared" library can work for you on other platforms of interest (Linux?).

Fortran code: note some changes with abstract interfaces, use of module for all Fortran procedures, and use of a default message writer:

module my_interfaces

   use, intrinsic :: iso_c_binding, only : c_char, c_size_t

   abstract interface
      subroutine Ifortran_message(msg, lenmsg) bind(C)
         import :: c_char, c_size_t
         implicit none
         ! Argument list
         character(kind=c_char, len=1), intent(in) :: msg(*)
         integer(c_size_t), intent(in), value      :: lenmsg
      end subroutine Ifortran_message
   end interface

end module my_interfaces

module my_long_calc_m

   use, intrinsic :: iso_c_binding, only : c_char, c_size_t, c_funptr, c_f_procpointer
   use, intrinsic :: iso_fortran_env, only : stdout => output_unit

   use my_interfaces, only : Ifortran_message

   implicit none

   procedure(Ifortran_message), pointer :: pMessageWriter => DefaultMessageWriter

contains

   ! My long calc subroutine
   subroutine my_long_calc() bind(C, name="my_long_calc")

      ! A single variable:
      character(kind=c_char, len=:), allocatable :: msg
      integer(c_size_t) :: lenmsg

      msg = "this is a msg from fortran"
      lenmsg = len_trim(msg, kind=kind(lenmsg) )

      ! Send a message to the C++ application:
      call pMessageWriter(msg, lenmsg)

      return

   end subroutine my_long_calc

   subroutine SetMessageWriter( pWriter ) bind(C, name="SetMessageWriter" )

      ! Argument list
      type(c_funptr), intent(in), value :: pWriter

      call c_f_procpointer( cptr=pWriter, fptr=pMessageWriter )

      return

   end subroutine

   subroutine DefaultMessageWriter( msg, lenmsg ) bind(C, name="DefaultMessageWriter" )

      ! Argument list
      character(kind=c_char, len=1), intent(in) :: msg(*)
      integer(c_size_t), intent(in), value      :: lenmsg

      ! Error handling elided e.g., lenmsg <= 0

      write( stdout, fmt="(*(g0))" ) msg(1:lenmsg)

      return

   end subroutine DefaultMessageWriter

end module

Use of a Windows definition file to handle exported symbols of your DLL:

LIBRARY my_long_calc
EXPORTS
     my_long_calc       @1
     SetMessageWriter   @2

C++ main program: use a typedef for a function pointer

#include <iostream>

typedef void (* pMessageWriter)( char*, size_t );

extern "C" {
  void my_long_calc(void);
  void SetMessageWriter( pMessageWriter );
}

void MyWriter(char* msg, size_t lenmsg)
{
  std::cout.write( msg, lenmsg );
}

int main(int argc, char *argv[])
{
    SetMessageWriter( MyWriter );
    my_long_calc();

    return 0;
}

Compile and link steps:

C:\Temp>ifort /standard-semantics /c /warn:all /stand:f18 my_long_calc.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.1.0.085 Pre-Release Beta Build 20190522
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

ifort: NOTE: The Beta evaluation period for this product ends on 9-oct-2019 UTC.

C:\Temp>link /DLL /DEF:my_long_calc.def /subsystem:windows my_long_calc.obj /out:my_long_calc.dll
Microsoft (R) Incremental Linker Version 14.21.27702.2
Copyright (C) Microsoft Corporation.  All rights reserved.

   Creating library libmy_long_calc.lib and object libmy_long_calc.exp

C:\Temp>g++ -Wall -c main.cpp

C:\Temp>g++ main.o -o main.exe -lmy_long_calc -Lc:\temp

C:\Temp>dir lib*.*
 Volume in drive C is OSDisk
 Volume Serial Number is ..

 Directory of C:\Temp

08/13/2019  05:21 PM           544,768 libmy_long_calc.dll
08/13/2019  05:21 PM               952 libmy_long_calc.exp
08/13/2019  05:16 PM             2,112 libmy_long_calc.lib
..

C:\Temp>

Upon execution:

C:\Temp>main.exe
this is a msg from fortran
C:\Temp>

 

0 Kudos
Maia__Nycholas
Beginner
3,752 Views

@FortranFan, thank you for your good explanation!
I will try!

Thanks,

0 Kudos
Maia__Nycholas
Beginner
3,752 Views

@FortranFan,

Thank about your information about DLL on Windows, but I really would like to create a fortran static library for other reasons.

I'm developing some plugins with UI for a other main application...and these plugins should be a mix of QT GUI + Fortran and C++ code.
For each developed plugin, I would like to build 2 output files:
1- A single *.dll file (Windows)
2- A single *.so file (Linux)

To build these plugins (dynamic libraries) above, I'm doing like this:


1- Write the "plugin X" Fortran source code and compile it to a static library (*.dll) and (*.a)
2- Write the "plugin X" C++ and QT UI source code using QT Creator IDE
3- Config QT Creator IDE to build a "shared library" output (*.dll) and (*.so).
4- Generate the final plugin file (*.dll) or (*.so) compiling the C++/UI code and linking it statically with the fortran static library.

So, my "plugin X" is a single file "shared library" (*.dll or *.so), but it have a Fortran static library inside of it.

I tried to test your Fortran code above, it compiles ok and I got the static library file using Visual Fortran, but I got linker errors on QT Creator IDE.
 

unresolved external symbol for_dealloc_allocatable referenced in function my_long_calc
unresolved external symbol for_alloc_allocatable referenced in function my_long_calc
unresolved external symbol for_len_trim referenced in function my_long_calc
unresolved external symbol c_f_pointer_set_scalar referenced in function SetMessageWriter
unresolved external symbol for_write_seq_fmt referenced in function DefaultMessageWriter

And a single C++ warning:

warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long long') to 'std::streamsize' (aka 'long long')

You already explain a lot to me about Fortran, but could you help me to complete this example?

I need to generate a cross-platform Fortran static library (*.lib using Visual Fortran) and (*.so using g++) and then link it statically with my QT C++ code.


@Steve, you are welcome too for any ideas, suggestions, improvements....

Thank you for your help,

0 Kudos
FortranFan
Honored Contributor III
3,751 Views

Maia, Nycholas wrote:

.. I tried to test your Fortran code above, it compiles ok and I got the static library file using Visual Fortran, but I got linker errors on QT Creator IDE...

I know little about Qt Creator IDE but as you were advised in Quote #7, mixing libraries during linking - as you are attempting using static library with Intel Fortran and linking that with code compiled using another processor - is generally a recipe for failure.  You may be familiar with this page:

https://doc.qt.io/qtcreator/creator-tool-chains.html

You may be able to follow instructions on above page to specify your toolchains.  I'll suggest you either work with compatible processors (e.g., Intel Fortran compiler + Intel C++ on Windows, Linux; Intel Fortran + Microsoft C/C++ on Windows; or gfortran compiler + Microsoft C/C++ on Windows; or gfortran compiler + g++ on Windows, Linux) or consider the run-time invocations as per the DLL/so option.

Maia, Nycholas wrote:

.. single C++ warning ...

You can get rid of this warning as follows:

void MyWriter(char* msg, size_t lenmsg)
{
  std::cout.write( msg, static_cast<std::streamsize>(lenmsg) );
}

 

0 Kudos
Maia__Nycholas
Beginner
3,751 Views

Yes, @FortranFan... now I know about the C++/Fortran compiler differences.

So, why Am'I trying to do it using QT Creator IDE and not using only MSVC (Visual Fortran) + Intel Fortran?

This project must be cross-platform (Windows and Linux), (maybe Mac too) and this application will have GUI (window, buttons, labels, etc...).

I think that QT with QT Creator IDE is a good choose to do that.

QT Creator IDE can be configured to compile QT projects using installed Microsoft Visual C++. I attached my QT compiler configuration here that shows that I'm using Microsoft Visual C++ 16.1 (x86_amd64) to compile my QT projects.

qt_compiler.jpg

So, in the background, my tools are:
Windows 10 x64 environment:
Fortran Compiler: Visual Fortran 2019 (running inside Visual Studio 2019)
C++ Compiler: Microsoft Visual C++ 16.1 (running inside QT Creator IDE)

Linux Ubuntu 18 x64 environment:
Fortran Compiler: gfortran (terminal)
C++ Compiler: g++ (terminal)

So, I believe that I'am be able to mix the fortran static library with QT C++ UI, right?

Let's try to focus in Windows environment only now, ok?

Do you have any ideas why I'm getting these linker errors above?
 

0 Kudos
FortranFan
Honored Contributor III
3,751 Views

Maia, Nycholas wrote:

Yes, @FortranFan... now I know about the C++/Fortran compiler differences. ..

Do you have any ideas why I'm getting these linker errors above? ..

So your attached image suggests the Fortran and C++ processors are compatible - Intel Fortran and Microsoft Visual C++ - assuming that is indeed the case, my suggestion will be to check your library path settings in Qt Creator IDE and ensure the right Intel Fortran compiler related libraries are picked up during the link step.  Toward this, this page which details the settings for Visual Studio IDE might help you cross-check what you have in Qt Creator IDE currently, or what might be missing.  My hunch is once you make sure the right libraries become known to your linker via suitable settings in the IDE, your link errors will be resolved: 

https://software.intel.com/en-us/articles/configuring-visual-studio-for-mixed-language-applications

0 Kudos
gib
New Contributor II
3,751 Views

Nycholas, I am also building a Qt GUI with a Fortran engine.  In Qt Creator I link several static libraries (VTK) and several dynamic libraries, including my own Fortran library.  I had to ensure that the Qt Creator toolchain was consistent with the Qt version and with the compiler version used to build the VTK static libraries.  I did not have a version of Intel Fortran compatible with the toolset, but building my Fortran library as a DLL (in Windows) avoided the problem.  I appreciate that your situation is a bit different, since you want to produce a single DLL, while I am building an executable and it's no problem to distribute the DLL to other users of the program.

Sometimes the order of the static libraries in Qt Creator is important - this is a possible cause of your link errors.  The dependent library must be processed before the library that satisfies the dependency:

https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc

0 Kudos
Maia__Nycholas
Beginner
3,751 Views

Now, I got it working perfectly fine! Thank you so much @Steve for your patience and quick reponses!

Just to help other people...here is my full example about how to use C/C++ and Fortran with Interoperability (ISO 2003).

This example below sends data from a C++ application to a Fortran Static Library and get back some results in C++ application:

My C++ code:

#include <iostream>

extern "C" {
  void fortran_subroutine(int input1, double* input2, int* input3, size_t input4);
  void fortran_return(int by_value, double* by_ref, char* string, int* array, size_t len_array);
}

void fortran_return(int by_value, double* by_ref, char* string, int* array, size_t len_array)
{
    std::cout << "by_value: " << by_value << std::endl;

    std::cout << "by_ref: " << *by_ref << std::endl;

    std::cout << "string: " << string << std::endl;

    for (size_t i = 0; i < len_array; i++ ) {
        std::cout << "array[" << i << "] = " << array << std::endl;
    }
}

int main(int argc, char* argv[])
{
    // Init C++ input variables:
    int x = 25;
    double y = 0.12345;
    int z[] = {1, 2, 3, 4, 5};

    size_t z_size = sizeof(z)/sizeof(z[0]);

    // Send 'x' and 'z_size' by value and send 'y' and 'z' by reference to Fortran subroutine:
    fortran_subroutine(x, &y, z, z_size);

    return 0;
}

My Fortran code:

! My ISO 2003 C Bind Interface
module my_interfaces
    interface
        subroutine fortran_return(a, b, d, e, f) bind(C)
            use, intrinsic :: ISO_C_BINDING
            
            ! Pass 'a' by value:
            integer(C_INT), intent(in), value :: a
            
            ! Pass 'b' by reference:
            real(C_DOUBLE), intent(in) :: b

            ! Pass 'd' string by reference with 'C NULL CHARACTER':
            character(kind=C_CHAR), intent(in) :: d(*)
            
            ! Pass 'f' by value, and declared BEFORE 'e' (compile dependency)
            INTEGER(C_SIZE_T), INTENT(IN), value :: f
            
            ! Pass 'e' array by reference:
            integer(C_INT), DIMENSION(f), INTENT(IN) :: e
            
        end subroutine fortran_return
    end interface
end module my_interfaces

! My Fortran subroutine
subroutine fortran_subroutine(x, y, z, n) bind(C)
    use, intrinsic :: ISO_C_BINDING
    use my_interfaces
    implicit none
    

    !====== ISO BIND ARGUMENTS =====!
    ! Get 'x' from C++ by value:
    integer(C_INT), intent(in), value :: x
    ! Get 'y' from C++ by reference:
    real(C_DOUBLE), intent(in) :: y
    ! Get 'z' array from C++ by reference:
    integer(C_INT), DIMENSION(n), INTENT(INOUT) :: z
    ! Get 'n' size from C++ by value:
    INTEGER(C_SIZE_T), INTENT(IN), value :: n
    !============================
    
    ! Temp internal variable:
    integer(C_INT) :: count

    ! Declare the same type of Fortran 'interface' arguments:
    integer(C_INT) :: my_int
    real(C_DOUBLE) :: my_double
    character(kind=C_CHAR, len=50) :: my_str
    
    ! Init variables / do some stuff:
    my_int = x + 1
    my_double = y + 1
    my_str = "Hello from Fortran"//C_NULL_CHAR
    
    FORALL (count = 1:n)  z(count) = 1
    
    ! Call C++ function:
    call fortran_return(my_int, my_double, my_str, z, n)
end subroutine fortran_subroutine
    


Step 1: Compilers
Your Fortran and C/C++ compilers MUST BE COMPATIBLE EACH OTHER.
So, in Windows environment use:
-> C++: Microsoft Visual C++
-> Fortran: Intel Visual Fortran

In Linux environment use:
-> C++: GCC (yes, gcc compiles C++ code too...)
-> Fortran: gfortran

In Mac OSX environment use:
-> C++: Clang
-> Fortran: gfortran

I tested this simple example on these 3 environments and it works well.

Warning: Do NOT mix uncompatible compilers like: gcc with Intel Visual Fortran. It doesn't work!

Step 2: IDE's
If you are using compatible compilers, you can change the IDE. I tested my C++ code using Qt Creator IDE with MSVC compiler. It works great!

Step 3: Qt Creator configurations (only for Qt Creator IDE users)
If you are in Linux environment together with Qt Creator IDE, you have to just add your compiled Fortran Library using Qt Creator Wizard and the link is done.
But if you are in Windows environment with Qt Creator IDE, add your Fortran compiled library (*.lib or *.a) with Qt Creator Wizard AND add this line in the *.pro file:

LIBS += -L"<full path to Intel Visual Fortran Compiler folder>/lib/intel64_win"

Obs. 1: In my machine, I have installed IVF 2019, so this folder is in:

C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_2019.4.245/windows/compiler

Obs. 2: Be careful about select the correct 32 bits or 64 bits IVF folder

Step 4: Visual Studio IDE
If you are using Microsoft Visual Studio IDE you have to link your Fortran Static Library with your C/C++ application too.
I not tested this setup, but is easy to find how to do it on internet.

Step 5: Intel Visual Fortran
If you are building a Fortran Static Library using Visual Studio 2019, check this configurations:


Project Properties -> Fortran -> Libraries:
- Run-time: Multithreaded
- Disable Default Library Search Rules: No
- Disable OBJCOMMENT Library Names in Object: No


Project Properties -> Fortran -> Librarian -> General:
- Link Library Dependencies: Yes

Build and Run!
The output should be like this:
 

by_value: 26
by_ref: 1.12345
string: Hello from Fortran
array[0] = 1
array[1] = 1
array[2] = 1
array[3] = 1
array[4] = 1

 

0 Kudos
Reply