在使用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.cythonize
和setuptools.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
,我能够验证id
my.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)
一般来说,这对于dylib来说不是一个好id
,但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后,我就可以下载并运行代码了。
答案 0 :(得分:0)
查看delocate和Linux等效版auditwheel。
delocate工具不是必须在运行时更改链接加载器路径,而是将第三方库嵌入到轮中并相应地调整加载时间路径。
结果是一个可分发的二进制轮,正确包含所有依赖库。
设置运行时加载路径不可移植,不能在python版本或机器架构中使用。
例如,对于上述内容,在python setup.py bdist_wheel
运行:
delocate-wheel -w fixed_wheels <wheel file>
固定的轮盘文件将放在fixed_wheels
目录下。使用-v
运行以查看它嵌入的库。