我正在开发一个 Rust 库,它使用 PyO3 进行 Python 绑定,这些绑定是使用 maturin 构建的。
问题
如果我在我的操作系统(Arch,使用 Glibc 2.31)上构建绑定,则生成的 .whl 不适用于旧系统,因为 Glibc 不兼容并引发错误,例如:
ImportError: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found
(required by /home/travis/virtualenv/python3.7.1/lib/python3.7/site-packages/my_package.cpython-37m-x86_64-linux-gnu.so)
当前的解决方法
为了解决这个问题,我们在一个有 Glibc 2.12 的centos 6.9上构建我们的绑定,因此“应该兼容”几乎所有的 Linux 发行版。
实际问题
这显然只是一种解决方法,应该有更好的解决方案。
以使它们在大多数 Linux 发行版上工作的方式编译 maturin 库的正确方法是什么?
据我了解,这就是manylinux 标准的用途,那为什么它不起作用呢?我错过了什么?
我的假设和测试
我想一个可能的解决方案是将 Glibc 静态链接到库中,因此针对用于静态编译的musl 。
是否有可能做到这一点?我发现这个博客表明它可以完成,但我看到在 .whl 文件(它们只是 python 可安装档案)内部有一个.so
,因此是一个共享库。
甚至可以构建一个使用 musl 静态链接 libc 的共享库吗?
我找到了一个可能的工作示例:在 tensorflow who 内部tf_nightly-2.4.0.dev20200710-cp36-cp36m-manylinux2010_x86_64
,有一个文件/tensorflow/python/_pywrap_utils.so
:
file _pywrap_utils.so [2]
_pywrap_utils.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), statically linked, BuildID[md5/uuid]=aee3c5fa4ae1243775857b2643b80ea0, not stripped
但它似乎无论如何都是动态链接的:
ldd _pywrap_utils.so
linux-vdso.so.1 (0x00007fffb3782000)
libtensorflow_framework.so.2 => not found
_pywrap_tensorflow_internal.so => not found
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f5c95672000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f5c95658000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f5c95491000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f5c9534a000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f5c95a9f000)```
那么这真的可能吗?
有些人,强烈建议不要这样做,这是为什么呢?我得到在同一个可执行文件中线程和分配器的不同实现可能会导致兼容性问题。
我试图改变Cargo.toml
从
[lib]
crate-type = ["cdylib"]
对此(如此处所示)
[lib]
crate-type = ["staticlib"]
但马图林似乎对此并不高兴。
maturin failed
Caused by: Cargo didn't build a cdylib. Did you miss crate-type = ["cdylib"] in the lib section of your Cargo.toml?
也许这可以通过编译标志来完成crt-static
?