makefile混淆链接器库路径
我已经编程了一段时间,但我仍然不完全理解链接器的行为。makefile混淆链接器库路径
例如,今天我下载并安装了一个我想在我的Linux应用程序中使用的库。 (这是Xerces - 用于解析XML文件)。
我创建了一个makefile,并在我的命令中为它指定了.so和.a文件的路径:-L/usr/local/lib并且还告诉它要包含的库的名称:-lxerces-c- 3.1。
我的应用程序编译得很好,但在运行时失败,出现“无法打开共享对象文件libxerces-c-3.1.so”。为什么会这样,当我正确地给它的路径和名称在生成文件?
然后,我将库路径添加到我的.bashrc文件中的LD_LIBRARY_PATH变量,然后它工作。这很好,但如果我现在删除我的makefile中的库的路径,甚至不包括库的名称,它仍然有效。
我很困惑这是怎么回事。如何通过将路径分配给LD_LIBRARY_PATH变量来找到正确的库,并且仅在我这样做时才能正常工作?我已经读过其他地方甚至不使用LD_LIBRARY_PATH。
我很感激任何答案。这个问题有点长,希望不是脱离主题,但我希望别人也可以从中学习。谢谢
这里没有神秘感。链接器(您调用的用于创建可执行文件的目录,例如ld
)和运行时链接程序(在执行程序时负责加载共享库的链接程序(例如,ld.so
))的默认库路径是不同的。运行时链接程序使用LD_LIBRARY_PATH,而链接程序使用在构建ld时配置的任何内容。
在你的情况下,看起来像/usr/local/lib
是一个部分,但不是另一个。
谢谢你。运行时链接程序如何知道链接tho的库? LD_LIBRARY_PATH只有库目录的路径,并且没有命名实际库 – Engineer999
@ Engineer999,因为可执行文件中所需的实际.so所需的实际名称.so已被记录在可执行文件中。你可以运行'ldd '来查看哪一个。这是您的文件需求,以及运行时链接程序可以在给定环境中找到它们的位置 – SergeyA
当我甚至在编译时没有提供信息时,我的可执行文件如何知道.so,只有头文件包含在内? – Engineer999
用-Wl,-rpath=/usr/local/lib
编译程序。这样,您将添加在/ usr/local/lib目录到运行程序的库搜索补丁,你会不会需要LD_LIBRARY_PATH
警告:由于现代动态链接程序会考虑rpath
为废弃还可以runpath
设置(它取代它)通过指定-Wl,-rpath=/usr/local/lib,--enable-new-dtags
如果你使用静态链接,你所要做的就是告诉链接器你的库在编译/链接时的位置。该库(或尽可能多的)被复制到您的可执行文件中,并且您的可执行文件是独立的。
但由于各种原因,现在我们通常使用动态链接,而不是静态链接。通过动态链接,你必须告诉链接器在编译/链接时间和哪里可以找到库,动态链接器(ld.so
)必须能够在运行时找到库。
如果图书馆在标准地点之一(/lib
,/usr/lib
等)没有问题。但是,如果您在非标准位置链接到库,则通常必须将该非标准位置添加到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)如果您需要安装在一个不寻常的位置库,你可以添加一个创建/etc/ld.so.conf.d
包含,例如下一个文件(文件yaml.conf):
# yaml default configuration
/opt/yaml/lib
在系统启动时,加载器读取此目录中的所有文件并将路径附加到加载器路径。如果您对此目录进行了修改,则可以使用ldconfig
命令使加载程序重新处理/etc/ld.so.con.d
。注:我知道这适用于GNU/Linux的centOS和Ubuntu版本 - 不能在其他版本上进行权威性的说明。
谢谢。非常有帮助 – Engineer999
这可能是其他地方的问题,但可执行文件如何决定是使用提供的静态库还是共享库? – Engineer999
@ Engineer999应用程序不做任何决定。运行时链接程序的确如此。使用静态链接库(在编译时),根本不会为该库完成共享对象的运行时链接。 –
我建议从你的makefile文件中添加最小的一组规则来演示这个问题,最多10行。现在,我们仍然在猜测makefile中的内容,以及是否可以提供最佳的改进。祝你好运。 – shellter
看看这个帖子:http://*.com/questions/1904990/what-is-the-difference-between-ld-library-path-and-l-at-link-time,其中类似的问题已经回答 –
'-L'和'LD_LIBRARY_PATH'影响两个非常*不同的(但相关的)操作。编译时链接和运行时链接。 –