Search code examples
ccmakelinkerelfsymbol-table

Find all symbols in a directory


I am looking to figure out which C library to include when compiling a program that includes it as a header, in this case #include <pcre2.h>. The only way I've been able to figure out where the file is I need is to check for a specific symbol that I know needs to be exported. For example:

$ 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

And because the symbol pcre2_compile_8 exists in that file (after trying every other file...) I know that the library I need to include is pcre2-8, that is, I compile my code with:

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

Two questions related to this:

  1. Is there a simpler way to find a symbols in a batch of files (some of which are not elf files)? For example, something like objdump -t *? Or what's the closest thing to doing that?
  2. Is there a better way to find out what the library value of -l<library> is? Or, what's the common way when someone downloads a new C program that they know what to add to their command-line so that the program works? (For me, I've just spent the last hour figuring out that it's -lpcre2-8 and not -lpcre or -lpcre2.

Solution

  • Usually, the function you call from the library will be a symbol defined by that library. But in PCRE2, due to different code unit sizes, the function you call (e.g. pcre2_compile) actually becomes a different symbol through preprocessor macros (e.g. pcre2_compile_8). You can find the symbol you need from the library by compiling your program and checking the undefined symbols:

    $ 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
    

    Is there a simpler way to find a symbols in a batch of files?

    You can search a directory (/usr/lib/ below) for the library files (.a or .so extension below), running nm for each and search for the undefined symbol (adapted from 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
    

    Is there a better way to find out what the library value of -l is?

    It is usually conveyed through the library documentation. For PCRE2, the second page of the documentation talks about the pcre-config tool that gives the appropriate flags:

    pcre2-config returns the configuration of the installed PCRE2 libraries and the options required to compile a program to use them. Some of the options apply only to the 8-bit, or 16-bit, or 32-bit libraries, respectively, and are not available for libraries that have not been built.

    [...]

    --libs8 Writes to the standard output the command line options required to link with the 8-bit PCRE2 library (-lpcre2-8 on many systems).

    [...]

    --cflags Writes to the standard output the command line options required to compile files that use PCRE2 (this may include some -I options, but is blank on many systems).

    So for this particular library, the recommended way to build and link is:

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