JAVA大数据程序员

错误:/lib64/libc.so.6: version `GL

2017-03-02  本文已影响0人  Kinva

不管你是用annoy还是用tensorflow,用pip安装后,然后import的时候会产生类似以下的异常:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/users/kinva/tools/lib/python2.7/site-packages/annoy/__init__.py", line 15, in <module>
    from .annoylib import *
ImportError: /lib64/tls/libc.so.6: version `GLIBC_2.14' not found (required by /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so)
# 如果是TF就是lib/python2.7/site-packages/tensorflow/python/_pywrap_tensorflow.so

优先尝试这种方法:
python错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法

我在这个问题上卡了很久,也查找了很多资料,都不能圆满解决glibc依赖的问题,连重新编译libc-2.14都试过了。
后来偶然发现了这篇文文章:Running new applications on old glibc 参考这篇文章的思路,这个问题才得以圆满解决(感谢文章的作者,同时感谢公司内部资料),下面根据这篇文章的思路来阐述如何逐步解决annoy或者tf依赖glibc的问题。

解决方案

解决方法主要包括两部分内容:

下面以annoy为例,TF类似的,自己替换文件路径即可

查看依赖

错误是由/home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so这个动态连接库引起的,那看一看这个so里到底哪部分依赖了glibc2.14。

# readelf -s 文件路径|grep GLIBC_2.14
readelf -s /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so | grep GLIBC_2.14

输出如下:

108: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND memcpy@GLIBC_2.14 (7)
180: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND memcpy@@GLIBC_2.14

我们看到依赖了2.14的memcpy函数。

再来看一看annoylib.so中依赖的glibc版本信息,执行:

# readelf -V 文件路径
readelf -V /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so

输出:


readelf1.png

可以看出在地址偏移量0x0050处,是glibc_2.14的标记地址,问题的关键是如何减弱这个版本依赖。
其思路就是想办法让这个glibc_2.14这个版本依赖变成可选而非强制性的。

更改glic_2.14依赖

通常Flags:none在二进制位置的值是0x0000,根据上述分析,为了能减弱glibc_2.14的版本依赖,需要在(0x002288+0x0050+0x04)处填充0x02(对应VER_FLG_WEAK)

因此执行:

# 要养成习惯,更改文件的时候,一定要备份
cp /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so annoylib.so
# 更改为弱依赖
# 其中0x22dc需要自己计算0x002288+0x0050+0x04
# 这里替换2个地方,一个是地址,一个是文件路径,其他保持不变。
for addr in 0x22dc; do printf '\x02' | dd conv=notrunc of=/home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so  bs=1 seek=$((addr)) ; done

执行完了,我们验证效果:

# readelf -V 文件路径
readelf -V /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so
readelf2.png

看到2.14版本依赖已经变成weak了。成功了一半。

实现缺失的函数

接下来需要解决缺失的memcpy函数,最简单的方式是生成一个本地的动态库来实现缺失的函数,并在执行程序之前使用LD_PRELOAD去load这个动态库。
针对上文中指出的缺失的memcpy函数,如果查看实际的glibc_2.14实现的memcpy函数就会发现,其实际上和memmove相同,这样我们可以自己实现这个函数(mylibc.so):

#include <string.h>
void* memcpy(void *dest, const void *src, size_t n) {
    return memmove(dest, src, n);
}

执行以下命令编译成so

gcc -s -shared -o mylibc.so -fPIC -fno-builtin mylibc.c

得到mylibc.so共享库
接下来就是链接动态库就好了。

再次执行:

[kinva@MacBook-Pro ~]$ python
Python 2.7.3 (default, Jan 24 2017, 17:03:37) 
[GCC 3.4.5 20051201 (Red Hat 3.4.5-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import annoy
>>> 

其他问题

如果还是继续报错,请注意报的so已经不一样了,把每一个so的问题都解决。
如果你依赖的gcc是4.8+,请用4.6版本,否则你要拥有root权限。

TF需要更改的文件:
_pywrap_tensorflow.so
libstdc++.so.6(root权限)
librt.so.1
_sparse_feature_cross_op.so
_bucketization_op.so
_set_ops.so
_lstm_ops.so
_sdca_ops.so
需要实现的so有:mylibc.so和mygettime.so
memcpy和gettime相关,可以查查别的资料这个实现很简单的,我就不写了。

建议

这个东西根本原因就是系统版本库太老,如果更新glibc将会引起系统不稳定,所以建议还是升级系统吧。如果是centos,建议用6u3及以上版本。

上一篇下一篇

猜你喜欢

热点阅读