使用distutils的setup.py编译C共享库时,如果该库依赖于第二个共享库

8
我正在使用OSX,尝试使用distutils的setup.py编译一个C语言共享库(以便在Python中使用ctypes),这与distutils是新领域。但是,当我想要编译的共享库(libreboundx.so)依赖于另一个共享库(librebound.so)时,我遇到了问题。具体来说,在modify_orbits_direct.c中:
#include "rebound.h"

rebound.h在目录/Users/dt/rebound/src/中,rebound.h中的所有函数都在共享库librebound.so中,该库位于/Users/dt/rebound/中。

使用cc进行链接的方法如下。

cc -fPIC -shared reboundx.o -L/Users/dt/rebound -lrebound -o libreboundx.so

更新:这种情况与https://docs.python.org/2/extending/building.html第3节末尾的示例完全相同。我已经更新了我的setup.py文件以模仿那个示例:

libreboundxmodule = Extension('libreboundx',
                sources = [ 'src/reboundx.c',
                            'src/modify_orbits_direct.c'],  
                include_dirs = ['src', '/Users/dt/rebound/src'], 
                extra_compile_args=['-fstrict-aliasing', '-O3','-std=c99','-march=native', '-D_GNU_SOURCE', '-fPIC'],
                library_dirs=['/Users/dt/rebound'],
                libraries=['rebound'],
                                )   

这段代码在我运行时安装正常。
pip install -e ./

构建输出:

You are using pip version 7.0.3, however version 7.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Obtaining file:///Users/dtamayo/Documents/workspace/reboundx
Installing collected packages: reboundx
Running setup.py develop for reboundx
Successfully installed reboundx-1.0

但是当我尝试时

import reboundx

在Python中,我遇到了OSError错误:dlopen(libreboundx.so,10):Symbol not found:_reb_boundary_particle_is_in_box,这是其他库(librebound.so)中的一个函数,该函数在libreboundx.so的代码中甚至没有被调用。
如果我使用上面的cc命令链接共享库,一切正常,我可以在C中完美地使用共享库libreboundx.so。如果我尝试将使用cc命令编译的相同libreboundx.so放在setup.py应该放置它的位置,然后尝试在python中导入reboundx,我却得到了...
OSError: dlopen(/Users/dtamayo/Documents/workspace/reboundx/reboundx/../libreboundx.so, 10): Library not loaded: librebound.so

参考来源:/Users/dtamayo/Documents/workspace/reboundx/libreboundx.so 原因:找不到图像

这可能类似于rpath问题,在运行时,libreboundx.so不知道在哪里查找librebound.so?


1
libraries=['librebound']看起来很可疑。它不应该包含lib前缀,而只应该是rebound。你也不应该链接-llibrebound,而是-lrebound。除此之外,您可以提供构建输出吗? - deets
我在问题中添加了它。使用'librebound'或'rebound'库时,我得到完全相同的行为/输出(这表明有些问题!)。此外,我尝试在底部的install_requires中添加'rebound'。这会显示"Requirement already satisfied (use --upgrade to upgrade): rebound in /Users/dtamayo/Documents/workspace/rebound (from reboundx==1.0)",但是在Python中导入时仍然出现相同的错误。 - Dan
2
在OS X上,otool -D显示库的install_name,而install_name_tool -id将更改它。如果您想要相对于加载模块的路径,请使用@loader_path标记。使用otool -L列出依赖项,并使用install_name_tool -change更改它们。您还可以设置-rpath依赖项搜索路径;这可以使用@loader_path作为相对路径。Extension类具有一个rpath参数,但是该类确实不适合构建通用共享模块(特别是在Windows上,如果这很重要)。您可以调用ccompiler.new_compiler直接执行gcc。 - Eryk Sun
既然您需要编译器,从宏观角度来看,如果您切换到使用CFFI的API接口,您的生活可能会更简单,而不是使用ctypes。 - Eryk Sun
顺便说一句,我从未使用过OS X,所以把我的建议当作一个起点。请参考dyld man页面OS X ABI Mach-O文件格式参考和这篇关于Mach-O二进制文件的文章。 - Eryk Sun
“otool -l libreboundx.so”的输出是什么? - deets
1个回答

5
感谢所有的建议。我应该在问题中明确说明,最终我希望能有一个解决方案,可以打包上传到PyPy,这样用户就可以用一个命令安装。它还应该在OSX和Linux上运行,因此我更喜欢不涉及install_name_tool的解决方案。
我还没有测试过它,但我认为添加
 runtime_library_dirs=['/Users/dt/rebound'],

在Linux上,将library_dirs放在旁边应该可以解决问题。显然,在Mac上这种方法行不通,但你可以使用extra_link_args。在上面发布的libreboundxmodule定义下方添加以下内容:

if platform.system() == 'Darwin':
    extra_link_args.append('-Wl,-rpath,'+'/Users/dtamayo/Documents/workspace/rebound')

问题已经解决。我在这里找到了答案:Python runtime_library_dirs 在 Mac 上无法工作


1
这个上传到PyPI上是行不通的。除非用户恰好叫做dtamayo并且在Documents文件夹下的工作区内工作;) 您需要将库与您的软件包捆绑在一起,并且需要使用相对路径,例如@executable_path或类似的别名。 - deets
没错。我想尝试单独定位反弹库的位置,因为Python setup.py install将其列为输出的一部分,这似乎是可能的。即使我知道路径,以前我也无法使它工作。 - Dan
1
我建议进行实验的步骤是:首先手工制作你想要的bundle。例如,将librebound.dylib复制到libreboundx.dylib旁边,然后尝试导入该包。如果失败了,可以使用install_name_tool更改libreboundx的rpath,以便找到它(显然是使用@-别名的相对路径)。一旦达到这个目标,尝试调整setup.py,直到它构建/交付此结果。 - deets
谢谢,我正在尝试像那样的简单情况。我发现extra_link_args使用rpath做了我需要的事情。现在我卡在下一个复杂问题上 :) http://stackoverflow.com/questions/32313793/how-to-have-pypi-package-install-header-files-for-c-extension-with-distutils-set - Dan

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