确定静态/动态库的名称

确定静态/动态库的名称

我经常使用使用 Unix/Linux C 库的第三方 C 代码片段,例如#include <glib.h>.#include <net/if.h>他们要求我知道具体的库文件名或 pkg-config 名称,例如-lglib-2.0, -lbluetooth, pkg-config --libs dbus-1.请注意,其中很多与具有“2.0”、“1”的头文件不同,因此您无法猜测它。

我到底如何才能找到 API/库所拥有的库文件的确切名称?使用我上面的例子;我如何找到该#include <glib.h>库文件的名称-lglib-2.0?令人沮丧的是,Glib/dbus/all 的在线参考文献不仅仅说“库文件的名称是 glib-2.0”。

我可以使用任何终端命令来找出这个问题吗?我可以使用一些实用程序来找出这个问题吗?在线 API/库参考对于找出这一点来说确实很糟糕。

如果我想找到它hci.h的位置,我可以轻松地locate hci.h找到它的位置。有没有类似终端命令的东西来查找库名称?

答案1

没有通用方法可以知道使用特定函数需要哪个库。您需要查看该库的文档。编写良好的教程或 API 参考应该告诉您,这就是它的工作。

您至少可以了解什么是图书馆包裹是必需的:它与包含头文件的库包相同。如何确定哪个包包含头文件取决于发行版,例如dpkg -S /usr/include/glib-2.0/glib.h在 Debian/Ubuntu/Mint/...、rpm -qf /usr/include/glib-2.0/glib.hRHEL/CentOS/Fedora/...等。知道库包后,列出其内容以查找哪些.so文件它包含,例如

dpkg -L libglib2.0-dev | grep '\.so$'
rpm -qlf /usr/include/glib-2.0/glib.h | grep '\.so$'

对于 Glib,有多个.so文件,并且没有自动方法来判断特定函数需要哪些文件(可能有多个文件)。

如果库使用pkg-config,您应该使用它而不是硬编码标头和库路径。然而,并非所有图书馆都使用它。您通常可以看出,因为您的发行版的库包应该依赖于它的pkg-config包(例如dpkg -s libglib2.0-dev |grep '^Depends:.*pkg-config')。

如果文档真的很糟糕,请尝试列出库定义的符号:

nm -D /usr/lib/x86_64-linux-gnu/libgio-2.0.so |awk '$2=="T" {print $3}'

这不是一种万无一失的方法,因为它不会告诉您是否还需要其他库。

答案2

这些#include指令由 C 预处理器扩展。搜索路径由编译器控制(例如-I<dir>标志)。它们在生成的目标文件中提供符号。

然后,链接器使用约定将这些符号映射到存档/目标文件:给定类似 的标志-l<namespec>,链接器将在其库路径中的目录中搜索lib<namespec>.alib<namespec>.so。链接器将这些文件名包含在生成的二进制文件中,动态链接器在运行时使用这些文件名将符号解析为其实际实现。

您可以使用 找到编译器链接器的搜索目录ld --verbose | grep SEARCH_DIR。例如,这大致模拟链接器如何将库名称映射到文件.so

$ libname=glib-2.0; ld --verbose |  grep SEARCH_DIR |  tr -s ' ;' '\n' |  sed 's/SEARCH_DIR("=\?\(.*\)")/\1/g' |  xargs -I{} find {} -maxdepth 1 2>/dev/null | grep lib${libname}.so
/usr/lib/libglib-2.0.so.0.7000.0
/usr/lib/libglib-2.0.so
/usr/lib/libglib-2.0.so.0

(这些都是同一文件的符号链接。)

您可以在包管理器中找到提供该文件的包,例如yum

$ yum whatprovides /usr/lib64/libglib-2.0.so.0

glib2-2.68.1-1.fc34.x86_64 : A library of handy utility functions
Repo        : fedora
Matched from:
Filename    : /usr/lib64/libglib-2.0.so.0

glib2-2.68.4-1.fc34.x86_64 : A library of handy utility functions
Repo        : @System
Matched from:
Filename    : /usr/lib64/libglib-2.0.so.0

glib2-2.68.4-1.fc34.x86_64 : A library of handy utility functions
Repo        : updates
Matched from:
Filename    : /usr/lib64/libglib-2.0.so.0

您可以使用以下命令查看其中的符号nm

$ nm -D --defined-only /usr/lib/libglib-2.0.so.0
0000000000070000 T g_access
000000000001d600 T g_allocator_free
000000000001d5f0 T g_allocator_new
0000000000022810 T g_array_append_vals
000000000001e3a0 T g_array_binary_search
...

链接器约定记录在 中man ld

最后回答您的问题:这些机制旨在将头文件与实际实现分离,因此没有通用的方法可以根据设计将头文件映射到对象/归档文件。最终你必须找到.so实现你的符号的文件#include。正如另一个答案所说,这是临时的。

不过,包管理器对它有很大帮助,因为通常是提供头文件的包,<package>-devel并且该包<package>提供共享对象。例如,yum您可以使用它来查找开发包:

$ yum provides '*/glib.h'

glib-devel-1:1.2.10-62.fc34.i686 : Libraries and header files for glib development
Repo        : fedora
Matched from:
Filename    : /usr/include/glib-1.2/glib.h

glib-devel-1:1.2.10-62.fc34.x86_64 : Libraries and header files for glib development
Repo        : fedora
Matched from:
Filename    : /usr/include/glib-1.2/glib.h

glib2-devel-2.68.1-1.fc34.i686 : A library of handy utility functions
Repo        : fedora
Matched from:
Filename    : /usr/include/glib-2.0/glib.h

...

可以看到glib2-devel包中提供了头文件。因此,glib2包提供了该.so文件,并且从该文件名,您可以知道该标志要使用什么-l

$ repoquery -l glib2 | grep '.so'

/usr/lib/libgio-2.0.so.0
/usr/lib/libgio-2.0.so.0.6800.4
/usr/lib/libglib-2.0.so.0
/usr/lib/libglib-2.0.so.0.6800.4
...

所以你可以看到,鉴于glib.h,你至少应该使用-lglib-2.0.

相关内容