Find Which Static Library Defines Symbol on Linux

Find Which Static Library Defines Symbol on Linux

When building or debugging software on Linux, you may encounter missing symbol errors during linking. If the project depends on multiple static libraries (.a files), it can be tricky to know which library actually contains the symbol (function, variable, or other entity). This tutorial explains how to find which static library defines symbol on Linux.

The nm utility, part of the Binutils package, lists symbols in object files and libraries. By combining it with find and grep, we can automatically search through all static libraries on the system for a specific symbol.

For example, to locate which static library in the /usr/lib directory defines the symbol gz_open, you can run:

find /usr/lib -name "*.a" -exec bash -c "nm --defined-only {} 2>/dev/null | grep gz_open && echo {}" \;

Example output:

0000000000000000 t gz_open
/usr/lib/x86_64-linux-gnu/libz.a

This indicates that the gz_open symbol is present in the libz.a static library.

Breaking down the command:

  • find /usr/lib -name "*.a" - searches recursively under /usr/lib for all files ending in .a (static libraries).
  • -exec bash -c '...' \; - for each .a file found, execute the command inside the quotes in a new Bash shell.
  • nm --defined-only {} - lists only the symbols that are defined (not undefined) in the current library file {}.
  • 2>/dev/null - suppresses error messages, e.g., if nm cannot read a file.
  • grep gz_open - filters the output to only show lines containing the symbol gz_open.
  • && echo {} - if grep finds a match, print the name of the library file {} that contains it.

C++ symbols are often mangled, meaning their names include extra characters to encode namespaces, classes, and parameters. To convert them back into a readable format, use the -C option with nm.

For example, to find which static library in the /usr/lib directory contains std::filesystem::rename:

find /usr/lib -name "*.a" -exec bash -c "nm -C --defined-only {} 2>/dev/null | grep std::filesystem::rename && echo {}" \;

Example output:

0000000000000000 T std::filesystem::rename(std::filesystem::path const&, std::filesystem::path const&)
0000000000000000 t std::filesystem::rename(std::filesystem::path const&, std::filesystem::path const&) [clone .cold]
0000000000000000 T std::filesystem::rename(std::filesystem::path const&, std::filesystem::path const&, std::error_code&)
0000000000000000 T std::filesystem::rename(std::filesystem::__cxx11::path const&, std::filesystem::__cxx11::path const&)
0000000000000000 t std::filesystem::rename(std::filesystem::__cxx11::path const&, std::filesystem::__cxx11::path const&) [clone .cold]
0000000000000000 T std::filesystem::rename(std::filesystem::__cxx11::path const&, std::filesystem::__cxx11::path const&, std::error_code&)
/usr/lib/gcc/x86_64-linux-gnu/11/libstdc++.a

This indicates that the symbol is in libstdc++.a.

Leave a Comment

Cancel reply

Your email address will not be published.