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

5

假设我们有一个名为MyAwesomeLib的C++库的已完成源代码。我们的目标是将其部分功能暴露给Python,因此我们使用SWIG创建了一个包装器,并生成了一个名为PyMyAwesomeLib的Python包。

现在的目录结构如下:

root_dir
|-src/
|-lib/
|    |- libMyAwesomeLib.so
|    |- _PyMyAwesomeLib.so
|-swig/
|    |- PyMyAwesomeLib.py
|-python/
     |- Script_using_myawesomelib.py

到目前为止一切都很顺利。理想情况下,我们接下来要做的就是以一种“Pythonic”的方式将lib/*.soswig/*.pypython/*.py 复制到site-packages中相应的目录中。

python setup.py install

然而,当我试图使用setuptools和distutils来实现这个简单目标时,我变得非常困惑。这两个工具都通过一个内部系统处理Python扩展的编译,其中源文件、编译器标志等都是通过setup(ext_module=[Extension(...)])传递的。但这是荒谬的,因为MyAsesomeLib有一个完全功能的构建系统,它基于makefile。移植嵌入在makefile中的逻辑将是冗余和完全不必要的工作。
经过一些研究,似乎还剩下两个选择,我可以覆盖setuptools.command.build和setuptools.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_resources、data_files或MANIFEST.in之间的区别。
我认为这实际上是一个普遍存在的情况,我希望有一个简单的解决方案。任何帮助将不胜感激。

你能满意地解决这个问题吗?我也遇到了类似的情况,希望能借鉴一下你的经验。谢谢! - jorgeh
这个可能已经没有人关注了,但我也想知道您的解决方案。您找到了一个令人满意的解决方案吗? - muma
将近三年了!我也处于同样的情况。 - Jey
1个回答

1

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

不幸的是,这正是我不得不做的事情。我一直在为这个问题苦苦挣扎。

将其移植过来实际上并不太困难。distutils理解SWIG扩展, 但他们实现得相当草率。运行SWIG会创建Python文件,当前的构建顺序假定在运行build_ext之前已经考虑到了所有的Python文件。这个问题并不难解决, 但让人恼火的是他们声称支持SWIG却没有提到这一点。Distutils试图在编译东西时跨平台,所以使用它仍然有优势。

如果您不想将整个构建系统移植过来,可以使用系统的软件包管理器。许多复杂的库都这样做(但它们也会尽力处理setup.py)。例如,在Ubuntu上获取numpy和lxml只需执行:sudo apt-get install python-numpy python-lxml。不需要使用pip。
我知道您更愿意编写一个设置文件而不是处理每个软件包管理器,所以这可能没有什么帮助。
如果您尝试使用setuptools路线,那么我遇到的一个致命缺陷是依赖项。
例如,如果您正在分发基于SWIG的项目,它将需要libpython。如果他们没有它,就会出现这样的错误:
#include <Python.h>
error: File not found

对于普通用户来说,这相当不友好。

更糟糕的是,如果您需要共享库,但用户的库已过时,则用户可能会遇到一些奇怪的错误。您需要依赖他们的C++编译器输出谷歌友好的错误消息,以便他们可以弄清楚问题所在。

长期解决方案是让setuptools/distutils更好地检测非Python库,希望能够像Ruby的gem一样好。我几乎不得不自己动手。例如,在我正在处理的setup.py中,您可以看到我在顶部组合在一起的一些函数用于依赖项检测(仍然无法在所有系统上运行...绝对不能在Windows上运行)。


感谢您的建议。不幸的是,我的软件包有许多非平凡的依赖关系。现在,为一些常见的软件包管理系统准备预编译的软件包将是最好的选择。我希望 Python 社区能够在不久的将来解决这个问题。 - James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接