aggiornamento finaleCython e Fortran - come compilare insieme senza f2py
Questa domanda è su come scrivere un setup.py
che compilerà un modulo Cython che accede codice FORTRAN direttamente, come il C avrebbe fatto. È stato un viaggio piuttosto lungo e arduo verso la soluzione, ma il disordine completo è incluso di seguito per il contesto.
domanda iniziale
Ho un prolungamento che è un file Cython, che imposta un po 'di memoria heap e lo passa al codice Fortran, e un file FORTRAN, che è un vecchio modulo veneranda che ho' Mi piacerebbe evitare di reimplementare se posso.
Il file .pyx
compila bene a C, ma il compilatore Cython soffoca sul file .f90
con il seguente errore:
$ 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')
Ecco (la metà superiore della) mia file di installazione:
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: originariamente la posizione del file di Fortran è stata specificata in modo errato (senza il prefisso della directory) ma ciò si interrompe esattamente nello stesso modo dopo averlo corretto.
Le cose che ho provato:
ho trovato this, e ha cercato passando il nome del compilatore fortran (cioè gfortran) come questo:
$ 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
E ho anche provato rimuovere --inplace
, nel caso in cui quello era il problema (non lo era, come il messaggio di errore in alto).
Quindi, come si compila questo fortran? Posso hackerarlo in un .o
e farla franca collegandola? O is this a bug in Cython, che mi obbligherà a reimplementare le distutils o hackerare con il preprocessore?
UPDATE
Così, dopo aver verificato i numpy.distutils
pacchetti, capisco il problema un po 'più. Sembra che si deve
- Usa Cython per convertire i file .pyx per CPython file .c,
- quindi utilizzare un combinazione
Extension
/setup()
che supporta FORTRAN, comenumpy
's.
Dopo aver provato questo, il mio setup.py
ora assomiglia a questo:
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",
...
)
(notare che ho anche ristrutturato il modulo un po ', dal momento che apparentemente un __init__.pyx
è annullato ...)
Ora è dove le cose diventano bacate e dipendenti dalla piattaforma. Ho due sistemi di test disponibili: un Mac OS X 10.6 (Snow Leopard), usando Macports Python 2.7 e un Mac OS X 10.7 (Lion) usando il sistema python 2.7.
su Snow Leopard, vale quanto segue:
Ciò significa che la compilazione del modulo (evviva!) (Anche se non c'è --inplace
per NumPy, sembra, così ho dovuto livello di sistema installare il modulo di prova: /) ma ancora ottengo un incidente sul import
come segue:
>>> 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
e su Lion, ottengo un errore di compilazione, seguendo una linea di compilazione cercando piuttosto confusa:
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
Ora facciamo un passo indietro prima di esaminare i dettagli qui. In primo luogo, so che ci sono un sacco di grattacapi sulle architetture in Mac OS X a 64 bit; Ho dovuto lavorare molto duramente per far funzionare Macports Python sulla macchina Snow Leopard (solo per l'aggiornamento da system python 2.6). So anche che quando vedi gfortran -arch i686 -arch x86_64
stai inviando messaggi misti al tuo compilatore. Ci sono tutti i tipi di problemi specifici della piattaforma sepolti lì, che non dobbiamo preoccuparci nel contesto di questa domanda.
Ma facciamo solo un'occhiata a questa linea: gfortran:f77: build/src.macosx-10.7-intel-2.7/delaunay/sphere-f2pywrappers.f
Qual è numpy facendo ?! Non ho bisogno di funzioni f2py in questa build! In realtà ho scritto un modulo cython per evitare che affronta la follia di f2py (ho bisogno di avere 4 o 5 variabili di output, oltre ad argomenti senza-in-e-out - nessuno dei quali è ben supportato in f2py.) I voglio solo compilare .c
->.o
e .f90
->.o
e collegarli. Potrei scrivere questa riga del compilatore da solo se sapessi come includere tutte le intestazioni pertinenti.
Per favore dimmi che non ho bisogno di scrivere il mio makefile per questo ... o che c'è un modo per tradurre fortran in (output compatibile) C così posso solo evitare che python veda l'estensione .f90 (che risolve l'intero problema). Nota che f2c
non è adatto per questo, poiché funziona solo su F77 e questo è un dialetto più moderno (da cui l'estensione del file .f90
).
UPDATE 2 Il seguente script bash sarà lieto di compilare e collegare il codice a posto:
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
Qualche consiglio su come fare questo tipo di hack compatibile con una setup.py? Non tutti l'installazione di questo modulo per andare trovare Python.h
manualmente ...
Il supporto Fortran sembra venire da 'numpy'. Forse puoi importare ['numpy.distutils.extension.Extension'] (http://www.scipy.org/doc/numpy_api_docs/numpy.distutils.extension.html) invece di' distutils.core.Extension'. – MvG
Leggere anche la [Guida per gli utenti di NumPy Distutils] (https://github.com/numpy/numpy/blob/master/doc/DISTUTILS.rst.txt) e il [riferimento alla confezione] (http: //docs.scipy. org/doc/NumPy-1.6.0/riferimento/distutils.html). – MvG
Avete installato gfortran? Hai veramente bisogno di un compilatore Fortran, è davvero necessario. –