user2196748
user2196748

Reputation: 63

how to call a Fortran90 function included in a module in c++ code?

I m including a fortran90 program that is not mine in my C++ project .

In the first stept I try to call the function by their name_() and i get the error "undefined reference to mp_mpi_cartesian_init_ "by dispalying the symbol of the obj file (using nm) i found that the function are called by their module as module_function_ so i add the module name and i Get the same problem but between fortran obj such as "Constants.f90:(.text+0x36): undefined reference to __powi4i4"

here is the c++ code :

 #include <iostream>
 #include <complex>


 using namespace std;

 extern"C" {

        void  mod_save_wave_mp_read_it_psi_(int * it,complex<double>*  psi_E1E2 );
        void  mod_mpi_cartesian_mp_mpi_cartesian_init_( );
        extern int mod_mpl_h_mp_iproc_ ;
 }

 int  main(){
     complex<double>  psi_local[512*24*512*24];
     int it ;
     mod_mpi_cartesian_mp_mpi_cartesian_init_();
     cout << "proc  :" << mod_mpl_h_mp_iproc_ << "avant lecture\n";
     mod_save_wave_mp_read_it_psi_(&it,psi_local);
     cout << "psi ="<< psi_local[0] << "poiur le proc "<<mod_mpl_h_mp_iproc_ <<"\n";
   }

and this is an exemple of a module :

MODULE mod_save_wave

USE mod_constants
USE mod_MPI_CARTESIAN

    USE mod_time_mesure,    ONLY : tempsEcoule
    USE mod_input_data, ONLY : Nt_laserPsansLaser
    USE mod_input_data, ONLY : n_phi, n_rho1_seg, n_rho2_seg
    USE mod_input_data, ONLY : Nt_periode, save_periodique


    !////////////////////////////////////////////////////////////////
    IMPLICIT NONE                           !
    REAL(kind=d_t)      :: prog_start_time, time_max_second !
    character(len=80)   :: IntermedWaveDir
    !================================================================


CONTAINS

SUBROUTINE begin_count_time()
    IMPLICIT NONE

    prog_start_time = tempsEcoule()                 !

END SUBROUTINE begin_count_time


SUBROUTINE READ_IT_PSI( it,  psi_E1E2 )
    IMPLICIT NONE
    !////////////////////////////////////////////////////////////////////////////////
    INTEGER                             :: it       !
    COMPLEX(kind=d_t), DIMENSION(n_phi,n_rho1_seg,n_phi,n_rho2_seg) :: psi_E1E2 !
    !================================================================================

    integer :: c

    do c = 0, c_max-1
        if( mod(iproc,c_max)==c ) then

            !////////////////////////////////////////////////////////////////////////////////
            OPEN( unit=11,file=concat(trim(IntermedWaveDir),concat(concat('BACK/wave_',str_iproc),'_2p2p2')),&
                            status='old', form='unformatted', MODE='READ'       )
                READ(11) it                             !
                READ(11) psi_E1E2                           !
            CLOSE(11)                                   !
            print*,'iproc,readed it=',iproc, it

        endif

        CALL MPI_BARRIER(MPI_COMM_WORLD,infompi)                    !
        !================================================================================
    enddo
    !================================================================================

END SUBROUTINE READ_IT_PSI


SUBROUTINE WRITE_IT_PSI( it, psi_E1E2 )
    IMPLICIT NONE
    !////////////////////////////////////////////////////////////////////////////////
    INTEGER                             :: it       !
    COMPLEX(kind=d_t), DIMENSION(n_phi,n_rho1_seg,n_phi,n_rho2_seg) :: psi_E1E2 !
    !================================================================================

    integer :: c

    do c = 0, c_max-1
        if( mod(iproc,c_max)==c ) then
            !////////////////////////////////////////////////////////////////////////////////
            OPEN( unit=11,file=concat(trim(IntermedWaveDir),concat(concat('wave_',str_iproc),'_2p2p2')),&
                                        form='unformatted') !
                WRITE(11) it+1          !---- recommence a partir de la prochaine iterat!
                write(11) psi_E1E2                          !
            CLOSE(11)                                   !
        endif

        CALL MPI_BARRIER(MPI_COMM_WORLD,infompi)                    !
        !================================================================================
    enddo

END SUBROUTINE WRITE_IT_PSI


END MODULE mod_save_wave

Upvotes: 6

Views: 4457

Answers (2)

cup
cup

Reputation: 8237

I am assuming you are using the g++, gfortran, mpif90 toolchain. If you have a module

module rocker
contains
subroutine bye_baby
...
end subroutine

The external C declaration for it in C++ is

extern "C"
{
    //          ,-- 2 Leading underscores to start
    //          | ,-- then the module name
    //          | |     ,-- then _MOD_
    //          | |     |    ,-- then the subroutine name
    //          V V     V    V
    extern void __rocker_MOD_bye_baby();
}

You may also need to add attribute((stdcall)) after the extern. By default, C assumes cdecl which stacks the parameters differently.

If you do not want the __rocker_MOD part, then the subroutine/function should not be declared in a module.

Upvotes: 6

B&#225;lint Aradi
B&#225;lint Aradi

Reputation: 3812

First of all, on the Fortran side I strongly suggest to use the Fortran 2003 features of C-bindings, and especially the iso_c_binding module. You can see many examples for that on SO, among others this post. Then you get rid of the "how does my fortran compiler name my procedures" problem in a transparent and compiler independent way.

The linking problem arrises as you are missing some libraries of your Fortran compiler I guess. You either can try to link your object file using the Fortran compiler, or find out which library is missing and link it manually. Some Fortran compiler have also options for creating a library with automatical linking of compiler related libraries.

Upvotes: 1

Related Questions