如何安装 C++ 库的 python 绑定

Jam*_*mes 5 python swig distutils setuptools setup.py

想象一下,我们得到了一个名为MyAwesomeLib. 目标是将其部分功能暴露给 python,因此我们使用 swig 创建了一个包装器并生成了一个名为PyMyAwesomeLib.

目录结构现在看起来像

root_dir
|-src/
|-lib/
|    |- libMyAwesomeLib.so
|    |- _PyMyAwesomeLib.so
|-swig/
|    |- PyMyAwesomeLib.py
|-python/
     |- Script_using_myawesomelib.py
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。理想情况下,所有我们下一步要做的就是复制lib/*.so swig/*.pypython/*.py在进入相应的目录site-packagesPython化,即使用方式

python setup.py install
Run Code Online (Sandbox Code Playgroud)

但是,在尝试使用setuptoolsand实现这个简单的目标时,我感到非常困惑distutils。这两个工具都通过内部系统处理 python 扩展的编译,其中源文件、编译器标志等使用setup(ext_module=[Extension(...)]). 但这很荒谬,因为它MyAsesomeLib有一个基于 makefile 的功能齐全的构建系统。移植嵌入在 makefile 中的逻辑将是多余的并且完全没有必要的工作。

经过一些研究,似乎还有两个选项,我可以覆盖setuptools.command.buildsetuptools.command.install使用现有的 makefile 并直接复制结果,或者我可以以某种方式setuptools告知这些文件并要求它在安装过程中复制它们。第二种方式更吸引人,但却是最让我头疼的地方。我尝试了以下选项但没有成功

  • package_data, 并且include_package_data不起作用,因为 *.so 文件不受版本控制并且它们不在任何包内。
  • data_files似乎不起作用,因为文件只在运行时被包含python setup.py sdist,但在python setup.py install. 这与我想要的相反。这些.so文件不应包含在源代码分发中,而应在安装步骤中复制。
  • MANIFEST.in失败的原因与data_files.
  • eager_resources也不起作用,但老实说,我不知道eager_resourcesanddata_files或之间的区别MANIFEST.in

我认为这实际上是一种常见情况,我希望有一个简单的解决方案。任何帮助将不胜感激。

sci*_*ctn 1

移植 makefile 中嵌入的逻辑将是多余且完全不必要的工作。

不幸的是,这正是我必须做的。我已经为同样的问题苦苦挣扎了一段时间了。

移植它实际上并不算太糟糕。distutils 确实理解 SWIG 扩展,但他们的实现相当随意。运行 SWIG 会创建 Python 文件,并且当前的构建顺序假定在运行之前已考虑所有 Python 文件build_ext。这个问题并不难修复,但令人恼火的是他们声称支持 SWIG 而没有提及这一点。Distutils 在编译时尝试跨平台,因此使用它仍然有优势。

如果您不想移植整个构建系统,请使用系统的包管理器。许多复杂的库都这样做(但他们也尽力使用 setup.py)。例如,要在 Ubuntu 上获取 numpy 和 lxml,您只需执行以下操作 sudo apt-get install python-numpy python-lxml:没有点。

我意识到您宁愿编写一个安装文件,而不是处理每个包管理器,所以这可能不是很有帮助。

如果你确实尝试使用 setuptools 路线,我会遇到一个致命的缺陷:依赖关系。

例如,如果您要分发基于 SWIG 的项目,则它将需要 libpython。如果他们没有它,就会发生这样的错误:

#include <Python.h>
error: File not found
Run Code Online (Sandbox Code Playgroud)

这对普通用户来说毫无帮助。

更糟糕的是,如果您需要共享库但用户的库已过时,用户可能会遇到一些疯狂的错误。你受他们的 C++ 编译器的摆布,输出 Google 友好的错误消息,以便他们能够找出答案。

长期的解决方案是让 setuptools/distutils 更好地检测非 python 库,希望与 Ruby 的 gem 一样好。我几乎不得不自己动手。例如,在我正在处理的setup.py中,您可以在顶部看到一些我为了依赖性检测而拼凑在一起的函数(仍然不适用于所有系统......绝对不是 Windows)。