Mazkime
Mazkime

Reputation: 93

Passing a string from Python to Fortran through Cython

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

Answers (1)

roygvib
roygvib

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

Related Questions