[英]Compiling an optional cython extension only when possible in setup.py
我有一个在 python 中完全实现的 python 模块。 (出于便携性原因。)
一小部分的实现已复制到一个 cython 模块中。 在可能的情况下提高绩效。
我知道如何使用distutils
安装由 cython 创建的.c
模块。 但是,如果机器没有安装编译器,我怀疑即使模块在纯 python 模式下仍然可用,安装也会失败。
如果可能,有没有办法编译.c
模块,但如果无法编译,则优雅地失败并在没有它的情况下安装?
我想您必须在setup.py
和模块中的一个__init__
文件中进行一些修改。
假设您的包的名称将是“模块”,并且您有一个功能sub
,您在sub
文件夹中有纯 python 代码,在c_sub
子文件夹中有等效的 C 代码。 例如在您的setup.py
:
import logging
from setuptools.extension import Extension
from setuptools.command.build_ext import build_ext
from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError
logging.basicConfig()
log = logging.getLogger(__file__)
ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOError, SystemExit)
setup_args = {'name': 'module', 'license': 'BSD', 'author': 'xxx',
'packages': ['module', 'module.sub', 'module.c_sub'],
'cmdclass': {'build_ext': build_ext}
}
ext_modules = [Extension("module.c_sub._sub", ["module/c_sub/_sub.c"])]
try:
# try building with c code :
setup(ext_modules=ext_modules, **setup_args)
except ext_errors as ex:
log.warn(ex)
log.warn("The C extension could not be compiled")
## Retry to install the module without C extensions :
# Remove any previously defined build_ext command class.
if 'build_ext' in setup_args['cmdclass']:
del setup_args['cmdclass']['build_ext']
# If this new 'setup' call don't fail, the module
# will be successfully installed, without the C extension :
setup(**setup_args)
log.info("Plain-Python installation succeeded.")
现在你需要在你的__init__.py
文件中(或在任何与你的情况相关的地方)包含这样的内容:
try:
from .c_sub import *
except ImportError:
from .sub import *
通过这种方式,如果构建,将使用 C 版本,否则使用纯 python 版本。 它假定sub
和c_sub
将提供相同的 API。
您可以在Shapely
包中找到以这种方式执行此操作的安装文件示例。 实际上,我发布的大部分代码都是从这个文件中复制( construct_build_ext
函数)或改编的(行后)。
问题我应该如何构建包含 Cython 代码的 Python 包
是相关的,问题是如何从 Cython 回退到“已经生成的 C 代码”。 您可以使用类似的策略来选择要安装的.py
或.pyx
代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.