依赖cython和f2py的packages的setup.py
我想为一个包含多个子模块的Python包创建一个setup.py脚本,这些子模块依赖于cython和f2py。我尝试过使用setuptools和numpy.distutils,但到目前为止都没有成功:
使用setuptools
我可以用setuptools编译我的cython扩展(并为包的其他部分创建安装包)。但是,我一直搞不清楚如何用setuptools生成f2py扩展。经过大量搜索,我只找到了一些比较旧的信息,说f2py模块必须使用numpy.distutils来编译。
使用numpy.distutils
我可以用numpy.distutils编译我的f2py扩展(并为包的其他部分创建安装包)。不过,我一直无法让numpy.distutils编译我的cython扩展,因为它总是试图用pyrex来编译(而我使用的是专门针对cython的扩展)。我搜索了一下,发现至少在一年前,他们建议对numpy.distutils应用一个猴子补丁。看起来应用这样的猴子补丁还会限制可以传递给Cython的选项。
我的问题是:对于依赖于f2py和cython的包,编写setup.py脚本的推荐方法是什么?对numpy.distutils应用补丁真的还是最佳选择吗?
2 个回答
其实这个说法现在已经不成立了。现在使用 setuptools
和 distutils
(至少是 numpy
的版本)时,可以使用 C、Cython 和 f2py 来创建扩展模块。唯一需要注意的是,编译 f2py 模块时,必须始终使用 numpy.distutils
来处理 setup
和 Extension
函数。不过,安装时仍然可以使用 setuptools
(比如,可以通过 python setup.py develop
来安装开发版本)。
如果你想完全使用 distutils
,可以这样做:
from numpy.distutils.core import setup
from numpy.distutils.extension import Extension
如果要使用 setuptools
,需要在导入 distutils
之前先导入它:
import setuptools
然后后面的代码就和之前的一样:
from numpy import get_include
from Cython.Build import cythonize
NAME = 'my_package'
NUMPY_INC = get_include()
extensions = [
Extension(name=NAME + ".my_cython_ext",
include_dirs=[NUMPY_INC, "my_c_dir"]
sources=["my_cython_ext.pyx", "my_c_dir/my_ext_c_file.c"]),
Extension(name=NAME + ".my_f2py_ext",
sources=["my_f2py_ext.f"]),
]
extensions = cythonize(extensions)
setup(..., ext_modules=extensions)
显然,你需要把其他所有的内容放在 setup()
调用里面。在上面的例子中,我假设你会用 Cython 和 numpy,并且有一个外部的 C 文件(my_ext_c_file.c
),这个文件会放在 my_c_dir/
目录下,同时 f2py
模块只有一个 Fortran 文件。根据需要进行调整。
你可以在你的 setup.py 文件中分别调用每个内容,就像在这个链接中提到的那样:
http://answerpot.com/showthread.php?601643-cython%20and%20f2py
# Cython extension
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
ext_modules = [Extension( 'cext', ['cext.pyx'] )],
cmdclass = {'build_ext': build_ext},
script_args = ['build_ext', '--inplace'],
)
# Fortran extension
from numpy.distutils.core import setup, Extension
setup(
ext_modules = [Extension( 'fext', ['fext.f90'] )],
)
你调用的上下文(我觉得他们叫这个命名空间,不太确定)
需要根据当前的对象 Extension 和函数 setup() 来进行调整。
第一次调用 setup() 时,使用的是 distutils.extension.Extension
和 distutils.core.setup()。
第二次调用 setup() 时,使用的是 numpy.distutils.core.Extension
和 numpy.distutils.core.setup()。