10

我有一个在 python 中完全实现的 python 模块。(出于便携性原因。)

一小部分的实现已在 cython 模块中复制。尽可能提高性能。

我知道如何.c使用distutils. 但是,如果机器没有安装编译器,我怀疑即使模块在纯 python 模式下仍然可用,安装也会失败。

如果可能的话,有没有办法编译.c模块,但如果无法编译,可以优雅地失败并在没有它的情况下安装?

4

3 回答 3

8

我想您将不得不在您的模块setup.py和模块中的一个__init__文件中进行一些修改。

假设您的包的名称将是“模块”,并且您有一个功能,sub您在子文件夹中有纯 Python 代码,在sub子文件夹中有等效的 C 代码c_sub。例如在你的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从该文件中复制(函数)或改编(之后的行)。

于 2017-01-21T23:42:17.527 回答
3

类在构造函数中Extension有参数 optional

可选- 指定扩展中的构建失败不应中止构建过程,而只是跳过扩展。

这里也是mgc提出的一段非常有趣的代码历史的链接

于 2019-12-07T01:14:50.730 回答
1

问题我应该如何构建包含 Cython 代码的 Python 包

是相关的,问题是如何从 Cython 回退到“已经生成的 C 代码”。您可以使用类似的策略来选择要安装.py的代码。.pyx

于 2017-01-21T11:57:23.907 回答