Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从.so文件导入Python模块在GLIBC版本较低的目标系统上失败_Python_C++_Linux_Glibc_Shared Libraries - Fatal编程技术网

从.so文件导入Python模块在GLIBC版本较低的目标系统上失败

从.so文件导入Python模块在GLIBC版本较低的目标系统上失败,python,c++,linux,glibc,shared-libraries,Python,C++,Linux,Glibc,Shared Libraries,我在Ubuntu14.04上使用GCC4.9.0(从源代码构建)构建了一个共享库(“libFoo.so”),并围绕它构建了一个Boost.Python包装库(“Foo.so”用于模块Foo,根据命名约定) 出于分发目的,我将所有共享对象依赖项包含在同一目录中,我使用ldd提取了该目录: machine1:~/lib$ ls Foo.so libc.so.6 libgcc_s.so.1 libFoo.so libpthread.so.0 librt.so.1

我在Ubuntu14.04上使用GCC4.9.0(从源代码构建)构建了一个共享库(“libFoo.so”),并围绕它构建了一个Boost.Python包装库(“Foo.so”用于模块Foo,根据命名约定)

出于分发目的,我将所有共享对象依赖项包含在同一目录中,我使用ldd提取了该目录:

machine1:~/lib$ ls
Foo.so    libc.so.6   libgcc_s.so.1     libFoo.so  libpthread.so.0      librt.so.1      libutil.so.1
libboost_python.so.1.55.0  libdl.so.2  libm.so.6       libpython2.7.so.1.0  libstdc++.so.6  libz.so.1

machine1:~/lib$ ldd Foo.so 
    linux-vdso.so.1 =>  (0x00007fff319fe000)
    libboost_python.so.1.55.0 (0x00007f9d568aa000)
    libpython2.7.so.1.0 (0x00007f9d56342000)
    libFoo.so (0x00007f9d55e92000)
    libm.so.6 (0x00007f9d55b8c000)
    libc.so.6 (0x00007f9d557c5000)
    libutil.so.1 (0x00007f9d555c2000)
    libpthread.so.0 (0x00007f9d553a4000)
    libdl.so.2 (0x00007f9d5519f000)
    librt.so.1 (0x00007f9d54f97000)
    libstdc++.so.6 => /usr/local/lib64/libstdc++.so.6 (0x00007f9d54c8d000)
    libgcc_s.so.1 => /usr/local/lib64/libgcc_s.so.1 (0x00007f9d54a76000)
    libz.so.1 (0x00007f9d5485d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f9d56d82000)
在原来的系统上,我现在可以写:

machine1:~/lib$ LD_LIBRARY_PATH=. PYTHONPATH=. python
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Foo
>>>
然而,在另一个系统(Ubuntu12.04LTS)上,我在这一步的工作中遇到了严重的问题

machine2:~/lib$ LD_LIBRARY_PATH=. PYTHONPATH=. python
Inconsistency detected by ld.so: dl-close.c: 759: _dl_close: Assertion `map->l_init_called' failed!
好的,甚至在启动Python时也存在某种冲突,所以让我们将有问题的库移到其他地方:

machine2:~/lib$ mv libc.so.6 libdl.so.2 ..

machine2:~/lib$ LD_LIBRARY_PATH=. PYTHONPATH=. python
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found (required by ./libstdc++.so.6)
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/apport_python_hook.py", line 66, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
  File "/usr/lib/python2.7/dist-packages/apport/__init__.py", line 1, in <module>
    from apport.report import Report
  File "/usr/lib/python2.7/dist-packages/apport/report.py", line 20, in <module>
    import apport.fileutils
  File "/usr/lib/python2.7/dist-packages/apport/fileutils.py", line 22, in <module>
    from apport.packaging_impl import impl as packaging
  File "/usr/lib/python2.7/dist-packages/apport/packaging_impl.py", line 20, in <module>
    import apt
  File "/usr/lib/python2.7/dist-packages/apt/__init__.py", line 21, in <module>
    import apt_pkg
ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found (required by ./libstdc++.so.6)

Original exception was:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found (required by ./libstdc++.so.6)
我如何才能做到这一点,并在目标系统上成功地导入Python中的模块Foo?假设我不能在目标系统上全局安装一个新的GLUBC版本,也不能安装GCC 4.9并在本地编译C++库。 我确实可以控制构建系统上的构建过程,但是为了便于讨论,我想假设我从第三方收到了共享对象文件,并且也不能修改它们

目标系统上的“python”二进制文件似乎依赖于较旧的Glibc版本。我假设Glibc是向后ABI兼容的,也就是说,有了一个更新的版本(由我提供),一切都应该按预期工作


我真的无法想象自己是第一个遇到此类问题的人,因此我假设一定有一个简单的解决方案,即使我无法解决它……

似乎解决方案只是从构建系统复制共享库加载器(当前目录中存在所有依赖项)并调用Python,如下所示:

machine2:~/lib$ ./ld-linux-x86-64.so.2 --library-path . `which python`
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Foo
>>> dir(Foo)
[...]
为什么提供更新版本的Glibc不起作用

这是可以解释的

如果在
中没有完整的glibc安装,那么您提出的解决方案(使用
--库路径运行加载程序)仍然存在问题。特别是,绑定访问任何NSS函数(
getgrpnam
getpwnam
,等等)可能会导致程序崩溃,因为您没有复制
libnss*。因此


“如果我使用了这些函数中的任何一个,libnss*.so将使用ldd Foo.so列出,并因此复制到.,对吗?”

不,那是错误的。这些库是动态加载的,而不是直接链接到

有什么方法可以可靠地找出所有依赖项吗

对于给定的调用,可以执行以下操作:

LD_DEBUG=libs ./ld-linux-x86-64.so.2 --library-path . `which python` foo.py
这将为您提供特定
foo.py
所需的库的列表。当您运行不同的脚本时,该列表可能会更改,因此这不是一个通用的解决方案

在你的链接帖子中,glibc由200多个库组成,对此有什么支持吗

当然可以:

其中一些是符号链接,但不是全部。如果需要非符号链接计数:

for j in $(dpkg -L libc6 | grep '\.so' ); do [[ -L $j ]] || echo $j; done | wc -l
279

对于包含本机代码的Python模块,典型的方法是在目标平台上编译它们。但如果我想重新发布一个具有给定依赖项的Python模块呢?这通常是如何做到的?相当辛苦,由特定发行版的包装系统完成。使用
pip
easy install
拉入的Python模块通常要求系统上存在特定的本机库,通常还包括该库的标题。对。我的意思是:如何让我的特定文件编译运行,这样我就可以将必要的文件(即重新分发)提供给其他人?无论我是否在使用打包系统——Python不应该崩溃,也不应该在尝试加载模块时抱怨。我的问题可能没有Linux相关的Python那么具体。如果一个程序(Python)依赖于特定版本的Glibc,并希望动态加载依赖于不同版本的Glibc(我的模块)的符号,那么解决方法是什么?为什么提供更新版本的Glibc不起作用呢?我假设Glibc 2.15和2.17之间的ABI兼容性没有中断?“解决方案很简单……”——这不是一个可靠工作的解决方案。这很公平,但我应该能够假设,如果我使用这些函数中的任何一个,
libnss*。那么
将使用
ldd Foo.so
列出,然后复制到
,对吗?正如在第一篇文章中所写,我正在将所有依赖项复制到
“如果我使用了这些函数中的任何一个,libnss*.so将使用ldd Foo.so列出,并因此复制到,对吗?”--不,这是错误的。这些库是动态加载的,不直接链接到。Hmmm。。。那太愚蠢了。有什么方法可以可靠地找出所有依赖项吗?在你的链接帖子中,glibc由200多个库组成,对此有什么支持吗?我会认为这是非常糟糕的设计。谢谢,这非常有帮助!遗憾的是,LD_DEBUG=libs输出似乎不太适合自动脚本处理,但另一方面,至少在我的例子中,没有其他依赖项。
dpkg -L libc6 | grep '\.so' | wc -l
300
for j in $(dpkg -L libc6 | grep '\.so' ); do [[ -L $j ]] || echo $j; done | wc -l
279