INFORME FINAL DE ACTUALIZACIÓNCython y Fortran - cómo compilar juntos sin f2py
Esta pregunta es acerca de cómo escribir un setup.py
que compilar un módulo Cython que accede directamente el código FORTRAN, al igual que lo haría C. Fue un viaje bastante largo y arduo a la solución, pero el desastre completo se incluye a continuación para el contexto.
pregunta original
Tengo una extensión que es un archivo Cython, que fija un poco de memoria del montón y lo pasa al código Fortran, y un archivo de Fortran, que es un módulo venerable viejo que yo Me gustaría evitar volver a implementar si puedo.
El archivo .pyx
compila bien a C, pero el compilador Cython ahoga en el archivo .f90
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')
He aquí (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 tuve la ubicación del archivo fortran incorrectamente especificada (sin el prefijo de directorio) pero esto se rompe exactamente de la misma manera después de que lo arreglé.
cosas que he intentado:
me encontré this, y trató de pasar en 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 eliminando --inplace
, en caso de que ese fuera el problema (no era lo mismo que el mensaje de error superior).
Entonces, ¿cómo compilo este fortran? ¿Puedo hackearlo en un .o
y salí con la vinculación? O is this a bug in Cython, lo que me obligará a volver a implementar distutils o hackear con el preprocesador?
ACTUALIZACIÓN
Así que, habiendo leído los numpy.distutils
paquetes, entiendo el problema un poco más. Parece que usted tiene que
- Uso Cython para convertir los archivos a .pyx CPython .c archivos,
- A continuación, utilice una combinación
Extension
/setup()
que soporta Fortran, comonumpy
's.
Habiendo probado esto, mi setup.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 el módulo un poco, ya que al parecer un __init__.pyx
no está permitido ...)
Ahora es cuando las cosas se vuelven defectuosas y dependen de la plataforma. Tengo dos sistemas de prueba disponibles: un Mac OS X 10.6 (Snow Leopard), usando Macports Python 2.7, y un Mac OS X 10.7 (Lion) usando el sistema python 2.7.
En Snow Leopard, se aplica lo siguiente:
Esto significa que las compilaciones de módulos (hurra!) (Aunque no hay --inplace
para numpy, parece, así que tuve que todo el sistema de instalar el módulo de prueba: /), pero sigo teniendo un accidente en import
de la siguiente manera:
>>> 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 León, me sale un error de compilación, siguiendo una línea de compilación en lugar confuso buscando:
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 estudiar detenidamente los detalles aquí. En primer lugar, sé que hay muchos dolores de cabeza por los choques de arquitectura en Mac OS X de 64 bits; Tuve que trabajar mucho para conseguir que Macports Python trabaje en la máquina Snow Leopard (solo para actualizar desde el sistema Python 2.6). También sé que cuando veas gfortran -arch i686 -arch x86_64
estarás enviando mensajes mezclados a tu 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 vamos a ver en 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 versión! De hecho, escribí un módulo cython para evitar que trata con la locura de f2py (necesito tener 4 o 5 variables de salida, así como argumentos none-in-or-out, ninguno de los cuales es bien soportado en f2py). solo quiere que compile .c
->.o
, y .f90
->.o
y vincule. Podría escribir esta línea de compilación si supiera cómo incluir todos los encabezados relevantes.
Por favor, dime que no necesito escribir mi propio archivo MAKE para esto ... o que hay una forma de traducir Fortran a C (compatible con la salida), así que puedo evitar que python vea la extensión .f90 (que corrige todo el problema.) Tenga en cuenta que f2c
no es adecuado para esto, ya que solo funciona en F77 y este es un dialecto más moderno (de ahí la extensión de archivo .f90
).
ACTUALIZACIÓN 2 La siguiente secuencia de comandos bash felizmente compilar y enlazar el código en su sitio:
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 este tipo de corte compatible con una setup.py? Ni cualquier instalación de este módulo a tener que ir a buscar manualmente Python.h
...
El soporte de Fortran parece provenir de 'numpy'. Tal vez pueda importar ['numpy.distutils.extension.Extension'] (http://www.scipy.org/doc/numpy_api_docs/numpy.distutils.extension.html) en lugar de' distutils.core.Extension'. – MvG
Lea también la [Guía del usuario de NumPy Distutils] (https://github.com/numpy/numpy/blob/master/doc/DISTUTILS.rst.txt) y la [referencia del paquete] (http: //docs.scipy. org/doc/numpy-1.6.0/reference/distutils.html). – MvG
¿Tiene instalado gfortran en absoluto? Realmente necesitas un compilador Fortran, es realmente necesario. –