ldd: Find Missing Shared Libraries in CI
ldd prints the shared libraries a dynamically linked binary depends on and shows "not found" against any the loader cannot locate.
When a downloaded or built binary fails to start with "error while loading shared libraries", ldd names the exact missing library so you can install it or pick a compatible build.
What it does
ldd resolves a binary’s dynamic dependencies the way the runtime loader would, listing each needed library and the path it resolves to, or "=> not found" when it cannot. It reveals which package provides a missing .so and exposes glibc vs musl mismatches (a glibc binary on Alpine fails because Alpine ships musl, not glibc).
Common usage
ldd ./myapp
ldd ./myapp | grep "not found" # just the missing libraries
ldd "$(command -v node)" # libraries a tool on PATH needs
# the underlying error this diagnoses:
# ./myapp: error while loading shared libraries: libssl.so.3: cannot open shared object fileOptions
| Form / flag | What it does |
|---|---|
| ldd <binary> | List dependencies and their resolved paths |
| -v | Verbose, including version information |
| -u | Report unused direct dependencies |
| grep "not found" | Filter to the unresolved libraries |
In CI
For "error while loading shared libraries: libX.so.N: cannot open shared object file", run ldd on the binary and look for => not found; the named library tells you which package to install (e.g. libssl.so.3 from openssl libraries). On Alpine, a glibc-linked binary shows nearly everything as not found because the musl loader is incompatible; use a glibc image or a musl build.
Common errors in CI
"not a dynamic executable" means the binary is statically linked (nothing to resolve) and is fine. On Alpine, ldd ./glibc-binary often errors or shows "Not a valid dynamic program" because musl’s ldd differs from glibc’s. Never run ldd on an untrusted binary on a sensitive host: it can execute the program in some implementations. The fix for a missing lib is installing its package or matching the libc.