使用 cython 创建包,这样用户就可以在没有安装 cython 的情况下安装它
Create package with cython so users can install it without having cython already installed
我有一个问题。我想分发我的 cython 驱动的包,但我看不到在 setup.py 中构建它们的简单方法。我想 setup.py 到:
- 最重要的是:在没有 cython 的情况下安装我的包(从预先生成的 C 文件或通过预先安装 cython)
- 在 sdist
上重建(运行 cythonize)包
- 不需要硬编码我的 cython 模块列表(只需使用 glob 或其他东西)
- 能够在没有 .c 文件(不应存储在 git)或 .pyx(可能不会分发)的情况下工作。当然,至少其中一套会一直存在。
目前在我痒痒的包里,我正在使用这个相当复杂的代码:
import os
from glob import glob
from distutils.command.build_ext import build_ext as _build_ext
from distutils.command.sdist import sdist as _sdist
from distutils.core import setup
from distutils.core import Extension
def generate_extensions():
return [
# Compile cython-generated .c files into importable .so libraries.
Extension(os.path.splitext(name)[0], [name])
for name in C_FILES
]
# In distribution version, there are no pyx files, when you clone package from git, there will be no c files.
CYTHON_FILES = glob('itchy/*.pyx')
C_FILES = glob('itchy/*.c')
extensions = generate_extensions()
class build_ext(_build_ext):
def run(self):
# Compile cython files (.pyx, some of the .py) into .c files if Cython is available.
try:
from Cython.Build import cythonize
if CYTHON_FILES:
cythonize(CYTHON_FILES)
# Update C_FILES in case they were originally missing.
global C_FILES, extensions
C_FILES = glob('itchy/*.c')
extensions = generate_extensions()
else:
print('No .pyx files found, building extensions skipped. Pre-built versions will be used.')
except ImportError:
print('Cython is not installed, building extensions skipped. Pre-built versions will be used.')
assert C_FILES, 'C files have to be present in distribution or Cython has to be installed'
_build_ext.run(self)
class sdist(_sdist):
def run(self):
# Make sure the compiled Cython files in the distribution are up-to-date
self.run_command("build_ext")
_sdist.run(self)
setup(
(...)
ext_modules = extensions,
cmdclass = {
'build_ext': build_ext,
'sdist': sdist,
},
)
通常通过尝试导入 cython 并将扩展调整为
- 如果存在 cython,则使用 cython 构建 pyx 文件
- 如果 cython 不存在,构建 C 文件
例如:
try:
from Cython.Distutils.extension import Extension
from Cython.Distutils import build_ext
except ImportError:
from setuptools import Extension
USING_CYTHON = False
else:
USING_CYTHON = True
ext = 'pyx' if USING_CYTHON else 'c'
sources = glob('my_module/*.%s' % (ext,))
extensions = [
Extension(source.split('.')[0].replace(os.path.sep, '.'),
sources=[source],
)
for source in sources]
cmdclass = {'build_ext': build_ext} if USING_CYTHON else {}
setup(<..>, ext_modules=extensions, cmdclass=cmdclass)
需要 source.split
东西,因为 cythonized 扩展名需要采用 my_module.ext
形式,而 glob 需要像 my_module/ext
.
这样的路径名
See this repository 一个真实世界的例子。
但是,您应该在 git 存储库和可分发文件中包含 .c
文件,否则当需要构建分发时,.c
文件将被重新构建的文件可能与在您的计算机上构建的文件相同,也可能不同。
例如,它们可能由另一个版本的 cython 构建,或者在不同的平台上生成不同的代码。
Cython 是一个静态编译器 - 建议将其生成的文件提交到存储库。
It is strongly recommended that you distribute the generated .c files as well as your Cython sources, so that users can install your module without needing to have Cython available.
我有一个问题。我想分发我的 cython 驱动的包,但我看不到在 setup.py 中构建它们的简单方法。我想 setup.py 到:
- 最重要的是:在没有 cython 的情况下安装我的包(从预先生成的 C 文件或通过预先安装 cython)
- 在 sdist 上重建(运行 cythonize)包
- 不需要硬编码我的 cython 模块列表(只需使用 glob 或其他东西)
- 能够在没有 .c 文件(不应存储在 git)或 .pyx(可能不会分发)的情况下工作。当然,至少其中一套会一直存在。
目前在我痒痒的包里,我正在使用这个相当复杂的代码:
import os
from glob import glob
from distutils.command.build_ext import build_ext as _build_ext
from distutils.command.sdist import sdist as _sdist
from distutils.core import setup
from distutils.core import Extension
def generate_extensions():
return [
# Compile cython-generated .c files into importable .so libraries.
Extension(os.path.splitext(name)[0], [name])
for name in C_FILES
]
# In distribution version, there are no pyx files, when you clone package from git, there will be no c files.
CYTHON_FILES = glob('itchy/*.pyx')
C_FILES = glob('itchy/*.c')
extensions = generate_extensions()
class build_ext(_build_ext):
def run(self):
# Compile cython files (.pyx, some of the .py) into .c files if Cython is available.
try:
from Cython.Build import cythonize
if CYTHON_FILES:
cythonize(CYTHON_FILES)
# Update C_FILES in case they were originally missing.
global C_FILES, extensions
C_FILES = glob('itchy/*.c')
extensions = generate_extensions()
else:
print('No .pyx files found, building extensions skipped. Pre-built versions will be used.')
except ImportError:
print('Cython is not installed, building extensions skipped. Pre-built versions will be used.')
assert C_FILES, 'C files have to be present in distribution or Cython has to be installed'
_build_ext.run(self)
class sdist(_sdist):
def run(self):
# Make sure the compiled Cython files in the distribution are up-to-date
self.run_command("build_ext")
_sdist.run(self)
setup(
(...)
ext_modules = extensions,
cmdclass = {
'build_ext': build_ext,
'sdist': sdist,
},
)
通常通过尝试导入 cython 并将扩展调整为
- 如果存在 cython,则使用 cython 构建 pyx 文件
- 如果 cython 不存在,构建 C 文件
例如:
try:
from Cython.Distutils.extension import Extension
from Cython.Distutils import build_ext
except ImportError:
from setuptools import Extension
USING_CYTHON = False
else:
USING_CYTHON = True
ext = 'pyx' if USING_CYTHON else 'c'
sources = glob('my_module/*.%s' % (ext,))
extensions = [
Extension(source.split('.')[0].replace(os.path.sep, '.'),
sources=[source],
)
for source in sources]
cmdclass = {'build_ext': build_ext} if USING_CYTHON else {}
setup(<..>, ext_modules=extensions, cmdclass=cmdclass)
需要 source.split
东西,因为 cythonized 扩展名需要采用 my_module.ext
形式,而 glob 需要像 my_module/ext
.
See this repository 一个真实世界的例子。
但是,您应该在 git 存储库和可分发文件中包含 .c
文件,否则当需要构建分发时,.c
文件将被重新构建的文件可能与在您的计算机上构建的文件相同,也可能不同。
例如,它们可能由另一个版本的 cython 构建,或者在不同的平台上生成不同的代码。
Cython 是一个静态编译器 - 建议将其生成的文件提交到存储库。
It is strongly recommended that you distribute the generated .c files as well as your Cython sources, so that users can install your module without needing to have Cython available.