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。
我很感激任何答案。 问题有点长,希望不是偏离主题,但我希望其他人也可以从中学习。 谢谢
编译和运行是不同的事情。 🙂
1)make文件包含有关如何构建应用程序的规则。 所以当你写一条规则时:
-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)如果您需要在exception位置安装库,可以在/etc/ld.so.conf.d
下添加一个包含的文件,例如(file is yaml.conf):
# yaml default configuration /opt/yaml/lib
在系统引导时,加载程序读取此目录中的所有文件,并将路径附加到加载程序路径。 如果对此目录进行了修改,则可以使用ldconfig
命令使加载程序重新处理/etc/ld.so.con.d
。 NB我知道这适用于GNOS / Linux的centOS和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,以便运行时链接程序始终能够找到它。