Title: Wrapping F compiled Fortran 90 modules with F2PY ================================================ Rationale: The F compiler does not support external procedures which makes it impossible to use it in F2PY in a normal way. This document describes a workaround to this problem so that F compiled codes can be still wrapped with F2PY. Author: Pearu Peterson Date: May 8, 2002 Acknowledgement: Thanks to Siegfried Gonzi who hammered me to produce this document. Normally wrapping Fortran 90 modules to Python using F2PY is carried out with the following command f2py -c -m fun foo.f90 where file foo.f90 contains, for example, module foo public :: bar contains subroutine bar (a) integer,intent(inout) :: a print *,"Hello from foo.bar" print *,"a=",a a = a + 5 print *,"a=",a end subroutine bar end module foo Then with a supported F90 compiler (running `f2py -c --help-compiler' will display the found compilers) f2py will generate an extension module fun.so into the current directory and the Fortran module foo subroutine bar can be called from Python as follows >>> import fun >>> print fun.foo.bar.__doc__ bar - Function signature: bar(a) Required arguments: a : in/output rank-0 array(int,'i') >>> from Numeric import array >>> a = array(3) >>> fun.foo.bar(a) Hello from foo.bar a= 3 a= 8 >>> a 8 >>> This works nicely with all supported Fortran compilers. However, the F compiler (http://www.fortran.com/F/compilers.html) is an exception. Namely, the F compiler is designed to recognize only module procedures (and main programs, of course) but F2PY needs to compile also the so-called external procedures that it generates to facilitate accessing Fortran F90 module procedures from C and subsequently from Python. As a result, wrapping F compiled Fortran procedures to Python is _not_ possible using the simple procedure as described above. But, there is a workaround that I'll describe below in five steps. 1) Compile foo.f90: F -c foo.f90 This creates an object file foo.o into the current directory. 2) Create the signature file: f2py foo.f90 -h foo.pyf This creates a file foo.pyf containing module foo ! in foo.f90 real public :: bar subroutine bar(a) ! in foo.f90:foo integer intent(inout) :: a end subroutine bar end module foo 3) Open the file foo.pyf with your favorite text editor and change the above signature to python module foo interface subroutine bar(a) fortranname foo_MP_bar intent(c) bar integer intent(in,out) :: a end subroutine bar end interface end python module foo The most important modifications are a) adding `python' keyword everywhere before the `module' keyword b) including an `interface' block around the all subroutine blocks. c) specifying the real symbol name of the subroutine using `fortranname' statement. F generated symbol names are in the form _MP_ d) specifying that subroutine is `intent(c)'. Notice that the `intent(inout)' attribute is changed to `intent(in,out)' that instructs the wrapper to return the modified value of `a'. 4) Build the extension module f2py -c foo.pyf foo.o --fcompiler=Gnu /opt/F/lib/quickfit.o \ /opt/F/lib/libf96.a This will create the extension module foo.so into the current directory. Notice that you must use Gnu compiler (gcc) for linking. And the paths to F specific object files and libraries may differ for your F installation. 5) Finally, we can call the module subroutine `bar' from Python >>> import foo >>> print foo.bar.__doc__ bar - Function signature: a = bar(a) Required arguments: a : input int Return objects: a : int >>> foo.bar(3) 8 >>> Notice that the F compiled module procedures are called as ordinary external procedures. Also I/O seems to be lacking for F compiled Fortran modules. Enjoy, Pearu