2017-01-21 22 views
2

我有一個Python模塊python中全面實施。 (對於便攜性的原因。)編譯一個可選的擴展用Cython只有可能在setup.py

一小部分的實施已被複制一個用Cython模塊中。儘可能提高性能。

我知道如何安裝由distutils和cython創建的.c模塊。但是,如果一臺機器沒有安裝編譯器,那麼即使該模塊仍然可以在純Python模式下使用,我仍然懷疑安裝失敗。

有沒有一種方法,如果可能的編譯.c模塊,但無法正常安裝,沒有它,如果編譯是不可能的?

回答

0

問題How should I structure a Python package that contains Cython code

是相關的,有問題是如何從用Cython退回到「已生成的C代碼」。你可以使用類似的策略選擇哪個.py.pyx代碼的安裝。

+0

我不明白這是怎麼適用。他們嘗試將cython作爲python模塊導入,如果導入失敗,則回退到C模塊。你如何建議我嘗試在Python中導入系統C編譯器? – ARF

+0

事實上,我早晚得出結論。 –

2

我想你將不得不在你的模塊中的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) 

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版本將被使用,如果它是構建,否則使用普通的Python版本。它假定subc_sub將提供相同的API。

你可以找到一個example of setup file做這樣的Shapely包。實際上,我發佈的大多數代碼都是從該文件中複製的(construct_build_ext函數)或修改後的代碼。

相關問題