cython - 分发 python 包时处理 dylibs

标签 cython portability distutils dylib

在使用 python setup.py bdist_wheel 构建 Cython 模块后,我需要运行某些命令或等效的命令。这可能吗?

具体情况如下:
我正在为 osx 开发 Cython 程序。它链接到某些 .dylib我的主目录中的文件并要构建程序,您要么必须运行

export DYLD_LIBRARY_PATH=/path/to/parent/dir

(这很麻烦)或在 setup.py 中包含指令运行
install_name_tool -change @executable_path/my.dylib /path/to/my.dylib

这基本上是告诉二进制文件在哪里寻找 dylib .这两种选择都不理想,但后者似乎更便携。现在我刚刚将这些说明添加到 setup.py 的底部。 ,但这仍然是不可移植的:假设我打包并上传我的包如下:
python setup.py sdist  # I think this collects source files into a .tar
python setup.py bdist_wheel  # I think this builds a binary. This is where I assume the post-compilation stuff should happen.
twine upload dist/*   # This puts stuff up on PyPi.

现在,我已经阅读了文档和一些教程,诚然我仍然不能 100% 确定这些命令的作用。但我知道,如果随后,在另一个项目中,我运行
pip install mypackage

dylib 问题抬头:
ImportError: dlopen(/path/to/my/module.cpython-36m-darwin.so, 2): 
Library not loaded: @executable_path/my.dylib
  Referenced from: /path/to/my/module.cpython-36m-darwin.so
  Reason: image not found

解决方案似乎是在 setup.py 中添加某种自动编译后方向,以指示 install_name_tool需要进行操作。假设这是可能的,人们将如何做到这一点?理想情况下,我想使用现成的 Cython.Build.cythonizesetuptools.Extension ,但也许我需要做一些更定制的事情。感谢您的建议!

解决方案

Danny 正确地指出运行 install_name_tool不是一个可移植的解决方案,而是应该以某种方式将 dylib 包含在包中。 delocate 是工作的工具,但我遇到的第一个挑战是 delocate不适用于 @executable_path :
❯ delocate-wheel -w fixed_wheels -v dist/*.whl
Fixing: dist/my-package-1.0.9-cp36-cp36m-macosx_10_12_x86_64.whl
/Users/ethan/virtualenvs/my-package/lib/python3.6/site-packages/delocate/delocating.py:71: UserWarning: Not processing required path @executable_path/my.dylib because it begins with @
  'begins with @'.format(required))

使用 otool ,我能够验证 idmy.dylib使用 @executable_path :
❯ otool -L my.dylib
my.dylib:
    @executable_path/my.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.1.0)
    /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1258.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

摆脱@executable_path我运行了以下内容:
❯ install_name_tool -id my.dylib my.dylib

现在查看 otool -L 的输出:
❯ otool -L my.dylib
my.dylib:
    my.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.1.0)
    /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1258.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

总的来说,这不是一个好的id用于 dylib,但对于 delocate-wheel 来说已经足够了跟...共事。我重建了我的 .whl :
python setup.py bdist_wheel

现在,当我运行 delocate_wheel :
❯ delocate-wheel -w fixed_wheels -v dist/*.whl
Fixing: dist/my.whl
Traceback (most recent call last):
...    
delocate.delocating.DelocationError: library "/Users/ethan/my-package/my.dylib" does not exist

这清楚地告诉我们delocate期望找到 my.dylib .所以我复制了my.dylib/Users/ethan/my-package/my.dylib并重新运行命令:
❯ delocate-wheel -w fixed_wheels -v dist/*.whl
Fixing: dist/my.whl
Copied to package .dylibs directory:
  /Users/ethan/my-package/my.dylib

成功!这是什么.dylibs目录?我跑了tar -xvf my.whl打开车轮包装并检查其内容:
❯ tree -a fixed_wheels/my-package
fixed_wheels/my-package
├── .dylibs
│   └── my.dylib
├── __init__.py
└── package.cpython-36m-darwin.so

如您所见,my.dylib已复制到 .dylibs/打包在 my.whl 中的目录.上传后my.whl对于 pypi,我能够很好地下载和运行代码。

最佳答案

看看delocate和 Linux 等效的 auditwheel .

delocate 工具无需在运行时更改链接加载器路径,而是将第三方库嵌入到轮子中并相应地调整加载时间路径。

结果是一个可分发的二进制轮子,其中包含正确的所有依赖库。

设置运行时加载路径是不可移植的,并且不能跨 python 版本或机器架构工作。

例如对于上面的例子,在 python setup.py bdist_wheel 创建了一个轮子之后跑:
delocate-wheel -w fixed_wheels <wheel file>
固定轮文件将放在 fixed_wheels 下目录。运行 -v查看它嵌入了哪些库。

关于cython - 分发 python 包时处理 dylibs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47380150/

相关文章:

python - 如何在 cythonize 脚本中包含 numpy?

mysql - 在 web.py DB INSERT 中使用 SQLLiteral ("NOW()") 的可移植性如何?

java - 什么是便携性? java如何比其他语言更便携?

python - 让 py2exe 包含我的数据文件(如 include_package_data)

python - 为 linux 打包 python 应用程序

python - cython setup.py 给出 .o 而不是 .dll

python - 如何获取 pyd 文件的路径(又名相当于 __file__)

python-3.x - 用 Cython 编译 python3 脚本 | CentOS 6.x

windows - 将非 bat 扩展文件作为批处理文件运行

python - PYTHONPATH 应该包含 ./build/* 吗?