当前位置: 首页 > 科技观察

编译代码时动态链接库

时间:2023-03-23 11:21:55 科技观察

编译软件是开发人员经常做的事情,在开源世界中,一些用户甚至选择自己动手。Linux播客DannWashko将源代码称为“通用包格式”,因为它包含使应用程序在任何平台上运行所需的所有组件。当然,并非所有源代码都是为所有系统编写的,因此它只是目标系统子集中的“通用”代码,但事实是,源代码非常灵活。使用开源,您可以决定代码的编译和运行方式。编译代码时,通常会处理多个源文件。开发人员倾向于将不同的类或模块放在不同的文件中,这样它们就可以单独维护,甚至可能被不同的项目使用。但是当你编译这些文件时,许多文件被编译成一个可执行文件。这通常是通过创建共享库然后从可执行文件动态链接它们来完成的。这通过将模块化功能保持在外部来保持可执行文件较小,并确保库可以独立于使用它们的应用程序进行更新。在编译期间定位共享对象当您使用GCC进行编译时,通常需要在您的工作站上安装一个库,以便GCC可以定位它。默认情况下,GCC假定库位于系统库路径中,例如/lib64和/usr/lib64。但是,如果您要链接到您自己的未安装的库,或者如果您需要链接到未安装在标准位置的库,那么您必须帮助GCC找到这些文件。两个选项对于在GCC中查找库很重要:-L(大写L)向GCC搜索的位置添加一个额外的库路径。-l(小写L)设置要链接的库的名称。例如,假设您编写了一个名为libexample.so的库,并且您希望在编译应用程序demo.c时使用它。首先,从demo.c创建一个目标文件:$gcc-I./include-csrc/demo.c-I选项在GCC搜索头文件的路径中添加一个目录。在此示例中,我假设自定义头文件位于名为include的本地目录中。-c选项阻止GCC运行链接器,因为此任务仅用于创建目标文件。结果是:$lsdemo.oinclude/lib/src/现在你可以使用-L选项为你的库设置一个路径然后编译:$gcc-L`pwd`/lib-omyDemodemo.o-lexample注意,-L选项出现在-l选项之前。这很重要,因为如果您在告诉GCC查找非默认库之前没有将-L添加到GCC的搜索路径,GCC就不知道要在您的自定义位置进行搜索。编译成功,但是当你尝试运行它时,出现了错误:$./myDemo./myDemo:errorwhileloadingsharedlibraries:libexample.so:cannotopensharedobjectfile:NosuchfileordirectoryTroubleshootwithlddldd工具可以打印出共享对象的依赖关系,这在排查类似问题时很有用:$ldd./myDemolinux-vdso.so.1(0x00007ffe151df000)libexample.so=>notfoundlibc.so.6=>/lib64/libc.so.6(0x00007f514b60a000)/lib64/ld-linux-x86-64.so.2(0x00007f514b839000)您已经知道libexample不存在,但ldd输出至少确认了它期望工作库的位置。例如,已找到libc.so.6,并且ldd显示了其完整路径。LD_LIBRARY_PATHLD_LIBRARY_PATH环境变量定义库的路径。如果您运行的应用程序依赖于未安装到标准目录中的库,则可以使用LD_LIBRARY_PATH添加到系统的库搜索路径中。设置环境变量有多种方法,但最灵活的是在运行命令之前放置环境变量。在分析“损坏的”可执行文件时,查看设置LD_LIBRARY_PATH对ldd命令的作用:$LD_LIBRARY_PATH=`pwd`/libldd./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`/libmyDemohelloworld!但是,如果您移动库或可执行文件,它将再次失败:$mvlib/libexample.so~/.local/lib64$LD_LIBRARY_PATH=`pwd`/libmyDemo./myDemo:errorwhileloadingsharedlibraries...要修复它,您必须调整LD_LIBRARY_PATH以匹配库的新位置:$LD_LIBRARY_PATH=~/.local/lib64myDemohelloworld!在使用LD_LIBRARY_PATH时大多数情况下,LD_LIBRARY_PATH不是您需要设置的变量。根据设计,库安装在/usr/lib64中,因此应用程序自然会在那里搜索所需的库。在这两种情况下,您都可以使用LD_LIB需要使用RARY_PATH:您正在编译的软件需要链接到本身刚刚编译但尚未安装的库。设计良好的构建系统,例如Autotools和CMake,可以帮助解决这个问题。您正在使用设计为在没有安装脚本的单个目录软件之外运行的库,或者安装脚本将库放置在非标准目录中。某些应用程序的版本可供Linux用户下载、复制到/opt并“无需安装”即可运行。LD_PATH_LIBRARY变量被传递给Wraps脚本设置的内容,因此用户通常甚至不知道它已设置。编译软件为您运行系统的方式提供了很大的灵活性。LD_LIBRARY_PATH变量以及-L和-lGCC选项是这种灵活性的一部分。