前言
博主今天ubuntu编译go项目出来的一个可执行文件,放centos运行发现居然依赖于XXlib库。然后我一下就想到两个系统库版本不一致,重编。换系统,导项目,配环境……
等等,编出来的文件为啥还需要lib库??
然后使用ldd命令查看,显示除了依赖的共享库文件。但是为啥会依赖呢?一会儿我们会主要介绍ldd命令的功能。
比较正常编译出来的go程序的设置 go env 发现不同的只有CGO_ENABLED=0
CGO_ENABLED=1
两个参数区别,这里博主去查看了一下这个环境变量的用处。
CGO_ENABLED=0
是一个环境变量,用于控制 Go 语言程序是否使用 CGO(C 与 Go 之间的接口)。当 CGO_ENABLED
设置为 0
时,Go 程序将不会尝试链接任何 C 代码或库。这通常用于确保 Go 程序可以在没有 C 编译器的环境中编译和运行,例如在纯 Go 容器中。
最后使用CGO_ENABLED=0 go build
重新编译即可。如下图所示即为不依赖于库的可执行文件。
下面进入正题:ldd命令
ldd命令是Linux系统中的一个工具,用于打印出一个可执行文件所依赖的共享库文件(动态链接库)。
在Linux操作系统中,程序运行时往往依赖于多个动态链接库(Dynamic Link Libraries,简称DLLs或.so文件)。这些库文件提供了程序运行所需的函数和数据结构。为了了解一个程序依赖哪些库文件以及库的版本,通常可以使用ldd命令来实现这一目的[2]。它不仅能够列出程序运行时需要加载的共享库文件及其路径,还能帮助调试程序、解决运行时错误以及优化系统环境[3]。
首先,ldd命令的基本语法如下:
ldd [选项] 可执行文件或共享库文件
其中,常用项包括:
-v
或--verbose
:显示详细信息模式,打印所有相关信息[4]。-u
或--unused
:显示未使用的直接依赖项[1]。-d
或--data-relocs
:显示包含数据重定位的共享库[3]。-r
或--function-relocs
:显示包含函数重定位的共享库[3]。
例如,查看某个可执行文件(如ls
命令)所需的动态库,可以使用以下命令[1][4]:
ldd $(which ls)
此命令将输出类似以下的结果:
linux-vdso.so.1 => (0x00007ffd3a7b3000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5d5e18b000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f5d5e161000)
...
这表明ls
命令依赖于libpthread.so.0
、libselinux.so.1
等共享库文件,每个依赖项的路径都会显示在箭头(=>)之后。
其次,ldd命令的工作原理是通过设置一系列的环境变量,如LD_TRACE_LOADED_OBJECTS
、LD_WARN
、LD_BIND_NOW
、LD_LIBRARY_VERSION
和LD_VERBOSE
等。当LD_TRACE_LOADED_OBJECTS
环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的依赖关系,而程序并不真正执行[1][3]。实际上,ldd命令的本质是通过执行/lib/ld-linux.so.*
来实现的[1]。
在使用ldd命令时,还可以结合其他参数来获取更多信息。例如,使用-v
参数可以打印所有相关信息,包括符号的版本信息;使用-u
参数则可以打印未使用的直接依赖项[4]。这对于深入理解程序的运行机制非常有帮助。
最后,值得注意的是,ldd命令只能用于分析动态链接的程序和库文件,如果程序或库文件是静态链接的,则无法列出其依赖的库文件[2]。此外,由于ldd需要读取可执行文件或共享库文件的符号表信息,因此可能需要足够的权限来执行该命令,遇到权限问题时可以尝试使用sudo
命令提升权限[2]。
综上所述,ldd命令是一个强大的工具,能够帮助人们了解程序依赖的动态链接库文件及其路径,从而更好地调试程序、优化系统环境以及理解程序运行机制。在使用ldd命令时需要注意权限问题、静态链接与动态链接的区别以及库文件路径的解析方式。