Reputation: 93
I am trying to pass a string from Python to Fortran using Cython, but I can't make it work correctly. I successfully passed lists of real using numpy arrays, so I tried to do something similar by converting my string to a array of char inside my Cython routine and passing this array to Fortran, but I do not get the correct char* in the Fortran routine.
I tried to follow the infos given here : http://docs.cython.org/src/tutorial/strings.html, especially the need to convert my python string to a C char* using the encode()
method, but it does not work properly.
Any help to make it work would be greatly appreciated. Here is a minimum working example :
File ex.pyx
cdef extern from "ex.h":
void fortfunction(int* nchar, char** outputFile)
def f(str file):
ftmp = file.encode('UTF-8')
cdef char* outputFile = ftmp
cdef int nchar = len(file)
fortfunction(&nchar, &outputFile)
File ex.h
extern void fortfunction(int* nchar, char** outputFile);
File ex.f90
module ex
use iso_c_binding
implicit none
contains
subroutine fortfunction(nchar,outputFile) bind(c)
implicit none
integer(c_int), intent(in) :: nchar
character(c_char), intent(in) :: outputFile(nchar)
print*,'outputFile=',outputFile
end subroutine fortfunction
end module ex
File setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from os import system
# compile the fortran modules without linking
system('ifort ex.f90 -c -o ex.o -fPIC -nofor_main')
ext_modules = [Extension('ex', # module name:
['ex.pyx'], # source file:
extra_link_args=['-limf','-lifcore','ex.o'])] # other files to link to
setup(name = 'mymodule',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules)
to build the package, runpython setup.py build_ext --inplace
Here is what I finally obtain
>>> import ex
>>> ex.f('foo')
outputFile=�
Upvotes: 4
Views: 416
Reputation: 7395
Because the dummy argument outputFile(nchar)
in ex.f90 is an array of character(c_char)
, it receives the address of the first element of this array. So I think we should probably pass char*
rather than char**
, such that
File ex.pyx
cdef extern from "ex.h":
void fortfunction(int* nchar, char* outputFile)
def f(str file):
ftmp = file.encode('UTF-8')
cdef char* outputFile = ftmp
cdef int nchar = len(file)
fortfunction(&nchar, outputFile)
File ex.h
extern void fortfunction(int* nchar, char* outputFile);
then the Cython code seems to be working properly:
>>> import ex
>>> ex.f( 'foo' )
outputFile=foo
Upvotes: 4