生成文件混淆中的链接器库路径

Eng*_*999 1 c c++ linux linker makefile

我已经编程了一段时间,但我仍然不完全了解链接器的行为。

例如,今天我下载并安装了一个库,我想在我的 Linux 应用程序中使用它。(它是 Xerces - 用于解析 XML 文件)。

我创建了一个 makefile 并在我的命令中为它提供了 .so 和 .a 文件的路径:-L/usr/local/lib 并告诉它要包含的库的名称:-lxerces-c-3.1。

我的应用程序编译正常但在运行时失败,“无法打开共享对象文件 libxerces-c-3.1.so”。当我在 makefile 中正确地给它路径和名称时,为什么会出现这种情况?

然后我将库路径添加到 .bashrc 文件中的 LD_LIBRARY_PATH 变量,然后它就可以工作了。很好,但是如果我现在在我的 makefile 中删除库的路径并且甚至不包括库的名称,它仍然可以工作。

我对这里发生的事情感到困惑。它如何仅通过将路径分配给 LD_LIBRARY_PATH 变量来找到正确的库,并且只有在我这样做时才能工作?我在别处读过,甚至不使用 LD_LIBRARY_PATH。

我很感激对此的任何回答。问题有点长,希望不会偏离主题,但我希望其他人也能从中学习。谢谢

thu*_*zas 5

编译和运行是不同的东西。:)

1) make 文件包含有关如何构建应用程序的规则。因此,当您编写如下规则时:

    -L/usr/local/lib -lxerces-c-3.1
Run Code Online (Sandbox Code Playgroud)

您正在将选项传递给链接器。该-L选项告诉链接器将其他库(在本例中为“/usr/local/lib”)添加到链接器的搜索路径。该-l选项命名应该链接的库。

2)当你去运行一个可执行文件时,加载器需要找到所有需要的库。例如,在 Linux 系统上,您可以使用 ldd 命令查看使用了哪些共享库。例如在我的系统上:

ldd FEParser
    linux-vdso.so.1 =>  (0x00007ffcdc7c9000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f835b143000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f835ae3d000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f835ac27000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f835a862000)
/lib64/ld-linux-x86-64.so.2 (0x00007f835b447000)
Run Code Online (Sandbox Code Playgroud)

从这里,您可以看到链接到“=>”标记左侧的库的名称,以及右侧库的路径。如果未找到库,它将显示为丢失。

现在,在您的情况下,由于提供了要使用的路径和库名称,您能够成功编译和链接您的程序。由于加载程序在运行时无法找到库,您无法运行程序。

您在此处有多种选择:

1)您可以将库移动到加载程序搜索路径中的目录中。

2)您可以修改LD_LIBRARY_PATH将其他目录添加到加载程序搜索路径的内容。此外,指定的目录LD_LIBRARY_PATH将传递给链接器(它将附加在所有-L标志之后)。你确实需要小心这一点,就像你全局设置它一样(比如在.bashrc),那么它会影响你所做的所有编译。您可能想要也可能不想要这种行为。

3)正如其他人指定的那样,您可以使用-Wl,rpath=....,但它已被弃用,我很少使用它。

4)如果你需要把库安装在一个不寻常的位置,你可以添加一个/etc/ld.so.conf.d包含的创建文件,例如(文件是yaml.conf):

# yaml default configuration
/opt/yaml/lib
Run Code Online (Sandbox Code Playgroud)

在系统启动时,加载程序读取此目录中的所有文件并将路径附加到加载程序路径。如果对该目录进行修改,则可以使用该ldconfig命令使加载程序重新处理/etc/ld.so.con.d。注意,我知道这适用于 GNU/Linux 的 centOS 和 Ubuntu 风格 - 不能对其他风格发表权威性言论。