【问题标题】:Package a pre-built python extension打包一个预构建的 python 扩展
【发布时间】:2019-01-06 21:12:19
【问题描述】:

我正在开发一个 C 库(使用 cmake 作为构建系统)和一个用 cython 编写的相应 python 扩展。

构建过程由 cmake 进行,它调用 cython 可执行文件生成 C 文件。该文件被编译成一个 python_library.so 链接 针对原生 library.so 和其他依赖项。

该库按预期工作,我可以将PYTHONPATH 设置为构建目录,运行python 和import 并执行包装的python 代码。

剩下的问题是如何安装/打包 python 模块。 据我所知,创建python包的推荐方法是在setup.py文件中使用setuptools / distutils。

当然可以在setup.py 文件中定义一个C Extension(可选地使用cython)。但是,我希望编译由 cmake 处理(它涉及一些依赖库等)

所以基本上,我想告诉 python 整个包是由现有的 python_library.so 文件定义的。这可能吗?

注意:有一个related 问题。但是 OP 已经想出了如何打包扩展。

【问题讨论】:

  • something like this 会是解决方案吗?让 setup.py 调用 cmake?
  • 感谢您提供的链接,但这并不是我的想法。在给定的示例中,cmake 和 setup.py 的角色是相反的。我对 cmake 构建一切都很好。我只是想让 setup.py 运行测试/构建一个 egg 或类似的。

标签: cmake cython


【解决方案1】:

显然,这不是分发 python 包的最可靠的方式,因为它不适用于不同的操作系统,或者如果 Python 版本不匹配,可能会导致奇怪的结果 - 但仍有可能。

让我们考虑以下文件夹结构:

/
|--- setup.py
|--- my_package
        |-------  __init__.py
        |-------  impl.pyx          [needed only for creation of impl.so]
        |-------  impl-XXX.so       [created via "cythonize -i impl.pyx"]

内容如下:

__init__.py:

from .impl import foo

impl.pyx:

def foo():
    print("I'm foo from impl")

setup.py:

from setuptools import setup, find_packages


kwargs = {
      'name':'my_package',
      'version':'0.1.0',
      'packages':find_packages(),

       #ensure so-files are copied to the installation:
      'package_data' : { 'my_package': ['*.so']},
      'include_package_data' : True,
      'zip_safe' : False  
}


setup(**kwargs)

现在调用python setup.py install后,安装包就可以使用了:

>>> python -c "import my_package; my_package.foo()"
I'm foo from impl

注意:不要从包含安装文件的文件夹中调用测试,因为那样不能使用已安装但本地版本的my_package


您可能希望为不同的 Python 版本提供不同的二进制文件。可以为不同的 Python 版本编译相同的扩展 - 您必须为生成的共享库添加正确的后缀,例如:

  • impl.cpython-36m-x86_64-linux-gnu.so 用于我的 linux 机器上的 Python3.6
  • impl.cpython-37m-x86_64-linux-gnu.so for Python3.7
  • impl.cp36-win_amd64.pyd 在 Windows 上

可以使用

获取当前机器上的扩展后缀
>>> import importlib
>>> importlib.machinery.EXTENSION_SUFFIXES
['.cp36-win_amd64.pyd', '.pyd']

【讨论】:

  • 感谢您的评论。你所说的健壮性是什么意思?显然,该库依赖于操作系统。我不希望在 Linux 上构建的包(包含 *.so)在 Windows 上运行。但是不同的版本呢?我希望 Python C API / ABI 是稳定的?!
  • @hfhc2 Python 3.X 不适用于使用 Python 3.Y 构建的 so-files。这就是原因,so-files(和 pyc-files)有后缀 a la cpython-36m-x86_64-linux-gnu 所以不会有混淆。
  • 好吧,我想遵循这个约定。根据上述模式命名库是否足够?我可以通过编程方式获取后缀吗?
  • @hfhc2 有一种简单的方法可以在本地机器上找到它(请参阅我的更新),不知道如何在没有目标机器的情况下获得它。但这也可能是一个单独的问题
猜你喜欢
  • 1970-01-01
  • 2018-01-17
  • 1970-01-01
  • 2016-11-04
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多