【发布时间】:2012-10-02 18:59:00
【问题描述】:
最终更新
这个问题是关于如何编写一个setup.py 来编译一个直接访问 FORTRAN 代码的 cython 模块,就像 C 语言一样。找到解决方案的过程相当漫长而艰巨,但下面列出了完整的混乱情况。
原始问题
我有一个扩展,它是一个 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 文件,
- 然后使用支持fortran的
Extension/setup()组合,如numpy的。
尝试了这个,我的setup.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 的 Mac OS X 10.7 (Lion)。
在雪豹上,以下适用:
这意味着模块编译(万岁!)(虽然似乎没有 --inplace 用于 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 位 Mac OS X 中的架构冲突令人头疼;我必须非常努力地让 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
numpy 在做什么?!我在这个版本中不需要任何 f2py 功能!我实际上编写了一个 cython 模块为了避免处理 f2py 的精神错乱(我需要有 4 或 5 个输出变量,以及既不进也不出的参数 - 两者都没有得到很好的支持在 f2py 中。)我只希望它编译 .c -> .o 和 .f90 -> .o 并链接它们。如果我知道如何包含所有相关的头文件,我可以自己编写这个编译器行。
请告诉我,我不需要为此编写自己的 makefile...解决了整个问题。)请注意,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
关于如何使这种 hack 与 setup.py 兼容的任何建议?我没有人安装这个模块必须手动找到Python.h...
【问题讨论】:
-
Fortran 支持似乎来自
numpy。也许您可以导入numpy.distutils.extension.Extension而不是distutils.core.Extension。 -
您是否安装了 gfortran?你真的需要一些 Fortran 编译器,真的很有必要。
-
@Vladimir F - gfortran 肯定已安装。
-
@MvG - 谢谢,我现在正在调查。
标签: python c fortran cython distutils