[英]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.