C ++链接器缺少运行时的库(SONAME行为) [英] C++ linker missing library when running (SONAME behavior)

查看:445
本文介绍了C ++链接器缺少运行时的库(SONAME行为)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个程序,使用两个共享库(我编译),并放置如下:

  home_directory_where_I_compile_and_run_everything 
- > /lib/libjson_linux-gcc-4.4.6_libmt.so
- > /lib/libre2.so.0
pre>

当我编译程序时,我将这些库的相对位置传递给链接器,例如:

  g ++ ...... stuff ........ my_program.cc lib / libjson_linux-gcc-4.4.6_libmt.so lib / libre2.so.0 

它编译正常,但是当运行程序时,它无法找到libre2.so,如果我检查它ldd,这里会发生什么:

  .... 
lib / libjson_linux-gcc-4.4.6_libmt.so 0x00007f62906bc000)
libre2.so.0 =>未找到
....

显然,它确认libjson上的路径relative,但它不会在libre2.so.0上修改它(它修剪所有的路径,只剩下libre2.so.0)



有人可以告诉我为什么这发生了吗?



此外,有没有办法通过g ++参数修改这个?



/ p>

* UPDATE * Whoa检查一下!
我改变了libre2.so.0的名字为stuff.so,然后试图编译本质上是这样:

  g ++ ...... stuff ........ my_program.cc lib / libjson_linux-gcc-4.4.6_libmt.so lib / stuff.so 

它失败了;不仅它失败,它失败,因为它找不到libre2.so.0。



为什么?


$ b b

* UPDATE#2 *



输出 readelf -d the_program.o

  0x0000000000000001(NEEDED)共享库:[lib / libjson_linux-gcc-4.4.6_libmt.so] 
0x0000000000000001(NEEDED)共享库:[libre2.so.0]

现在,



* UPDATE#3 *



如@troubadour发现:


使用具有DT_SONAME字段的共享对象,则当可执行文件运行时,动态链接器将尝试加载由DT_SONAME字段指定的共享对象,而不是使用给链接器的文件名。


这就是为什么它适用于libjson .....所以没有libre2.so.0。 (libjson .....所以没有一个条目为SONAME)。



我终于找到了我正在寻找的确切问题:



有没有办法告诉gcc链接器忽略共享库文件上的SONAME条目,并链接到特定的文件路径? >

解决方案

我会回答你的问题的第二部分,即为什么重命名libre2.so.0没有做你想要的。 / p>

当您运行可执行文件时,传递给链接器的文件名是不相关的(除非您不能提供 -soname 当建库时 - 见下面的第二个编辑)。依赖取自所谓的soname。如果在库上运行 readelf 命令,您可以确定它的soname例如

  readelf -d libre2.so.0 | grep SONAME 

重命名文件无关紧要。上面的命令的结果仍然会给你相同的声音,因此程序仍然找不到libre2.so.0的原因。



你的问题的一部分,这取决于图书馆是否有一个 RPATH RUNPATH 内置于他们和/您的 LD_LIBRARY_PATH 环境变量的内容为。这些是运行时链接器(ld.so)将用来查找共享库的东西。尝试

  man ld.so 

更多信息。



由于你自己编译库,你会知道他们是否使用 -rpath -runpath 选项。或者,再次使用 readelf 例如

  readelf -d libre2.so .0 | grep RPATH 
readelf -d libre2.so.0 | grep RUNPATH

我怀疑上面的两个命令什么都不返回。



我的猜测是你在你的 LD_LIBRARY_PATH 中有当前目录,这将允许运行时链接器找到lib / libjson_linux-gcc- 4.4.6_libmt.so但不是libre2.so.0。我注意到您已回复我对您的问题的意见,表示您的 LD_LIBRARY_PATH 为空。这很奇怪。



也许你在libame的soname上得到了前缀lib /?即为SONAME返回 readelf 命令

  lib / libjson_linux- gcc-4.4.6_libmt.so 

而不只是

  libjson_linux-gcc-4.4.6_libmt.so 

另外,通过运行

检查程序在soname方面的需求。

  readelf -d my_progam | grep需要

也许lib /前缀是因为你传递给gcc的方式。如果是这样,那么如果你使用由@enobayram给出的gcc命令,它将调整播放域,即它也将无法找到libjson。



首先要建立的是不是为什么不是找到libre2.so.0,而是如何管理以找到libjson。如果你尝试从一个不同的目录运行可执行文件它仍然工作或现在失败为libjson太?



编辑



一个在Fedora论坛上发帖表明Fedora版本的ld。所以有当前目录作为内置的搜索路径。我没有能够验证这一点,但它会解释为什么你拾起所有的图书馆,因为所有其他的东西ld.so用途不在你的情况。



编辑2



从我系统上的ld手册页



< >

-soname = name



在创建ELF共享对象时,将内部DT_SONAME字段
设置为指定的名称。当一个可执行文件与具有DT_SONAME字段的共享
对象链接时,当可执行文件运行
时,动态链接器将尝试加载由
指定的共享对象DT_SONAME字段,而不是使用给予
链接器的文件名。



版权所有(c)1991,1992,1993,1994,1995,1996,1997,1998,1999 ,
2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free
软件基金会。



被授予根据GNU自由文档许可证1.3版或
自由软件基金会发布的任何更新版本的条款复制,分发和/或修改此文档
;没有
不变部分,没有封面文本,没有背盖
文本。


因此,理论在您的评论是正确的。如果在构建库时没有明确指定 -soname ,则在共享对象中不存在SONAME,并且可执行文件中的NEEDED字段仅仅具有给链接器的文件名,在你的情况下,包含领先的lib /\".


I've made a program that uses two shared libraries (which I compiled) and are placed like this:

/home_directory_where_I_compile_and_run_everything
-->/lib/libjson_linux-gcc-4.4.6_libmt.so
-->/lib/libre2.so.0

When I compile my program I pass the relative location of those libraries to the linker, like this:

g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/libre2.so.0

And it compiles fine, however when running the program it fails to find libre2.so, and if I inspect it with ldd, here's what happens:

....
lib/libjson_linux-gcc-4.4.6_libmt.so (0x00007f62906bc000)
libre2.so.0 => not found
....

Apparently, it does acknowledge that the path on libjson is relative, but it doesn't do that on libre2.so.0 (it trims all the path and just leaves libre2.so.0)

Can someone tell me why this happens?

Also, is there a way to modify this via a g++ argument?

Best.

* UPDATE * Whoa check this out! I've changed the name of libre2.so.0 to stuff.so, and then tried to compile essentially the same like this:

g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so

And it fails anyways; not only it does fail, it fails because it can't find "libre2.so.0".

Whyyy?

* UPDATE # 2 *

Output for readelf -d the_program.o

0x0000000000000001 (NEEDED)             Shared library: [lib/libjson_linux-gcc-4.4.6_libmt.so]
0x0000000000000001 (NEEDED)             Shared library: [libre2.so.0]

Now, if I could just make that [libre2.so.0] to be [lib/libre2.so.0] instead it would be fine.

* UPDATE # 3 *

As @troubadour found out:

When an executable is linked with a shared object which has a DT_SONAME field, then when the executable is run the dynamic linker will attempt to load the shared object specified by the DT_SONAME field rather than the using the file name given to the linker.

That's why it works with libjson.....so and not with libre2.so.0. (libjson.....so does not have an entry for SONAME).

And I finally found the exact question for what I'm looking for:

Is there any way to tell the gcc linker to ignore the SONAME entries on a shared library file and link instead to the specific file path?

解决方案

I'll answer the second part of your question first i.e. why renaming libre2.so.0 didn't do what you expected.

The file name that you pass to the linker is irrelevant when you run the executable (unless you fail to supply -soname when building the library - see second edit below). The dependency is taken from what is called the "soname". If you run the readelf command on your library you can determine its soname eg.

readelf -d libre2.so.0 | grep SONAME

It doesn't matter if you rename the file. The result of the above command will still give you the same soname, hence the reason the program still failed to find "libre2.so.0".

As to the original part of your question it all hinges on whether the libraries have an RPATH or RUNPATH built in to them and/or what the content of your LD_LIBRARY_PATH environment variable is. These are the things the run-time linker (ld.so) will use to find the shared libraries. Try

man ld.so

for more information.

Since you built the libraries yourself you will know whether or not they used the -rpath or -runpath options at the final linking stage. Alternatively, use readelf again eg.

readelf -d libre2.so.0 | grep RPATH
readelf -d libre2.so.0 | grep RUNPATH

I suspect the above two commands will return nothing.

My guess was going to be that you have the current directory in your LD_LIBRARY_PATH which would allow the run-time linker to find lib/libjson_linux-gcc-4.4.6_libmt.so but not libre2.so.0. I notice that you've replied to my comment on your question to say that your LD_LIBRARY_PATH is empty. That's odd.

Perhaps you've somehow got the prefix "lib/" on the soname for libjson? i.e. did the readelf command for the SONAME return

lib/libjson_linux-gcc-4.4.6_libmt.so

rather than just

libjson_linux-gcc-4.4.6_libmt.so

Also, check what the program needs in terms of soname by running

readelf -d my_progam | grep NEEDED

Perhaps the "lib/" prefix is in there because of the way you passed it to gcc. If so then if you use the gcc command given by @enobayram then it will level the playing field i.e. it will fail to find libjson too.

The first thing to establish is not why it is not finding libre2.so.0 but how it is managing to find libjson. If you try running your executable from a different directory does it still work or does it now fail for libjson too? Alternatively, if you copy libre2.so.0 to be beside your executable does that change anything?

Edit

A posting on the Fedora Forum suggest that the Fedora version of ld.so has the current directory as a built-in search path. I haven't been able to verify this though but it would explain why you are picking up any libraries at all given that all the other things ld.so uses are absent on your case.

Edit 2

From the ld man page on my system

-soname=name

When creating an ELF shared object, set the internal DT_SONAME field to the specified name. When an executable is linked with a shared object which has a DT_SONAME field, then when the executable is run the dynamic linker will attempt to load the shared object specified by the DT_SONAME field rather than the using the file name given to the linker.

Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back- Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

So, the theory in your comment is correct. If no -soname is explicitly specified when the library is built then no SONAME exists in the shared object and the NEEDED field in the executable simply has the file name given to the linker which, in your case, contained the leading "lib/".

这篇关于C ++链接器缺少运行时的库(SONAME行为)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆