Calling c++ from fortran

147 views Asked by At

I want to call a function which is both in a c++ parent class "inval" and in the c++ derived class "SMval", from Fortran. The function I want to call is included in a bigger code which I would like to interface to my fortran. I have written the following code (3 files)

In library_wrapper.h:

#include "classes.h"
#include "SMval.h"
#ifdef __cplusplus 
//Forward declarations of classes 
class inval; 
class SMval;

extern "C" { 
#endif

void* createinval_(); 
void destroyinval_(void* instance); 
void* createSMval_(); 
void destroySMval_(void* instance); 
void invalsetWrapper_(const int idx, const double val); 
void SMvalsetWrapper_(const int idx, const double val); // Declaration of the wrapper function

#ifdef __cplusplus } 
#endif

In library wrapper.cpp:

#include "library_wrapper.h" 
#include "classes.h" 
#include "SMval.h" 
#include "Cplx.h"
#include <iostream> 
#include <string.h>

extern "C" {
void* createinval_() {
    return new inval();
}

void* createSMval_() {
    return new SMval();
}

void destroyinval_(void* instance) {
     delete static_cast<inval*>(instance);
}

void destroySMval_(void* instance) {
    delete static_cast<SMval*>(instance);
}

void invalsetWrapper_(const int idx, const double val) {
    inval obj;
    return obj.set(idx, val);
}

void SMvalsetWrapper_(const int idx, const double val) {
    SMval obj;
    return obj.set(idx, val);
}

}

and finally the main fortran:

   PROGRAM main
   implicit none
   CALL CREATEINVAL()
   CALL CREATESMVAL()
   CALL INVALSETWRAPPER(12, 1/137.03599976)
   CALL SMVALSETWRAPPER(1, 91.1876)
   END

I am compiling on MAC Sonoma:

clang++ -g -std=c++11 -c library_wrapper.cpp
ld -r allothersobjectfiles.o library_wrapper.o -o combined_library.o
clang++ -shared -o liblibrary.a combined_library.o
gfortran -ffixed-line-length-none fortran.f -o main -L. -llibrary

But I get

ld: Undefined symbols:
  _createinval_, referenced from:
      _MAIN__ in ccPLQP9I.o
  _createsmval_, referenced from:
      _MAIN__ in ccPLQP9I.o
  _invalsetwrapper_, referenced from:
      _MAIN__ in ccPLQP9I.o
  _smvalsetwrapper_, referenced from:
      _MAIN__ in ccPLQP9I.o
collect2: error: ld returned 1 exit status

I tried to create a static library and link it, but it is still not working

1

There are 1 answers

6
PierU On

To do that as properly as possible, you should use the C/Fortran interoperabilty features of Fortran, based on the iso_c_binding Fortran module

For instance, to call the invalsetWrapper_ function, your Fortran code should look like:

program main
   use iso_c_binding
   implicit none

   interface
      subroutine inval_set_wrapper(idx,val) bind(C,name="invalsetWrapper_")
         import c_int, c_double
         integer(kind=c_int), value :: idx
         real(kind=c_double), value :: val
      end subroutine
   end interface

   !...

   call inval_set_wrapper(12, 1/137.03599976d0)

end

Note that the interoperability assumes the use of pairs of compilers (that is, you should use gcc along with gfortran), even if it often works when mixing compilers (but without any guarantee).