Cython y fortran - cómo compilar juntos sin f2py

ACTUALIZACIÓN FINAL

Esta pregunta es sobre cómo escribir unsetup.py que compilará un módulo de cython que accede directamente al código FORTRAN, como lo haría C. Fue un viaje bastante largo y arduo hacia la solución, pero el lío completo se incluye a continuación para el contexto.

PREGUNTA ORIGINAL

Tengo una extensión que es un archivo de Cython, que configura algo de memoria del montón y lo pasa al código de Fortran, y un archivo de Fortran, que es un módulo antiguo venerable que me gustaría evitar volver a implementar si puedo.

los.pyx el archivo se compila bien en C, pero el compilador de cython se ahoga en el.f90 archivo con el siguiente error:

$ python setup.py build_ext --inplace
running build_ext
cythoning delaunay/__init__.pyx to delaunay/__init__.c
building 'delaunay' extension
error: unknown file type '.f90' (from 'delaunay/stripack.f90')

Aquí está (la mitad superior de) mi archivo de configuración:

from distutils.core import setup, Extension
from Cython.Distutils import build_ext

ext_modules = [
  Extension("delaunay",
    sources=["delaunay/__init__.pyx",
             "delaunay/stripack.f90"])
]

setup(
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules,
  ...
)

NOTA: Originalmente, la ubicación del archivo fortran se especificó de forma incorrecta (sin el prefijo de directorio), pero esto se interrumpe exactamente de la misma manera después de que lo solucioné.

Cosas que he probado:

encontréesta, e intenté pasar el nombre del compilador fortran (es decir, gfortran) así:

$ python setup.py config --fcompiler=gfortran build_ext --inplace
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd --help

error: option --fcompiler not recognized

Y también he intentado quitar--inplace, en caso de que ese fuera el problema (no lo era, igual que el mensaje de error superior).

Entonces, ¿cómo compilo este fortran? ¿Puedo hackearlo en un.o ¿Y me salgo con la suya? O¿Es esto un error en Cython?, ¿lo que me obligará a volver a implementar distutils o hackear con el preprocesador?

ACTUALIZAR

Por lo tanto, después de revisar lanumpy.distutils Paquetes, entiendo el problema un poco más. Parece que tienes que

Use cython para convertir los archivos .pyx en archivos .py de cpython,Luego usa unExtension/setup() combinación que soporta fortran, comonumpy's.

Habiendo probado esto, misetup.py ahora se ve así:

from numpy.distutils.core import setup
from Cython.Build import cythonize
from numpy.distutils.extension import Extension

cy_modules = cythonize('delaunay/sphere.pyx')
e = cy_modules[0]

ext_modules = [
  Extension("delaunay.sphere",
      sources=e.sources + ['delaunay/stripack.f90'])
]

setup(
  ext_modules = ext_modules,
  name="delaunay",
  ...
)

(Tenga en cuenta que también he reestructurado un poco el módulo, ya que aparentemente un__init__.pyx es rechazado ...)

Ahora es donde las cosas se vuelven buggy y dependen de la plataforma. Tengo dos sistemas de prueba disponibles: uno Mac OS X 10.6 (Snow Leopard), usando Macports Python 2.7, y uno Mac OS X 10.7 (Lion) utilizando el sistema python 2.7.

En Snow Leopard, se aplica lo siguiente:

Esto significa que el módulo se compila (¡hurra!) (Aunque no hay--inplace Parece que para el número, por lo que tuve que instalar el módulo de prueba en todo el sistema: /) pero todavía tengo un fallo enimport como sigue:

  >>> import delaunay
  Traceback (most recent call last):
    File "<input>", line 1, in <module>
    File "<snip>site-packages/delaunay/__init__.py", line 1, in <module>
      from sphere import delaunay_mesh
  ImportError: dlopen(<snip>site-packages/delaunay/sphere.so, 2): no suitable image found.  Did find:
    <snip>site-packages/delaunay/sphere.so: mach-o, but wrong architecture

y en Lion, recibo un error de compilación, siguiendo una línea de compilación de aspecto bastante confuso:

gfortran:f77: build/src.macosx-10.7-intel-2.7/delaunay/sphere-f2pywrappers.f
/usr/local/bin/gfortran -Wall -arch i686 -arch x86_64 -Wall -undefined dynamic_lookup -bundle build/temp.macosx-10.7-intel-2.7/delaunay/sphere.o build/temp.macosx-10.7-intel-2.7/build/src.macosx-10.7-intel-2.7/delaunay/spheremodule.o build/temp.macosx-10.7-intel-2.7/build/src.macosx-10.7-intel-2.7/fortranobject.o build/temp.macosx-10.7-intel-2.7/delaunay/stripack.o build/temp.macosx-10.7-intel-2.7/build/src.macosx-10.7-intel-2.7/delaunay/sphere-f2pywrappers.o -lgfortran -o build/lib.macosx-10.7-intel-2.7/delaunay/sphere.so
ld: duplicate symbol _initsphere in build/temp.macosx-10.7-intel-2.7/build/src.macosx-10.7-intel-2.7/delaunay/spheremodule.o ldand :build /temp.macosx-10.7-intelduplicate- 2.7symbol/ delaunay/sphere.o _initsphere in forbuild architecture /i386
temp.macosx-10.7-intel-2.7/build/src.macosx-10.7-intel-2.7/delaunay/spheremodule.o and build/temp.macosx-10.7-intel-2.7/delaunay/sphere.o for architecture x86_64

Ahora retrocedamos un momento antes de examinar detenidamente los detalles aquí. En primer lugar, sé que hay muchos problemas con los conflictos de arquitectura en Mac OS X de 64 bits; Tuve que trabajar mucho para que Macports Python trabajara en la máquina Snow Leopard (solo para actualizar desde el sistema Python 2.6). También sé que cuando lo veas.gfortran -arch i686 -arch x86_64 Usted está enviando mensajes mixtos a su compilador. Hay todo tipo de problemas específicos de la plataforma enterrados allí, de los que no tenemos que preocuparnos en el contexto de esta pregunta.

Pero veamos esta línea: gfortran:f77: build/src.macosx-10.7-intel-2.7/delaunay/sphere-f2pywrappers.f

¿Qué está haciendo numpy? ¡No necesito ninguna característica f2py en esta compilación! En realidad escribí un módulo de cythonpara evitar tratar con la locura de f2py (necesito tener 4 o 5 variables de salida, así como tampoco argumentos in-nor-out, ninguno de los cuales está bien soportado en f2py). Sólo quiero que se compile.c ->.oy.f90 ->.o y enlazarlos. Podría escribir esta línea del compilador si supiera cómo incluir todos los encabezados relevantes.

Por favor, dime que no necesito escribir mi propio makefile para esto ... o que hay una manera de traducir fortran a (salida compatible) C, así puedo evitar que Python vea la extensión .f90 (que corrige el conjunto). problema.) Tenga en cuenta quef2c no es adecuado para esto ya que solo funciona en F77 y este es un dialecto más moderno (de ahí el.f90 extensión de archivo).

ACTUALIZACIÓN 2 El siguiente script de bash compilará y vinculará el código en su lugar:

PYTHON_H_LOCATION="/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7/"

cython sphere.pyx

gcc -arch x86_64 -c sphere.c -I$PYTHON_H_LOCATION
gfortran -arch x86_64 -c stripack.f90
gfortran -arch x86_64 -bundle -undefined dynamic_lookup -L/opt/local/lib *.o -o sphere.so

¿Algún consejo sobre cómo hacer que este tipo de hack sea compatible con un setup.py? No tengo a nadie instalando este modulo para tener que ir a buscar.Python.h a mano...

Respuestas a la pregunta(3)

Su respuesta a la pregunta