Shared variables between Cython and Fortran

16 views
Skip to first unread message

javier delgado

unread,
Aug 10, 2017, 5:00:10 PM8/10/17
to cython-users
Hi,

I am trying to write a package that combines Python and Fortran. I'm currently struggling to figure out how to share a module variable. Specifically, I want to be able to modify the variable in the Python code and have the change reflected in Fortran and vice versa. The following are the contents of the source files:

m.f90
       MODULE m
         USE ISO_C_BINDING
         integer(C_INT), bind(C, name="py_int") :: fort_int
       END MODULE

f.f90 - simply sets variable to 99
       subroutine f() bind(C, name="f")
         use m, only : fort_int
         use ISO_C_BINDING
         fort_int = 99
       END subroutine f

test.h
extern int py_int;
void f(void) ;

lib.pyx
def doit():
    cdef extern from "test.h":
        extern int py_int
        void f()

    py_int = 5
    print "Before f(): ", py_int
    f()
    print "after f(): ", py_int

Compilation script:
cython lib.pyx
ifort -c m.f90  -fPIC
ifort -c f.f90 -fPIC
INCLUDES="-I/usr/include/python2.7"
LIBS="-lpthread -ldl -lutil -lm -lpython2.7"
eval icc -c lib.c -fPIC $INCLUDES $LIBS
eval icc -shared f.o m.o  lib.o -o lib.so -fPIC $INCLUDES $LIBS

run.py  - The program that runs it
from lib import doit
doit()

Output
Before f():  5
after f():  5 !! <- should be 99, since f() modifies the variable


My understanding is that by declaring "py_int" within a  "cdef extern" block, Cython would make it an "extern int" that would ultimately point to the variable declared in m.f90. But apparently that is not happening. 
Can someone point out the flaw in my understanding?

Thanks!

Pierre Complex

unread,
Aug 11, 2017, 7:07:17 AM8/11/17
to cython-users
The line "py_int = 5" makes the variable become local, whereas you wish to use the globally defined variable.

From Python's documentation: "A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects." (see https://docs.python.org/3/tutorial/classes.html#python-scopes-and-name-spaces )

Simply add "global py_int" at the start of the function should solve the issue.

Regards,

Pierre

javier delgado

unread,
Aug 11, 2017, 3:48:28 PM8/11/17
to cython-users
Thanks, Pierre!
In addition to making it global, I had to put the extern statement outside of the python function. 

Here is the final version of "lib.pyx" in case anyone runs into this in the future:

cdef extern from "test.h":
    extern int py_int
    void f()


def doit():
    global py_int


    py_int = 5

    print "Before f(): ", py_int
    f()
    print "after f(): ", py_int


Pierre Complex

unread,
Aug 12, 2017, 5:40:38 AM8/12/17
to cython-users
Glad that it works! In my tests, I ended up moving the extern part as one of the steps
but did not mention it.

Regards,

Pierre
Reply all
Reply to author
Forward
0 new messages