【问题标题】:Find all symbols in a directory查找目录中的所有符号
【发布时间】:2021-04-09 20:46:35
【问题描述】:

我正在寻找在编译包含它作为头文件的程序时要包含哪个 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

【问题讨论】:

  • 库的文档通常应该包含这些信息。
  • 通常,软件包附带 README 或其他描述链接内容的文档。
  • 有时,您可以使用pkg-config,例如pkg-config --libs pcre.
  • 通过正常的完整安装,.h 文件转到(例如)/usr/include/local,但 .a.so 转到 /usr/local/lib64。那么,您的ls 显示它们位于同一目录中,您正在执行make 的目录也是如此吗?如果您不需要/不想安装,您可以(例如)pcdir=/home/me/pcre_build_directory ; gcc myfile.c -I $pcdir -L $pcdir -lpcre2-8 -o myfile。有时,最好将-lwhatever 作为gcclast arg。您还可以在strace 下运行gcc 以查看检查了哪些目录。
  • @OlafDietsche 我明白了,谢谢你的建议。这在$ pkg-config --list-all | grep pcre 上效果很好,但如果我以--libs pcre 的方式进行操作,它会显示找不到包。如何让 pkg-config 识别 pcre

标签: c cmake linker elf symbol-table


【解决方案1】:

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

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

int main() {
  pcre2_compile("",0,0,NULL,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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    相关资源
    最近更新 更多