I needed to call Fortran functions from Python-Cython. To do this, I adapted a method described in fortran90.org and some lines of code from this Stackoverflow page. Since it didn't work without modification, I present the result here:
A Fortran file modf.f90:
module wrapper_f_to_c use iso_c_binding, only: c_double, c_int implicit none contains subroutine c_func(a, b, input, output) bind(c) real(c_double), intent(in) :: a real(c_double), intent(in) :: b integer(c_int), intent(in) :: input real(c_double), intent(out) :: output write(*,*) a*b output = 10*input end subroutine end module
A Cython file mod.pyx:
from numpy cimport ndarray from numpy import empty cdef extern: void c_func(double *a, double *b, int *input, int *output) def func(double a, double b, int input): int output c_func(&a, &b, &input, &output) return output
A Python file for building Fortran code with a setup.py file:
import os import platform import subprocess libs_gfortran = ['gfortran'] libs_mpifortran = ['mpi_f90', 'mpi_f77'] path_base = os.path.join( 'build', 'temp.' + platform.system().lower() + '-' + platform.machine() + '-' + '.'.join(platform.python_version_tuple()[:2])) def build_objects_from_fortran(sources): objects = [] for source in sources: path_dir, name = source.rsplit(os.path.sep, 1) path_dir_objet = os.path.join(path_base, path_dir) if not os.path.exists(path_dir_objet): os.makedirs(path_dir_objet) path_objet = os.path.join( path_dir_objet, os.path.splitext(name)[0] + '.o') objects.append(os.path.relpath(path_objet)) command_compile_fortran_mod = ( 'mpif90 ' + ' -O3 -fPIC -J ' + path_dir_objet + ' ' + source + ' -c -o ' + path_objet) print(command_compile_fortran_mod) code = subprocess.check_output(command_compile_fortran_mod, shell=True) print(code) return objects if __name__ == '__main__': path_source = 'pack0/source' objects = build_objects_from_fortran([path_source + '/modf.f90']) print(objects)
The setup.py file:
from setuptools import setup from Cython.Distutils import build_ext from Cython.Distutils.extension import Extension import os os.environ['CC'] = 'mpicc' path_source = 'pack0/source' from setup_fortran import ( build_objects_from_fortran, libs_gfortran, libs_mpifortran) objects = build_objects_from_fortran([path_source + '/modf.f90']) # for include directories import numpy import mpi4py files = ['mod.pyx'] ext = Extension( name='pack0.m0', libraries=['mpi'] + libs_gfortran + libs_mpifortran, sources=[path_source + '/' + f for f in files], include_dirs=[numpy.get_include(), mpi4py.get_include(), 'include'], extra_objects=objects) setup( name='pack0', packages=['pack0'], cmdclass={'build_ext': build_ext}, ext_modules=[ext])
Build with python setup.py build_ext --inplace
.