How do I find where a symbol is defined among static libraries

Using nm, it is possible to list the symbols defined in a binary, and the --defined-only switch ignores undefined references.

Option 1: find

In a single command:

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

where $path is the root of the file tree containing the binaries, and $symbol is the name of the symbol you are looking for.

Option 2: find + GNU parallel

Running nm on all files can take time, so it could be helpful to process the results of find in parallel (using GNU parallel):

find $path -name \*.a | parallel "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"

Option 3: fd

And at last, my favourite. Using the fd tool, that has a simpler syntax than find, is generally faster, and processes the results in parallel by default:

fd '.*\.a$' -x bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"

Simple benchmark

Searching for the gz_write symbol in /usr/lib on my laptop:

  • find takes around 23 seconds
  • find | parallel takes around 10 seconds
  • fd takes around 8 seconds

Assuming a linux box, the nm tool, listing names in library files, comes to the rescue.

It can be used to do an extensive search as follows: one can first find all the libraries available (assuming the project have been successfully compiled without the component you are adding) with a find, then such find can be enclosed in a loop where you call nm on all discovered libraries; the output you then grep for discarding "U" references (undefined symbols, aka where else the symbol is being used). On a single bash line that gives:

for lib in $(find base_path -name \*.a) ; do echo $lib ; nm $lib | grep my_symbol | grep -v " U "   ; done

where:

  • base_path is the root of your codebase
  • my_symbol is the symbol you are looking for

The echo generates a list of all libraries found, which is not so clean since it outputs names of libs not holding the symbol, but it was the fastest way I found to have a direct reference to the library so when you see a:

base_path/component/libA.a
0000000000000080 D my_symbol

You have found your usual suspect.