错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法

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

Traceback (most recent call last):
  File "", line 1, in 
  File "/home/users/kinva/tools/lib/python2.7/site-packages/annoy/__init__.py", line 15, in 
    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的问题。

解决方案

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

  • 减弱版本依赖以便在程序在启动的时候不被动态连接器终止
  • 提供缺失的依赖函数(由最新的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

输出:


错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法_第1张图片
readelf1.png

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

更改glic_2.14依赖

  • 图中.gpu.version_r 的地址起始位置在文件偏移量0x002288处
  • glibc_2.14版本标记地址偏移量是0x0050,在文件地址偏移量的(0x002288+0x0050)
  • 指向0x0090偏移量的位置存放的是结构体Elfxx_Vernaux


    错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法_第2张图片
    glibc1.png
  • vna_flags 是依赖信息,在结构体的第二个位置,ELFxx_Word是32bit,也就是4B,因此vna_flag的起始地址偏移量是0x04

通常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
错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法_第3张图片
readelf2.png

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

实现缺失的函数

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

#include 
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共享库
接下来就是链接动态库就好了。

  • 可以拷贝so到已经在引入的路径,如我的/home/users/kinva/tools/lib
  • 或者 export LD_LIBRARY_PATH=/home/users/kinva/tools/mylib:$LD_LIBRARY_PATH

再次执行:

[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及以上版本。

你可能感兴趣的:(错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法)