You can still make it work, but to get hold of the non-interoperable Fortran type you’ll need to introduce a typeless “handle” object:
module somemodule_wrap
use, intrinsic :: iso_c_binding, only: &
c_double, c_int, c_ptr, &
c_f_pointer, c_loc
use somemodule, only: sometype, frout2
implicit none
contains
type(c_ptr) function sometype_create(len) bind(c)
integer(c_int), value :: len
type(sometype), pointer :: p
allocate(p)
allocate(p%a(len))
sometype_create = c_loc(p)
end function
type(c_ptr) function sometype_a(ptr, n) bind(c)
type(c_ptr), intent(in), value :: ptr
integer(c_int), intent(out) :: n
type(sometype), pointer :: p => null()
call c_f_pointer(ptr,p)
if (allocated(p%a)) then
n = size(p%a)
sometype_a = c_loc(p%a)
else
sometype_a = c_null_ptr
end if
end function
subroutine sometype_free(ptr) bind(c)
type(c_ptr), value :: ptr
type(sometype), pointer :: p => null()
call c_f_pointer(ptr,p)
if (allocated(p%a)) deallocate(p%a)
deallocate(p)
end subroutine
subroutine frout2_wrap(ptr) bind(c)
type(c_ptr), value :: ptr
type(sometype), pointer :: p => null()
call c_f_pointer(ptr,p)
if (allocated(p%a)) then
call frout2(p)
end if
end subroutine
end module
// main.c
//
#include "somemodule_wrap.h"
int main(void)
{
void *h_sometype = sometype_create( 6 );
int n;
double *a;
a = sometype_a(h_sometype, &n);
for (int i = 0; i < n; i++) {
a[i] = (double) i;
}
frout2_wrap(h_sometype);
sometype_free(h_sometype);
return 0;
}
Example build process and output:
ivan:~/fortran/somemodule$ make
gfortran -Wall -fcheck=all -std=f2018 -c somemodule.f90
gfortran -fc-prototypes -fsyntax-only somemodule_wrap.f90 > somemodule_wrap.h
gfortran -Wall -fcheck=all -std=f2018 -c somemodule_wrap.f90
gcc-10 -Wall -std=c11 -o main main.c somemodule_wrap.o somemodule.o -lgfortran
ivan:~/fortran/somemodule$ ./main
1 6 6
0.0000000000000000 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 5.0000000000000000
gfortran
is the only Fortran compiler I’m aware of that supports generation of the corresponding C prototypes.
Edit: here are the build files (both CMake and a custom Makefile) in case anyway is interested:
ivan:~/fortran/somemodule$ tree
.
├── CMakeLists.txt
├── Makefile
├── main.c
├── somemodule.f90
└── somemodule_wrap.f90
0 directories, 5 files
CMakeLists.txt
cmake_minimum_required(VERSION 3.12.0)
project(someproject VERSION 0.1.0 LANGUAGES C Fortran)
add_library(
somemodule
somemodule.f90
somemodule_wrap.f90
)
add_custom_command(
OUTPUT somemodule_wrap.h
COMMAND gfortran -fc-prototypes -fsyntax-only ${CMAKE_CURRENT_SOURCE_DIR}/somemodule_wrap.f90 > ${CMAKE_CURRENT_SOURCE_DIR}/somemodule_wrap.h
DEPENDS somemodule_wrap.f90
)
add_executable(main main.c somemodule_wrap.h)
target_link_libraries(main somemodule)
Makefile
FC=gfortran
CC=gcc-10
FCFLAGS=-Wall -fcheck=all -std=f2018
CFLAGS=-Wall -std=c11
LDFLAGS=-lgfortran
.phony: all clean
all: main
main: main.c somemodule_wrap.o somemodule.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
main.c: somemodule_wrap.h
somemodule_wrap.h: somemodule_wrap.f90
gfortran -fc-prototypes -fsyntax-only $< > $@
somemodule_wrap.f90: somemodule.mod
somemodule_wrap.o somemodule_wrap.mod: somemodule_wrap.f90 somemodule.mod
$(FC) $(FCFLAGS) -c $<
somemodule.o somemodule.mod: somemodule.f90
$(FC) $(FCFLAGS) -c $<
clean:
rm -rf *.o *.mod somemodule_wrap.h main