0

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.
David542
  • 104,438
  • 178
  • 489
  • 842
  • The documentation of the library should usually include this information. – Barmar Apr 09 '21 at 20:48
  • Usually packages come with a README or other documentation that describes what to link. – kaylum Apr 09 '21 at 20:48
  • 1
    Sometimes, you can use [`pkg-config`](https://en.wikipedia.org/wiki/Pkg-config), e.g. `pkg-config --libs pcre`. – Olaf Dietsche Apr 09 '21 at 21:59
  • 1
    With a normal full install, the `.h` files go to (e.g.) `/usr/include/local` but the `.a` or `.so` go to `/usr/local/lib64`. So, your `ls` shows them to be in the same directory, so is the directory in which you're doing `make`? If you don't need/want to install, you could do (e.g.) `pcdir=/home/me/pcre_build_directory ; gcc myfile.c -I $pcdir -L $pcdir -lpcre2-8 -o myfile`. Sometimes, it's best to put the `-lwhatever` as the _last_ arg to `gcc`. You can also run `gcc` under `strace` to see what directories are examined. – Craig Estey Apr 10 '21 at 00:04
  • @OlafDietsche I see, thanks for that suggestion. That works pretty well doing `$ pkg-config --list-all | grep pcre`, but if I do it as `--libs pcre` it says No package found. How do I get pkg-config to recognize `pcre` ? – David542 Apr 10 '21 at 01:55
  • @CraigEstey yes that was the `build` directory. To install I did: `$ mkdir build; cd build; cmake ../; make; sudo make install`. Regarding the `I`, `l`, and `L` options (unfortunately they all look the same...) `l` links to a file, `L` does the same but for a directory, which then looks up the file there, and then why is `I` necessary? – David542 Apr 10 '21 at 02:09
  • @David542 Typically in Linux, this is included in the development package, e.g. [libpcre3-dev](https://packages.debian.org/buster/amd64/libpcre3-dev/filelist) for Debian derived distributions, see – Olaf Dietsche Apr 10 '21 at 11:57
  • @David542 Just found out, that pcre3 is the old one and pcre2 is the newer library. So, you should rather use libpcre2-dev on Debian/Ubuntu. – Olaf Dietsche Apr 10 '21 at 12:13

1 Answers1

2

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)
mkayaalp
  • 2,631
  • 10
  • 17