查找目录中的所有符号

问题描述

我想知道在编译包含它作为头文件的程序时要包含哪个 C 库,在本例中为 #include <pcre2.h>。我能够弄清楚我需要的文件在哪里的唯一方法是检查我知道需要导出的特定符号。例如:

$ ls
CMakeCache.txt       Makefile             install_manifest.txt  libpcre2-posix.pc   pcre2_grep_test.sh
CMakeFiles           a.out                libpcre2-8.a          pcre2-config        pcre2_test.sh
CTestCustom.ctest    cmake_install.cmake  libpcre2-8.pc         pcre2.h             pcre2grep
CTestTestfile.cmake  config.h             libpcre2-posix.a      pcre2_chartables.c  pcre2test
$ objdump -t libpcre2-8.a|grep pcre2_compile
pcre2_compile.c.o:     file format elf64-x86-64
0000000000000000 l    df *ABS*  0000000000000000 pcre2_compile.c
00000000000100bc g     F .text  00000000000019dd pcre2_compile_8
0000000000000172 g     F .text  00000000000000e3 pcre2_compile_context_create_8
0000000000000426 g     F .text  0000000000000055 pcre2_compile_context_copy_8
0000000000000557 g     F .text  0000000000000032 pcre2_compile_context_free_8

并且因为符号 pcre2_compile_8 存在于该文件中(在尝试了所有其他文件之后......)我知道我需要包含的库是 pcre2-8,也就是说,我编译我的代码:

$ gcc myfile.c -lpcre2-8 -o myfile; ./myfile

与此相关的两个问题:

  1. 有没有更简单的方法可以在一批文件(其中一些不是 elf 文件)中找到一个符号?例如,像 objdump -t *?或者最接近这样做的事情是什么?
  2. 是否有更好的方法来找出 -l<library> 的库值?或者,当有人下载​​一个新的 C 程序时,他们知道将什么添加到他们的命令行以便程序运行时,常用的方法是什么? (对我来说,我刚刚花了最后一个小时才弄清楚它是 -lpcre2-8 而不是 -lpcre-lpcre2

解决方法

通常,您从库中调用的函数将是该库定义的符号。但是在 PCRE2 中,由于不同的代码单元大小,您调用的函数(例如 pcre2_compile)实际上通过预处理器宏(例如 pcre2_compile_8)变成了不同的符号。您可以通过编译您的程序并检查未定义的符号来从库中找到您需要的符号:

$ cat test.c 
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>

int main() {
  pcre2_compile("",NULL,NULL);
}
$ gcc -c test.c
$ nm -u test.o 
                 U _GLOBAL_OFFSET_TABLE_
                 U pcre2_compile_8

有没有更简单的方法可以在一批文件中找到一个符号?

您可以在目录(下面的/usr/lib/)中搜索库文件(下面的.a.so 扩展名),为每个文件运行 nm 并搜索未定义的符号(改编自this question):

$ for lib in $(find /usr/lib/ -name \*.a -o -name \*.so)
> do
>     nm -A --defined-only $lib 2>/dev/null| grep pcre2_compile_8
> done
/usr/lib/x86_64-linux-gnu/libpcre2-8.a:libpcre2_8_la-pcre2_compile.o:0000000000007f40 T pcre2_compile_8

有没有更好的方法来找出 -l 的库值是什么?

通常通过库文档传达。对于 PCRE2,the second page of the documentation 讨论了提供适当标志的 pcre-config 工具:

pcre2-config 返回已安装 PCRE2 库的配置以及编译程序以使用它们所需的选项。部分选项分别仅适用于 8 位、16 位或 32 位库,不适用于尚未构建的库。

[...]

--libs8 将链接 8 位 PCRE2 库(在许多系统上为 -lpcre2-8)所需的命令行选项写入标准输出。

[...]

--cflags 将编译使用 PCRE2 的文件所需的命令行选项写入标准输出(这可能包括一些 -I 选项,但在许多系统上为空白)。

所以对于这个特定的库,推荐的构建和链接方式是:

gcc -c $(pcre2-config --cflags) test.c -o test.o
gcc test.o -o test $(pcre2-config --libs8)