在与可执行文件相同的目录中找不到.so?


45

我有一个需要libtest.so动态链接的可执行文件,因此我将它们放在同一目录中,然后:

cd path_to_dir
./binary

但是得到这个:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

如何无法找到libtest.so与可执行文件本身已经在同一目录中的文件?

Answers:


25

除非明确将其定向到via,否则加载器永远不会在当前目录中检查共享对象$LD_LIBRARY_PATH。有关ld.so(8)更多详细信息,请参见手册页。


echo $LD_LIBRARY_PATH在我的机器上是空的:(
linuxer


2
它指定其他目录,供加载程序查找库。
伊格纳西奥·巴斯克斯

1
* nix中的路径用冒号(:)分隔,而不是分号。
伊格纳西奥·巴斯克斯

3
LD_LIBRARY_PATH通常在生产中是一个糟糕的选择。这对于快速黑客攻击很有用,例如在运行单元测试时帮助卸载的二进制文件找到共享库(例如./configure; make; make check)。构建二进制文件时,可以将库放在标准位置(在/etc/ld.so.conf中列出),也可以将-R标志传递给链接程序,以使二进制文件知道在哪里查找。
automatthias 2012年

57

您可以设置LD_LIBRARY_PATH来让动态链接程序知道在哪里查看,但还有更好的选择。您可以将共享库放在标准位置之一中,有关这些位置的列表,请参见/etc/ld.so.conf(在Linux上)和/usr/bin/crle(在Solaris上)

您可以-R <path>在构建二进制文件时传递给链接器,该链接器将添加<path>到为共享库扫描的目录列表中。这是一个例子。首先,显示问题:

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

你好ç:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

Makefile(必须使用标签):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

让我们运行它:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

如何解决?添加-R <path>到链接器标志(此处通过设置LDFLAGS)。

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

查看二进制文件,您可以看到它需要libtest.so.0

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

除了标准位置外,二进制文件还将在指定目录中查找其库:

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

如果希望二进制文件在当前目录中查找,则可以将RPATH设置为$ORIGIN。这有点棘手,因为您需要确保make不会解释美元符号。这是一种实现方法:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!

1
如果未使用make,例如手动调用时g++,请尝试-Wl,-rpath='$ORIGIN'(请注意单引号)以防止$ORIGIN扩展为空字符串。
Morpork

14

要从与可执行文件相同的目录中加载共享对象,只需执行以下命令:

$ LD_LIBRARY_PATH=. ./binary

注意:它不会修改系统的LD_LIBRARY_PATH变量。所做的更改只会影响程序的执行,也只会影响程序的执行。



3

对于使用CMake进行构建的任何人,可以将设置CMAKE_EXE_LINKER_FLAGS为以下内容:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")

这将正确传播所有构建类型(例如,Debug,Release等)的链接器标志,以便首先在当前工作目录中查找.so文件。


0

动态链接器将决定在哪里寻找库。对于Linux,动态链接程序通常是GNU ld.so(或出于兼容性原因而通常表现相同的替代程序。

要引用维基百科的话:

GNU C库的动态链接器在以下位置搜索共享库:

  1. DT_RPATH二进制文件的动态部分属性中的(用冒号分隔)路径(如果存在)并且该DT_RUNPATH属性不存在。
  2. LD_LIBRARY_PATH除非可执行文件是setuid/ setgid二进制文件,否则环境变量中的(用冒号分隔)路径将被忽略。LD_LIBRARY_PATH可以通过使用选项--library-path(例如/lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram)来调用动态链接器来覆盖它。
  3. DT_RUNPATH二进制文件的动态部分属性中的(用冒号分隔)路径(如果存在)。
  4. 基于ldconfig高速缓存文件(通常位于/etc/ld.so.cache)进行查找,该文件包含先前在增强库路径(由设置/etc/ld.so.conf)中找到的候选库的已编译列表 。但是,如果二进制文件已通过-z nodefaultlib链接器选项链接,则会跳过默认库路径中的库。
  5. 在受信任的默认路径中/lib,然后/usr/lib。如果二进制文件是使用-z nodefaultlib链接器选项链接的,则将跳过此步骤。

资料来源:https : //en.wikipedia.org/wiki/Rpath

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.