如何避免使用我的 python 包构建 C 库?

How to avoid building C library with my python package?

我正在使用带有 ctypes 的 C 库构建一个 python 包。 我想让我的包便携(Windows、Mac 和 Linux)。

我找到了一个策略,使用 build_extpip 在我的包安装过程中构建库。它根据目标平台创建 libfoo.dlllibfoo.dyliblibfoo.so

问题是我的用户需要安装 CMake。

是否存在另一种避免在安装过程中构建的策略?我必须在我的包中捆绑构建的库吗?

我想让我的用户继续做 pip install mylib

编辑:感谢@Dawid 的评论,我正在尝试使用命令 python setup.py bdist_wheel 创建 python wheel 但没有成功。

如何使用嵌入式库为不同平台创建 python 轮子?

编辑 2: 我正在使用 python 3.4 并在 Mac OS X 上工作,但我可以访问 Windows 台计算机,以及 Linux 台计算机

如果你不想让用户在安装时构建,你必须提供一个预构建的二进制包,我认为没有其他策略是可行的。我听说过关于 py2exe, but I don't use windows so IDK. I've had good experiences with miniconda, but it does require a little extra work to build binary packages from pypi.

的好消息

根据我的研究,您肯定是在朝着正确的方向前进...正如 Daniel 所说,您唯一的选择就是自己构建和分发二进制文件。

一般来说,packaging user guide. I won't repeat advice there as you have clearly already found it. However the key point in there is that the Python community, specifically PyPA are trying to standardize on using platform wheels 中很好地介绍了推荐的安装包的方式来打包二进制扩展。遗憾的是,此时存在一些问题:

  1. 您不能为所有 Linux 变体创建分布,但您可以为兼容的子集构建轮子。有关详细信息,请参阅 https://www.python.org/dev/peps/pep-0513/
  2. advice on building extensions有些不完整,反映出缺乏完整的二元分布解决方案。
  3. 然后人们尝试构建自己的库并将其作为数据文件分发,这混淆了设置工具。

我认为您正在解决最后一个问题。 workaround 是通过将 is_pure() 覆盖为始终 return False 来强制 Distribution 构建平台轮。但是,您可以只保留原始构建说明,bdist_wheel 应该会处理它。

不过,一旦你构建了轮子,你仍然需要分发它,也许还有它使用或使用它的其他二进制包。此时,您可能需要使用 recommended tools like conda or a PyPI proxy like devpi 之一来为您的轮子提供服务。

编辑:回答关于交叉编译的额外问题

如前所述here Python 2.6 and later allows cross-compilation for Windows 32/64-bit builds. There is no formal support for other packages on other platforms and people have had limited success 正在努力做到这一点。您最好在每个 Linux/Mac/Windows 环境中进行原生构建。

I prefer my user to install cygwin/mingw32 or cmake and do a pip install mylib [...]. I just want to go further and try to avoid the CMake installation.

关于打包预编译的python模块,参见@Peter Brittain的完整回答。

现在,假设用户实际安装了 C 编译器(无论是 Windows 上的 cygwin、conda,还是 Linux 上的系统编译器),您想要的只是避免CMake的安装,跟Python打包没有关系。

那么问题是您使用了多少 CMake 功能,以及是否可以使用更易于管理的替代方案来完成同样的事情,请参阅相关问题 (1), (2)

编辑: 特别是,我在想一些可能有用的 SCons that provides a full build system, but written in Python so it is easier to install in a Python friendly environment than CMake, see full comparison here. A wild guess (I have never used it myself), but since it is a pure python module, you could probably set SCons as a dependency in your setup.py, and fully automate the build of your C code there, so that pip install mylib does everything that's needed. See also, CMake2SCons 包。

@rth 和@PeterBrittain 帮了我很多。这里我使用的解决方案:

结构文件夹:

setup.py
python_package/
    lib/
        libfoo.dylib
        libfoo.dll
    __init__.py
    main.py

setup.py :

from setuptools import setup, dist


class BinaryDistribution(dist.Distribution):
    def is_pure(self):
        return False


setup(
    name='python_package',
    package_data={'python_package': ['lib/libfoo.dylib','lib/libfoo.dll']},
    include_package_data=True,
    distclass=BinaryDistribution,
    packages=['python_package'],
)

main.py :

#!/usr/bin/env python
import platform
from ctypes import CDLL, c_char_p

import pkg_resources

sysname = platform.system()

if sysname == 'Darwin':
    lib_name = "libfoo.dylib"
elif sysname == 'Windows':
    lib_name = "libfoo.dll"
else:
    lib_name = "libfoo.so"
lib_path = pkg_resources.resource_filename('python_package', 'lib/{}'.format(lib_name))
foo = CDLL(lib_path)

bar = foo.bar
bar.restype = c_char_p
bar.argtypes = [c_char_p]

print(bar('hello'))

构建轮子:

python setup.py bdist_wheel

它创建了一个特定的平台轮 rtfdoc-0.0.1-cp34-cp34m-macosx_10_10_x86_64.whl 和 mac 用户可以做一个简单的 pip install rtfdoc-0.0.1-cp34-cp34m-macosx_10_10_x86_64.whl

这个解决方案并不完全令人满意:

  • 我想我仍然需要为 linux 用户创建一个 Extension or look at SCons
  • 由于生成了 lib
  • ,更新我的包会很困难
  • 我不知道如何管理 32 位和 64 位的 .dll

谢谢,我学到了很多东西,我明白了为什么setup.py in Pillow 或 Psycopg2 很大

您可以使用 cibuildwheel 在 Travis CI and/or Appveyor 上为各种平台和 Python 版本构建轮子。该工具还可以在 PyPI 或其他地方部署您的轮子。