Home / Alt manpages / find-all-symbols-20(1)

  • find-all-symbols-20(1)
  • User command
  • linux

Inventory C++ API Symbols with find-all-symbols-20

You need a list of every class and function a C++ library exposes, and grepping headers will not get you there. find-all-symbols-20 parses your sources with their real compiler flags and writes YAML records for the symbols it finds.

The workflow uses a CMake-style compile_commands.json, writes results to a separate directory, and checks the records instead of assuming a clean exit means useful output. Allow about fifteen minutes.

  • You need: the clang-tools-20 package, a C++ source tree and a compile command database.
  • Installed version: LLVM 20.1.8, package version 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139.
  • Privileges: the examples only read source and write a new results directory, so they normally need no elevated privileges.

1. Check the installed tool

Confirm the binary and version before relying on its output:

$ command -v find-all-symbols-20
/usr/bin/find-all-symbols-20
$ find-all-symbols-20 --version
Ubuntu LLVM version 20.1.8
  Optimized build.

The syntax is find-all-symbols-20 [options] <source0> [... <sourceN>]. It is a Clang tooling program, so it needs the same compiler arguments the source normally builds with. Those come from the compilation database, not from the source file name.

Checkpoint

The version output should identify LLVM 20. If the command is missing, install the package through your normal distribution process and repeat the check. Do not run the analysis as root to work around a missing package.

2. Generate or locate a compilation database

For a CMake project, configure a build directory with export enabled:

$ cmake -S /path/to/project -B /path/to/project/build \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
$ test -r /path/to/project/build/compile_commands.json && echo ready
ready

This changes the build directory, not the source tree's files. If the project already has a configured build, look for the database first:

$ find /path/to/project -name compile_commands.json -type f -print
/path/to/project/build/compile_commands.json

The database holds the working directory, source path and compiler command for each translation unit. It matters when code depends on include directories, language standards, generated headers or preprocessor definitions. Without those flags you can get no records or misleading diagnostics.

Tip

Without -p, the installed manual says the program searches parent directories of the first input for compile_commands.json. Make the build path explicit in scripts so a change of working directory cannot silently select a different database.

3. Analyse one source file into a new directory

Choose a source path that appears in the database and write results somewhere dedicated:

$ mkdir -p /tmp/find-all-symbols-results
$ find-all-symbols-20 \
    -p /path/to/project/build \
    --output-dir=/tmp/find-all-symbols-results \
    /path/to/project/src/widget.cpp
/tmp/find-all-symbols-results/widget.cpp-5ac549.yaml

The output filename is the input basename plus a generated suffix, so do not script against the exact suffix. Treat the output directory as disposable analysis data, not a replacement for source control.

Checkpoint

List the directory and inspect the first record.

$ find /tmp/find-all-symbols-results -maxdepth 1 -type f -print
/tmp/find-all-symbols-results/widget.cpp-5ac549.yaml
$ sed -n '1,80p' /tmp/find-all-symbols-results/widget.cpp-5ac549.yaml
---
Name:            Widget
Contexts:
  - ContextType:     Namespace
    ContextName:     demo
FilePath:        '/path/to/project/include/api.h'
Type:            Class
Seen:            1
Used:            1
...

A record gives the symbol name, its namespace context, the declaration file, its kind and the counts seen during the run. Here the input is widget.cpp but the declaration is reported in the included public header. That is usually exactly what you want when inventorying an API.

4. Pass several translation units

You can give more than one source path in a single invocation:

$ rm -f /tmp/find-all-symbols-results/*
$ find-all-symbols-20 \
    -p /path/to/project/build \
    --output-dir=/tmp/find-all-symbols-results \
    /path/to/project/src/widget.cpp \
    /path/to/project/src/gadget.cpp
$ find /tmp/find-all-symbols-results -maxdepth 1 -type f -print
/tmp/find-all-symbols-results/widget.cpp-5ac549.yaml
/tmp/find-all-symbols-results/gadget.cpp-d435a8.yaml

Warning

The rm here targets only the disposable results directory. Check the path before running it, because a slip in a deletion command can remove useful files. If the directory holds anything you need, pick a new empty directory instead.

Recovery

Rerun the analysis, provided the source and database still exist.

For a repeatable job, create a fresh run directory under a known temporary or build location, record the command and database path, then consume all the generated YAML files. One output file does not represent the whole project.

5. Use relative paths only when they resolve in the database

The manual permits absolute and relative source paths, but the matching rules are easy to trip over:

  • Absolute path. Must point into the CMake source tree.
  • Relative path. Must be below the current working directory and must match a suffix of a path in the database.

From the project root, this is usually clearer:

$ cd /path/to/project
$ find-all-symbols-20 \
    -p build \
    --output-dir=/tmp/find-all-symbols-results \
    src/widget.cpp

Recovery

If the command cannot find a compile command, inspect the database and compare the recorded file paths with the path you supplied. Then use an absolute path into the source tree, or change to the directory that makes the relative path a suffix. Do not fix a path mismatch by adding random compiler flags with --extra-arg.

6. Add a compiler argument only when the database needs it

--extra-arg=<string> appends one argument to each compiler command. --extra-arg-before=<string> prepends one. Use them for a controlled, analysis-only adjustment, such as selecting a known language mode:

$ find-all-symbols-20 \
    -p /path/to/project/build \
    --extra-arg=-DAPI_SCAN=1 \
    --output-dir=/tmp/find-all-symbols-results \
    /path/to/project/src/widget.cpp

Keep the database as the source of truth for normal include paths and definitions. An extra argument does not repair a wrong compiler command, a missing generated header or a source path absent from the database.

Tip

If the analysis changes after you add an argument, record it alongside the result so another run can reproduce it.

7. Understand empty output and failed runs

A successful exit does not guarantee the output directory holds a useful record. A file can be empty when the source exposes no symbols the tool records, while a path or compile-database problem may print a diagnostic and leave no usable result. Check both the exit status and the files:

$ find-all-symbols-20 -p /path/to/project/build \
    --output-dir=/tmp/find-all-symbols-results \
    /path/to/project/src/widget.cpp
$ status=$?
$ printf 'exit status: %s\n' "$status"
exit status: 0
$ find /tmp/find-all-symbols-results -maxdepth 1 -type f -size +0c -print
/tmp/find-all-symbols-results/widget.cpp-5ac549.yaml

Warning

If the status is non-zero, keep the diagnostic and fix the database, path or source error before you interpret any old files in the output directory. A stale YAML file can make a failed run look successful, which is why a fresh directory is safer for automation.

Done means

  • Right version. find-all-symbols-20 --version reports the expected LLVM 20.1.8 installation.
  • Database match. The selected source file is in the compile database and is analysed with its recorded compiler context.
  • Clean output. Results went to a fresh, separate directory and you inspected them as YAML records.
  • Repeatable. Multiple input files and any extra compiler argument are recorded.
  • Suspicious of silence. Empty output, stale output and non-zero exits are treated as things to investigate, not as an API inventory.