最终更新
这个问题是关于如何写
setup.py
它将编译一个像C一样直接访问FORTRAN代码的cython模块。这是一个相当漫长和艰巨的解决之旅,但以下是完整的混乱情况。
原始问题
我有一个扩展名,它是Cython文件,它设置一些堆内存并将其传递给fortran代码,还有一个fortran文件,它是一个古老的模块,如果可以的话,我希望避免重新实现。
这个
.pyx
文件可以很好地编译到C,但cython编译器阻塞了
.f90
文件,错误如下:
$ 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')
这是我的安装文件(的上半部分):
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,
...
)
注意:我最初错误地指定了fortran文件的位置(没有目录前缀),但在修复后,它以完全相同的方式中断。
我尝试过的事情:
我发现
this
,并尝试像这样传入fortran编译器(即gfortran)的名称:
$ 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
我也试着把
--inplace
,以防出现问题(事实并非如此,与顶部错误消息相同)。
那么,我该如何编译这个fortran呢?我能把它破解成
.o
我自己,并逃脱链接?或
is this a bug in Cython
,这将迫使我重新实现distutils或破解预处理器?
更新
所以,在检查了
numpy.distutils
包裹,我对这个问题有了更多的了解。看来你必须
-
使用cython将.pyx文件转换为cpython.c文件,
-
然后使用
Extension
/
setup()
支持fortran的组合,如
numpy
的。
试过之后,我的
设置.py
现在看起来是这样的:
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",
...
)
(注意,我也对模块进行了一些重组,因为看起来
__init__.pyx
不允许…)
现在是事情变得有缺陷和依赖平台的地方。我有两个可用的测试系统——一个是使用Macports Python 2.7的Mac OS X 10.6(Snow Leopard),另一个使用系统Python 2.7的MacOS X 10.7(Lion)。
对于雪豹,以下内容适用:
这意味着模块会编译(万岁!)(尽管没有
--就地
对于numpy来说,似乎是这样,所以我不得不在系统范围内安装测试模块:/),但我仍然会崩溃
import
如下所示:
>>> 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
在Lion上,我得到了一个编译错误,遵循了一个看起来相当混乱的编译行:
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
现在,在我们仔细研究这里的细节之前,让我们退后一步。首先,我知道在64位MacOSX中有很多关于架构冲突的头疼问题;我不得不非常努力地让Macports Python在Snow Leopard机器上工作(只是从系统Python 2.6升级)
gfortran -arch i686 -arch x86_64
您正在向编译器发送混合消息。在这个问题的背景下,我们不需要担心各种特定于平台的问题。
但让我们看看这条线
以下为:
gfortran:f77: build/src.macosx-10.7-intel-2.7/delaunay/sphere-f2pywrappers.f
努皮在干什么?!
在这个版本中我不需要任何f2py功能!我实际上写了一个cython模块
为了避免
处理f2py的疯狂(我需要有4或5个输出变量,以及既不输入也不输出的参数——这两个参数在f2py中都没有得到很好的支持。)我只想让它编译
.c
->
.o
和
.f90
->
.o
并将它们链接起来。如果我知道如何包含所有相关的头,我可以自己编写这行编译器。
请告诉我,我不需要为此编写自己的makefile。。。或者有一种方法可以将fortran转换为(输出兼容的)C,这样我就可以避免python看到.f90扩展(它解决了整个问题)
f2c
不适合这样做,因为它只适用于F77,而且这是一种更现代的方言(因此
.f90
文件扩展名)。
更新2
下面的bash脚本将很好地编译并链接代码:
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
关于如何使这种破解与setup.py兼容,有什么建议吗?我没有人安装这个模块就必须去找
Python.h
手动。。。