当前位置:  开发笔记 > 编程语言 > 正文

仅在setup.py中可能时编译可选的cython扩展

如何解决《仅在setup.py中可能时编译可选的cython扩展》经验,为你挑选了1个好方法。

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

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

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

有没有办法编译该.c模块(如果可能的话),但无法正常运行,如果无法编译,则在没有该模块的情况下进行安装?



1> mgc..:

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

假设包的名称为“ module”,并且您具有一个功能,sub为此,您在sub子文件夹中具有纯python代码,在子文件夹中具有等效的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)

class BuildFailed(Exception):
    pass

def construct_build_ext(build_ext):
    class WrappedBuildExt(build_ext):
        # This class allows C extension building to fail.
        def run(self):
            try:
                build_ext.run(self)
            except DistutilsPlatformError as x:
                raise BuildFailed(x)

        def build_extension(self, ext):
            try:
                build_ext.build_extension(self, ext)
            except ext_errors as x:
                raise BuildFailed(x)
    return WrappedBuildExt

setup_args = {'name': 'module', 'license': 'BSD', 'author': 'xxx',
    'packages': ['module', 'module.sub', 'module.c_sub'],
    'cmdclass': {}
    }

ext_modules = [Extension("module.c_sub._sub", ["module/c_sub/_sub.c"])]
cmd_classes = setup_args.setdefault('cmdclass', {})

try:
    # try building with c code :
    setup_args['cmdclass']['build_ext'] = construct_build_ext(build_ext)
    setup(ext_modules=ext_modules, **setup_args)
except BuildFailed 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 'build_ext' in cmd_classes:
        del cmd_classes['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版本,则将使用C版本,否则将使用普通的python版本。它假定sub并且c_sub将提供相同的API。

您可以在软件包中找到执行此操作的安装文件示例Shapely。实际上,我发布的大多数代码都是construct_build_ext从此文件复制(函数)或改编(后一行)的。

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有