为什么我必须在运行程序之前设置 LD_LIBRARY_PATH,即使我已经在编译阶段链接了库位置?

Luk*_*vis 2 compiling libraries c++ fortran

我正在使用make. 该模型具有Makefile通过类似于-L/lib1 -L/lib2. 但是当我尝试运行该模型时,它会失败,除非我还确保环境变量

export LD_LIBRARY_PATH=/lib1:/lib2
Run Code Online (Sandbox Code Playgroud)

并指向完全相同的库。这对我来说似乎是多余的。

这里的幕后会发生什么?为什么我必须在编译之前和执行之前有效地指定库的位置?

这可能是一个愚蠢的问题;我对编译为机器代码不是很有经验,通常只使用脚本语言。

小智 6

尽管每个人都在将源代码转换为可执行文件的口语意义上使用编译,但从技术上讲,它是相当长的管道中的一个步骤:

  1. 输入文件通过预处理器运行,生成单个翻译单元。
  2. 预处理器的输出被编译为汇编。
  3. 汇编器将其作为输入并输出目标文件。
  4. 链接器将目标文件拼接在一起以生成可执行文件。

[ 迂腐,没有要求这些步骤是分开的,现代编译器通常将它们结合起来以提高效率。]

我们关注的是链接步骤,它将您的代码与标准系统库相结合。链接器将对象从静态库直接复制到可执行文件中。但是,对于共享库,它仅提供对库的引用。

共享库有很多优点。您可以在不重新编译程序的情况下更新它们,并且它们使用更少的内存,因为程序可以共享公共代码。它们还有一个明显的缺点,即代码不在可执行文件中。

解决方案是动态加载器,它负责在运行时解析所有共享库引用。加载器自动运行;这样做的指令是链接器在可执行文件中包含的一件事。当然,这以加载程序可以找到库为前提。

系统库位于标准目录中,这很简单。如果不是这种情况,加载程序将搜索 LD_LIBRARY_PATH。为什么链接器不只是将路径放在可执行文件中?因为那样你将无法移动或更改库。

实际上,您也无法真正移动可执行文件,因为该库位于系统搜索路径之外。如果它只在库位于 ~luke/lib 时运行,那么你不能把它交给 joe,除非他可以读取你的文件。如果你换了一份新工作,乔会很糟糕。

仅供参考,它也会以无数其他方式吸收。如果您只能在编译时指定库位置等,那么调试将成为永恒的噩梦。