参见英文答案 > Where do executables look for shared objects at runtime? 4个
我正在使用make编译模型;该模型有一个Makefile,它通过看起来像-L / lib1 -L / lib2的标志将源代码与依赖库连接起来.但是当我尝试运行该模型时,它会失败,除非我也确保环境变量
export LD_LIBRARY_PATH=/lib1:/lib2
并指向完全相同的库.这对我来说似乎是多余的.
引擎盖下有什么可以发生的?为什么我有效地必须在编译之前和执行之前指定库的位置?
这可能是一个愚蠢的问题;我不是很熟悉编译机器代码,通常只使用脚本语言.
解决方法:
尽管每个人都在将源代码转换为可执行文件的口语意义上使用编译,但从技术上讲,它只是在一个相当长的管道中的一个步骤:
>输入文件通过预处理器运行,从而生成单个翻译单元.
>预处理器的输出编译为汇编.
>汇编程序将输入作为输入输出目标文件.
>链接器将目标文件拼接在一起以生成可执行文件.
[要迂腐,不要求步骤分开,现代编译器通常将它们结合起来以提高效率. ]
我们关注的是链接步骤,它将您的代码与标准系统库相结合.链接器将对象从静态库直接复制到可执行文件中.但是,对于共享库,它仅提供对库的引用.
共享库有很多优点.您可以更新它们而无需重新编译程序,并且它们使用较少的内存,因为程序可以共享公共代码.它们也有明显的缺点,即代码不在可执行文件中.
解决方案是动态加载器,它负责在运行时解析所有共享库引用.装载机自动运行;这样做的说明是链接器在可执行文件中包含的一件事.当然这预示着加载器可以找到库.
系统库位于标准目录中,这很简单.如果不是这种情况,加载程序将搜索LD_LIBRARY_PATH.为什么链接器只是将路径放在可执行文件中?因为那时你将无法移动或更改库.
实际上,您也无法真正移动可执行文件,因为库位于系统搜索路径之外.如果它只在库位于~luke / lib时运行,那么除非他能读取你的文件,否则你不能将它交给joe.如果你搬到新工作岗位,那就很难过了.
仅供参考,它也会以无数其他方式吸收.如果你只能在编译时指定库位置,它会使调试成为永恒的噩梦.