python – 使用cython创建包,这样用户可以安装它而无需安装cython

我有个问题.我想分发我的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.

See Cython documentation on distributing modules.

转载注明原文:python – 使用cython创建包,这样用户可以安装它而无需安装cython - 代码日志