简体   繁体   English

Makefile混乱中的链接器库路径

[英]Linker library path in makefile confusion

I've been programming a while but I still don't fully understand how the linker behaves. 我已经编程了一段时间,但我仍然不完全了解链接器的行为。

For example, today I downloaded and installed a library that I want to use in my application in Linux. 例如,今天我下载并安装了要在Linux中的应用程序中使用的库。 (It was Xerces - for parsing XML files). (它是Xerces-用于解析XML文件)。

I created a makefile and gave it the path to the .so and .a files in my command : -L/usr/local/lib and also told it the name of the library to include : -lxerces-c-3.1. 我创建了一个makefile,并在命令:-L / usr / local / lib中提供了指向.so和.a文件的路径,并告诉它要包含的库名称:-lxerces-c-3.1。

My application compiled fine but failed during runtime with "cannot open shared object file libxerces-c-3.1.so". 我的应用程序编译良好,但在运行时失败,并显示“无法打开共享库文件libxerces-c-3.1.so”。 Why would this be the case, when I properly give it the path and name in the makefile? 当我在makefile中正确给它提供路径和名称时,为什么会这样呢?

I then added the library path to the LD_LIBRARY_PATH variable in my .bashrc file and then it worked. 然后,我将库路径添加到.bashrc文件中的LD_LIBRARY_PATH变量中,然后它起作用了。 That's fine , but if I now remove the path to the library in my makefile and don't even include the name of the library , it still works. 很好,但是如果我现在在我的makefile中删除该库的路径,甚至不包含该库的名称,它仍然可以工作。

I'm confused as to what is going on here. 我对这里发生的事情感到困惑。 How can it still find the correct library just by assigning the path to the LD_LIBRARY_PATH variable and will only work if I do so? 仅通过将路径分配给LD_LIBRARY_PATH变量,它如何仍能找到正确的库,并且仅在我这样做时才有效? I have read elsewhere to not even use LD_LIBRARY_PATH. 我在其他地方读过甚至没有使用LD_LIBRARY_PATH。

I appreciate any answer for this. 我对此表示感谢。 The question is a bit long and hopefully not off-topic but I hope others can learn from it too. 这个问题有点长,希望不会成为题外话,但我希望其他人也可以从中学习。 Thanks 谢谢

compilation and running are different things. 编译和运行是不同的事情。 :) :)

1) A make file contains rules on how to build your application. 1)生成文件包含有关如何构建应用程序的规则。 So when you write a rule like: 因此,当您编写如下规则时:

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

You are passing options to the linker. 您正在将选项传递给链接器。 The -L option tells the linker to add additional libraries (in this case '/usr/local/lib') to the linker's search path. -L选项告诉链接器将其他库(在本例中为“ / usr / local / lib”)添加到链接器的搜索路径。 The -l option names the library that should be linked in. -l选项为应该链接的库命名。

2) When you go to run an executable, the loader needs to find all the required libraries. 2)当您运行可执行文件时,加载器需要找到所有必需的库。 For example, on a Linux system you can use the ldd command to see what shared libraries are used. 例如,在Linux系统上,您可以使用ldd命令查看使用了哪些共享库。 For example on my system: 例如在我的系统上:

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)

From this, you can see the name of the library that is linked to the left of the '=>' token, and the path to the library to the right. 由此,您可以看到链接到'=>'标记左侧的库的名称以及右侧的库路径。 If a library is not found it will show up as missing. 如果未找到库,它将显示为丢失。

Now in your case, you were able to successfully compile and link your program due to giving the path and library name to use. 现在,根据您的情况,由于提供了要使用的路径和库名称,因此您能够成功编译并链接程序。 You were not able to run the program due to the loader not being able to find the library at run time. 由于加载程序无法在运行时找到库,因此无法运行程序。

You have several options here: 您在这里有几种选择:

1) you can move the library in a directory that is in the loaders search path. 1)您可以将库移动到装载程序搜索路径中的目录中。

2) you can modify LD_LIBRARY_PATH which adds additional directories to the loaders search path. 2)您可以修改LD_LIBRARY_PATH ,从而将其他目录添加到装载程序搜索路径。 Additionally, the directories specified in LD_LIBRARY_PATH will be passed to the linker (it will be appended after all -L flags). 此外,在LD_LIBRARY_PATH指定的目录将传递到链接器(它将附加在所有-L标志之后)。 You do need to be careful with this, as if you set it globally (say in .bashrc ), then it will effect all compilations that you do. 您确实需要注意这一点,就像您对其进行了全局设置(例如.bashrc )一样,它将影响您所做的所有编译。 You may or may not want this behavior. 您可能会或可能不会想要此行为。

3) As others have specified you can use -Wl,rpath=.... , but it is deprecated, and I rarely use it. 3)正如其他人所指定的,您可以使用-Wl,rpath=.... ,但已弃用,并且我很少使用它。

4) If you need the library installed in an unusual location, you can add a create a file under /etc/ld.so.conf.d that contains, for example (file is yaml.conf): 4)如果需要将库安装在不寻常的位置,则可以在/etc/ld.so.conf.d下添加一个创建文件,该文件包含例如(文件为yaml.conf):

# yaml default configuration
/opt/yaml/lib

At system boot, the loader reads all the files in this directory and appends the paths to the loader path. 在系统启动时,加载程序读取该目录中的所有文件,并将路径附加到加载程序路径。 If you make a modification to this directory you can use the ldconfig command to cause the loader to reprocess /etc/ld.so.con.d . 如果您对此目录进行了修改,则可以使用ldconfig命令使加载程序重新处理/etc/ld.so.con.d NB I know this works on centOS and Ubuntu flavors of GNU/Linux - can't speak authoritatively on other flavors. 注意:我知道这适用于centOS和GNU / Linux的Ubuntu版本-不能权威地谈论其他版本。

Compile your program with -Wl,-rpath=/usr/local/lib . 使用-Wl,-rpath=/usr/local/lib编译程序。 This way you'll add /usr/local/lib to runtime library search patch of your program and you won't need the LD_LIBRARY_PATH 这样,您将/ usr / local / lib添加到程序的运行时库搜索补丁中,并且不需要LD_LIBRARY_PATH
Warning : since modern dynamic linkers consider rpath as deprecated you can set also runpath (which supersedes it) by specifying -Wl,-rpath=/usr/local/lib,--enable-new-dtags 警告 :由于现代动态链接器认为rpath已弃用,因此您还可以通过指定runpath -Wl,-rpath=/usr/local/lib,--enable-new-dtags来设置runpath (取代它)

There is no mystery here. 这里没有谜。 Default library paths for linker (one you call to make your executable file, for example, ld ) and runtime linker (one which is responsible for loading shared libraries when you execute your program, for example, ld.so ) are different. 链接器(调用该文件以生成可执行文件,例如ld )和运行时链接器(负责在执行程序时加载共享库的一个,例如ld.so )的默认库路径是不同的。 Runtime linker uses LD_LIBRARY_PATH, while linker uses whatever was configured when ld was build. 运行时链接程序使用LD_LIBRARY_PATH,而链接程序使用构建ld时配置的内容。

In your case, looks like /usr/local/lib is part of one, but not another. 在您的情况下, /usr/local/lib似乎是其中一部分,而不是另一部分。

If you're using static linking, all you have to do is tell the linker where your library is at compile/link time. 如果您使用的是静态链接,则只需告诉链接器在编译/链接时库在哪里。 The library (or as much of it as is necessary) gets copied into your executable, and your executable is standalone. 该库(或必要时,尽可能多的库)被复制到可执行文件中,并且可执行文件是独立的。

But for various reasons, these days we generally use dynamic linking, not static linking. 但是由于种种原因,如今,我们通常使用动态链接,而不是静态链接。 With dynamic linking, you have to tell the linker where to find the library at compile/link time, and the dynamic linker ( ld.so ) has to be able to find the library at run time. 使用动态链接,您必须告诉链接器在编译/链接时在哪里可以找到库, 动态链接器( ld.so )必须能够在运行时找到该库。

If the library was in one of the standard places ( /lib , /usr/lib , etc.) there's no problem. 如果该库位于标准位置之一( /lib/usr/lib等)中,则没有问题。 But if you linked against a library in a nonstandard place, in general, you have to add that nonstandard place to your LD_LIBRARY_PATH, so that the runtime linker will always be able to find it. 但是,如果通常在非标准位置链接到库,则必须将该非标准位置添加到LD_LIBRARY_PATH中,以便运行时链接程序始终能够找到它。

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

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