繁体   English   中英

Makefile混乱中的链接器库路径

[英]Linker library path in makefile confusion

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

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

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

我的应用程序编译良好,但在运行时失败,并显示“无法打开共享库文件libxerces-c-3.1.so”。 当我在makefile中正确给它提供路径和名称时,为什么会这样呢?

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

我对这里发生的事情感到困惑。 仅通过将路径分配给LD_LIBRARY_PATH变量,它如何仍能找到正确的库,并且仅在我这样做时才有效? 我在其他地方读过甚至没有使用LD_LIBRARY_PATH。

我对此表示感谢。 这个问题有点长,希望不会成为题外话,但我希望其他人也可以从中学习。 谢谢

编译和运行是不同的事情。 :)

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

    -L/usr/local/lib -lxerces-c-3.1

您正在将选项传递给链接器。 -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)

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

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

您在这里有几种选择:

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

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

使用-Wl,-rpath=/usr/local/lib编译程序。 这样,您将/ usr / local / lib添加到程序的运行时库搜索补丁中,并且不需要LD_LIBRARY_PATH
警告 :由于现代动态链接器认为rpath已弃用,因此您还可以通过指定runpath -Wl,-rpath=/usr/local/lib,--enable-new-dtags来设置runpath (取代它)

这里没有谜。 链接器(调用该文件以生成可执行文件,例如ld )和运行时链接器(负责在执行程序时加载共享库的一个,例如ld.so )的默认库路径是不同的。 运行时链接程序使用LD_LIBRARY_PATH,而链接程序使用构建ld时配置的内容。

在您的情况下, /usr/local/lib似乎是其中一部分,而不是另一部分。

如果您使用的是静态链接,则只需告诉链接器在编译/链接时库在哪里。 该库(或必要时,尽可能多的库)被复制到可执行文件中,并且可执行文件是独立的。

但是由于种种原因,如今,我们通常使用动态链接,而不是静态链接。 使用动态链接,您必须告诉链接器在编译/链接时在哪里可以找到库, 动态链接器( ld.so )必须能够在运行时找到该库。

如果该库位于标准位置之一( /lib/usr/lib等)中,则没有问题。 但是,如果通常在非标准位置链接到库,则必须将该非标准位置添加到LD_LIBRARY_PATH中,以便运行时链接程序始终能够找到它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM