【发布时间】:2020-07-10 16:07:08
【问题描述】:
我正在开发一个 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)
当前的解决方法
为了解决这个问题,我们正在 centos 6.9 上构建我们的绑定,它具有 Glibc 2.12,因此“应该兼容”几乎所有 Linux 发行版。
实际问题
这显然只是一种解决方法,应该有更好的解决方案。
编译 maturin 库以使其适用于大多数 Linux 发行版的正确方法是什么?
据我了解,这就是manylinux standard 的用途,那为什么它不起作用?我错过了什么?
我的假设和检验
我猜想一个可能的解决方案是将 Glibc 静态链接到库中,因此以 musl 为目标,这意味着静态编译。
可以这样做吗?我发现 this blog 表明它可以完成,但我看到 .whl 文件(它们只是 python 可安装档案)内部有一个 .so ,因此是一个共享库。
是否有可能构建一个使用 musl 静态链接 libc 的共享库?
我找到了一个可能的工作示例:在 tf_nightly-2.4.0.dev20200710-cp36-cp36m-manylinux2010_x86_64 的 tensorflow 内部,有文件 /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)```
那么这真的可能吗?
Some people,强烈建议不要这样做,这是为什么呢?我发现在同一个可执行文件中线程和分配器的不同实现可能会导致兼容性问题。
我已尝试将Cargo.toml 更改为
[lib]
crate-type = ["cdylib"]
对此(as seen here)
[lib]
crate-type = ["staticlib"]
但 maturin 似乎对此并不满意。
???? 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 来完成?
【问题讨论】: