Cython e fortran - como compilar juntos sem f2py

ATUALIZAÇÃO FINAL

Esta questão é sobre como escrever umsetup.py que irá compilar um módulo cython que acesse diretamente o código FORTRAN, como C faria. Foi uma jornada bastante longa e árdua para a solução, mas a confusão completa está incluída abaixo para o contexto.

PERGUNTA ORIGINAL

Eu tenho uma extensão que é um arquivo Cython, que configura alguma memória heap e passa para o código fortran, e um arquivo fortran, que é um antigo módulo respeitável que eu gostaria de evitar a reimplementação se eu puder.

o.pyx arquivo compila bem para C, mas o compilador cython engasga com o.f90 arquivo com o seguinte erro:

$ 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')

Aqui está a metade superior do meu arquivo de configuração:

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,
  ...
)

Observação: originalmente eu tinha o local do arquivo fortran especificado incorretamente (sem o prefixo de diretório), mas isso quebra exatamente da mesma maneira depois que eu corrigi isso.

Coisas que eu tentei:

eu encontreiisto, e tentei passar o nome do compilador fortran (ou seja, gfortran) assim:

$ 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 eu também tentei remover--inplace, no caso em que foi o problema (não foi, mesmo que a mensagem de erro superior).

Então, como faço para compilar este fortran? Posso cortar em um.o eu mesmo e sair ligando isso? Ouisso é um bug no Cython, o que me forçará a reimplementar distúrbios ou invadir o pré-processador?

ATUALIZAR

Então, depois de ter verificado onumpy.distutils pacotes, eu entendo o problema um pouco mais. Parece que você tem que

Use o cython para converter os arquivos .pyx em arquivos cpython .cEntão use umExtension/setup() combinação que suporta fortran, comonumpyé.

Tendo tentado isso, meusetup.py agora se parece com isso:

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",
  ...
)

(note que eu também reestruturei o módulo um pouco, já que aparentemente__init__.pyx não é permitido ...)

Agora é onde as coisas ficam com bugs e dependem da plataforma. Eu tenho dois sistemas de teste disponíveis - um Mac OS X 10.6 (Snow Leopard), usando o Macports Python 2.7, e um Mac OS X 10.7 (Lion) usando o sistema python 2.7.

No Snow Leopard, o seguinte se aplica:

Isto significa que o módulo compila (hurra!) (Embora não haja--inplace para numpy, parece, então eu tive que instalar o módulo de teste em todo o sistema: /) mas eu ainda recebo um acidenteimport do seguinte modo:

  >>> 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 no Lion, recebo um erro de compilação, seguindo uma linha de compilação aparentemente 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

Agora vamos apenas recuar um pouco antes de nos debruçarmos sobre os detalhes aqui. Em primeiro lugar, eu sei que há um monte de dores de cabeça sobre conflitos de arquitetura no Mac OS X de 64 bits; Eu tive que trabalhar muito duro para fazer o Macports Python trabalhar na máquina do Snow Leopard (apenas para atualizar do sistema python 2.6). Eu também sei que quando você vêgfortran -arch i686 -arch x86_64 você está enviando mensagens mistas para o seu compilador. Existem todos os tipos de problemas específicos da plataforma enterrados lá, com os quais não precisamos nos preocupar no contexto dessa questão.

Mas vamos apenas olhar para essa linha: gfortran:f77: build/src.macosx-10.7-intel-2.7/delaunay/sphere-f2pywrappers.f

o que está fazendo numpy ?! Eu não preciso de nenhum recurso f2py nesta build! Eu realmente escrevi um módulo cythona fim de evitar lidando com a insanidade de f2py (eu preciso ter 4 ou 5 variáveis ​​de saída, assim como argumentos nem dentro nem fora - nenhum dos quais é bem suportado em f2py.) Eu só quero compilar.c ->.oe.f90 ->.o e ligá-los. Eu poderia escrever essa linha de compilador se soubesse como incluir todos os cabeçalhos relevantes.

Por favor, diga-me que não preciso escrever meu próprio makefile para isso ... ou que há uma maneira de traduzir o fortran para (compatível com saída) C para que eu possa evitar que o python veja a extensão .f90 (que corrige o todo problema.) Observe quef2c não é adequado para isso, pois só funciona em F77 e este é um dialeto mais moderno (daí o.f90 extensão de arquivo).

ATUALIZAÇÃO 2 O seguinte script bash será feliz compilar e vincular o código no 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

Algum conselho sobre como fazer este tipo de hack compatível com um setup.py? Eu não faço ninguém instalar este módulo para ter que ir encontrarPython.h manualmente ...

questionAnswers(3)

yourAnswerToTheQuestion