我有一個Python模塊python中全面實施。 (對於便攜性的原因。)編譯一個可選的擴展用Cython只有可能在setup.py
一小部分的實施已被複制一個用Cython模塊中。儘可能提高性能。
我知道如何安裝由distutils
和cython創建的.c
模塊。但是,如果一臺機器沒有安裝編譯器,那麼即使該模塊仍然可以在純Python模式下使用,我仍然懷疑安裝失敗。
有沒有一種方法,如果可能的編譯.c
模塊,但無法正常安裝,沒有它,如果編譯是不可能的?
我有一個Python模塊python中全面實施。 (對於便攜性的原因。)編譯一個可選的擴展用Cython只有可能在setup.py
一小部分的實施已被複制一個用Cython模塊中。儘可能提高性能。
我知道如何安裝由distutils
和cython創建的.c
模塊。但是,如果一臺機器沒有安裝編譯器,那麼即使該模塊仍然可以在純Python模式下使用,我仍然懷疑安裝失敗。
有沒有一種方法,如果可能的編譯.c
模塊,但無法正常安裝,沒有它,如果編譯是不可能的?
問題How should I structure a Python package that contains Cython code
是相關的,有問題是如何從用Cython退回到「已生成的C代碼」。你可以使用類似的策略選擇哪個.py
或.pyx
代碼的安裝。
我想你將不得不在你的模塊中的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版本。它假定sub
和c_sub
將提供相同的API。
你可以找到一個example of setup file做這樣的Shapely
包。實際上,我發佈的大多數代碼都是從該文件中複製的(construct_build_ext
函數)或修改後的代碼。
我不明白這是怎麼適用。他們嘗試將cython作爲python模塊導入,如果導入失敗,則回退到C模塊。你如何建議我嘗試在Python中導入系統C編譯器? – ARF
事實上,我早晚得出結論。 –