编译软件是开发人员经常做的事情,在开源领域,一些用户甚至选择自己编译。Linux 播客 Dann Washko 将源代码称为“通用软件包格式”,因为它包含了使应用程序在任何平台上运行所需的所有组件。当然,并非所有源代码都是为所有系统编写的,因此它仅在目标系统的子集中才是“通用”的,但重点是源代码非常灵活。通过开源,您可以决定代码的编译和运行方式。
当您编译代码时,通常会处理多个源文件。开发人员倾向于将不同的类或模块保存在单独的文件中,以便可以单独维护它们,甚至可以被不同的项目使用。但是,当您编译这些文件时,其中许多文件会被编译成一个可执行文件。
这通常通过创建共享库来完成,然后从可执行文件动态链接回这些库。这通过将模块化功能保持在外部来保持可执行文件的小巧,并确保库可以独立于使用它们的应用程序进行更新。
在编译期间定位共享对象
当您使用 GCC 编译时,通常需要您的工作站上安装一个库,以便 GCC 能够找到它。默认情况下,GCC 假定库位于系统库路径中,例如 /lib64
和 /usr/lib64
。但是,如果您要链接到您自己的尚未安装的库,或者您需要链接到未安装在标准位置的库,那么您必须帮助 GCC 找到这些文件。
GCC 中有两个选项对于查找库非常重要:
-L
(大写 L) 向 GCC 的搜索位置添加额外的库路径。-l
(小写 l) 设置您要链接的库的名称。
例如,假设您编写了一个名为 libexample.so
的库,并且您想在编译应用程序 demo.c
时使用它。首先,从 demo.c
创建一个目标文件:
$ gcc -I ./include -c src/demo.c
-I
选项将目录添加到 GCC 的头文件搜索路径。在本例中,我假设自定义头文件位于名为 include
的本地目录中。-c
选项阻止 GCC 运行链接器,因为此任务仅是创建目标文件。这正是发生的情况:
$ ls
demo.o include/ lib/ src/
现在您可以使用 -L
选项为您的库设置路径,并进行编译:
$ gcc -L`pwd`/lib -o myDemo demo.o -lexample
请注意,-L
选项位于 -l
选项之前。这很重要,因为如果在您告诉 GCC 查找非默认库之前,-L
尚未添加到 GCC 的搜索路径中,则 GCC 将不知道在您的自定义位置进行搜索。编译按预期成功,但是当您尝试运行时会出现问题:
$ ./myDemo
./myDemo: error while loading shared libraries:
libexample.so: cannot open shared object file:
No such file or directory
使用 ldd 进行故障排除
ldd
实用程序打印共享对象依赖项,它在解决此类问题时非常有用:
$ ldd ./myDemo
linux-vdso.so.1 (0x00007ffe151df000)
libexample.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f514b60a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f514b839000)
您已经知道无法找到 libexample
,但是 ldd
输出至少确认了从工作库中期望得到的结果。例如,libc.so.6
已被找到,并且 ldd
显示了它的完整路径。
LD_LIBRARY_PATH
LD_LIBRARY_PATH
环境变量 定义了库的路径。如果您运行的应用程序依赖于未安装到标准目录的库,则可以使用 LD_LIBRARY_PATH
将其添加到系统的库搜索路径中。
有几种设置环境变量的方法,但最灵活的方法是在运行命令之前设置它们。看看设置 LD_LIBRARY_PATH
对分析“损坏”的可执行文件的 ldd
命令有什么作用:
$ LD_LIBRARY_PATH=`pwd`/lib ldd ./
linux-vdso.so.1 (0x00007ffe515bb000)
libexample.so => /tmp/Demo/lib/libexample.so (0x0000...
libc.so.6 => /lib64/libc.so.6 (0x00007eff037ee000)
/lib64/ld-linux-x86-64.so.2 (0x00007eff03a22000)
它同样适用于您的自定义命令:
$ LD_LIBRARY_PATH=`pwd`/lib myDemo
hello world!
但是,如果您移动库文件或可执行文件,它会再次中断:
$ mv lib/libexample.so ~/.local/lib64
$ LD_LIBRARY_PATH=`pwd`/lib myDemo
./myDemo: error while loading shared libraries...
要修复它,您必须调整 LD_LIBRARY_PATH
以匹配库的新位置:
$ LD_LIBRARY_PATH=~/.local/lib64 myDemo
hello world!
何时使用 LD_LIBRARY_PATH
在大多数情况下,LD_LIBRARY_PATH
不是您需要设置的变量。按照设计,库安装在 /usr/lib64
中,因此应用程序自然会在其中搜索所需的库。您可能需要在两种情况下使用 LD_LIBRARY_PATH
:
- 您正在编译的软件需要链接到刚刚编译但尚未安装的库。良好的构建系统,例如 Autotools 和 CMake,可以帮助处理这种情况。
- 您正在捆绑旨在从单个目录运行的软件,没有安装脚本或安装脚本将库放置在非标准目录中。一些应用程序的发布版本 Linux 用户可以下载,复制到
/opt
并“无需安装”即可运行。LD_PATH_LIBRARY
变量通过包装器脚本设置,因此用户通常甚至没有意识到它已被设置。
编译软件让您在如何运行系统方面拥有很大的灵活性。LD_LIBRARY_PATH
变量以及 -L
和 -l
GCC 选项,都是这种灵活性的组成部分。
评论已关闭。