2017-01-21 5 views
2

私はPythonモジュールをPythonで完全に実装しています。 (移植性の理由から)オプションのcython拡張モジュールをsetup.pyでできるだけコンパイルする

小さな部分の実装は、cythonモジュールに複製されています。可能な限り性能を改善する。

私は.cモジュールをインストールする方法を知っています。distutilsでcythonで作成しました。しかし、マシンにコンパイラがインストールされていない場合、純粋なpythonモードでモジュールが使用可能であっても、セットアップに失敗すると思われます。

可能であれば.cモジュールをコンパイルする方法はありますか?正常に失敗し、コンパイルできない場合はインストールしないでインストールしますか?

答えて

0

How should I structure a Python package that contains Cython code

が関連している質問は、質問は「すでに生成されたCコード」にCythonからフォールバックする方法があります。同様の戦略を使用して、.pyまたは.pyxのいずれかのコードをインストールするかを選択できます。

+0

これはどのように適用されるのかわかりません。彼らはPythonモジュールとしてcythonをインポートしようとし、インポートが失敗した場合はCモジュールにフォールバックします。私はどのように私はPythonでシステムのCコンパイラをインポートしようとするとお勧めしますか? – ARF

+0

実際、少し早期に結論に飛びついた。 –

2

あなたのモジュールのsetup.py__init__ファイルの両方で何らかの変更を加えなければならないと思います。

レッツは、あなたのパッケージの名前は、「モジュール」になりますと言うと、あなたがsubサブフォルダ内の純粋なPythonのコードとc_subサブフォルダに同等の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にビルドの場合はバージョンが使用され、それ以外の場合はプレーンなPythonのバージョンが使用されます。 subc_subが同じAPIを提供すると仮定します。

このようにしてexample of setup fileShapelyパッケージにあります。実際に私が投稿したコードのほとんどは、このファイルからコピーされたものです(construct_build_ext関数)。

関連する問題