Build a Reliable Static Library Index with ranlib
ranlib builds the symbol index inside a static archive that lets a linker find the right object file by function name instead of scanning blindly. After this guide, you will have a static archive containing that index and a quick test proving it actually works. The examples use GNU ranlib from the installed binutils packages, and allow about 10 minutes if you already have a compiler, or 20 if you need to identify the right archive and back it up first.
The route
Jump straight to the step you need, or tick off Done means at the end.
Use an ordinary user account. ranlib rewrites the archive file, but it needs no elevated privileges unless the archive itself is writable only by root. Do not reach for sudo just because a link failed, check the file's ownership and permissions first, and keep a copy if the archive is valuable.
1. Check the installed tools
The local manpages describe binutils 2.42, packaged here as 2.42-4ubuntu2.10. The unprefixed executable on this host reports GNU Binutils 2.47.20260726, while the AArch64 and x86-64 aliases report GNU Binutils 2.42. Check your PATH rather than assume the manpage and executable came from the same installation:
$ command -v ranlib aarch64-linux-gnu-ranlib x86_64-linux-gnu-ranlib
$ ranlib --version | head -n 1
$ aarch64-linux-gnu-ranlib --version | head -n 1
$ x86_64-linux-gnu-ranlib --version | head -n 1
$ dpkg-query -W -f='${binary:Package}\t${Version}\n' \
binutils-aarch64-linux-gnu binutils-common:amd64 binutils-x86-64-linux-gnu
All three manpages share the same interface: an archive argument, an optional plugin, and the -D, -U, -t, help and version options. The prefixed names select a target-specific tool, so pick the one that matches the objects in your build, or use the unprefixed tool for the host toolchain.
2. Make a small archive without an index
An archive is a collection of object files, normally ending in .a. This example creates two objects and uses ar rc, deliberately leaving index generation for the next step:
$ mkdir -p /tmp/ranlib-demo
$ cd /tmp/ranlib-demo
$ cat > alpha.c <<'EOF'
int alpha(void) { return 1; }
EOF
$ cat > beta.c <<'EOF'
int beta(void) { return 2; }
EOF
$ cc -c alpha.c beta.c
$ ar rc libsample.a alpha.o beta.o
$ ar t libsample.a
alpha.o
beta.o
Swap libsample.a for your real archive once you understand the operation, and before touching a shared or release artefact, make a recoverable copy:
$ cp --preserve=all libsample.a libsample.a.before-ranlib
That copy is your undo path. ranlib has no inverse command that restores the previous bytes.
3. Generate the symbol index
Run ranlib with the archive as its final argument:
$ ranlib libsample.a
$ printf 'ranlib exit status: %s\n' "$?"
ranlib exit status: 0
A successful, silent run is normal. GNU ranlib is really another form of GNU ar: this operation is equivalent to ar -s libsample.a. The index lives inside the archive itself, so the command changes the archive rather than producing a separate index file.
With GNU binutils configured for deterministic archives, deterministic mode is already the default. Use -D when you want to state that requirement explicitly:
$ ranlib -D libsample.a
In this mode the symbol-map header uses zero for its UID, GID and timestamp, so repeated builds are less likely to differ purely because metadata changed. If your build genuinely needs real archive metadata, -U disables deterministic mode. Do not add -U as a reflex, it makes reproducible output harder to get back.
4. Inspect the index
Use GNU nm's archive-index option to see which symbols the index records:
$ nm -s libsample.a
Archive index:
alpha in alpha.o
beta in beta.o
alpha.o:
0000000000000000 T alpha
beta.o:
0000000000000000 T beta
The exact addresses and object formatting depend on the target, but the Archive index: section should name every exported function that a relocatable object defines. nm --print-armap libsample.a is the long form of the same inspection. If the archive holds no suitable relocatable symbols, an empty or smaller index can be entirely correct.
- Finds members by symbol instead of forcing the linker to scan every member in archive order.
- Lets routines in the library call each other without depending on where those members appear.
- Does not make a shared library, change symbol visibility, or fix an object compiled for the wrong architecture.
5. Test the archive in a link
Inspecting the map is useful, but a tiny link is the practical proof that the library can satisfy a reference:
$ cat > main.c <<'EOF'
#include <stdio.h>
int alpha(void);
int main(void) { printf("%d\n", alpha()); return 0; }
EOF
$ cc main.c libsample.a -o sample
$ ./sample
1
Place the archive after the object or source that refers to it. Traditional linkers scan static archives left to right, so putting libsample.a too early can leave an otherwise valid symbol unresolved. That is an ordering problem, not a missing ranlib index.
6. Handle timestamps and failures carefully
-t updates the archive symbol-map timestamp. It is useful when a build system needs that timestamp refreshed, but it is not a general rebuild command and it will not add missing object files:
$ ranlib -t libsample.a
$ nm -s libsample.a | sed -n '1,5p'
Expect a non-zero status and a diagnostic when the archive cannot be found:
$ ranlib missing-library.a
ranlib: 'missing-library.a': No such file
$ printf 'status: %s\n' "$?"
status: 1
For a permission error, check ls -l, the directory permissions, and whether another process is replacing the file. Do not make a library world-writable just to get past the error.
Recovery
If you changed the wrong archive, stop using it and restore the saved copy, only when you are sure the backup is the intended pre-change version, since it overwrites the current archive:
$ cp --preserve=all libsample.a.before-ranlib libsample.a
7. Use a target-specific alias when required
aarch64-linux-gnu-ranlib and x86_64-linux-gnu-ranlib are aliases for the cross and native target toolchains installed here. They accept the same ranlib options. Use the AArch64 alias for an archive of AArch64 objects, and the x86-64 alias for x86-64 objects:
$ aarch64-linux-gnu-ranlib -D libaarch64.a
$ x86_64-linux-gnu-ranlib -D libx86_64.a
Do not infer the target from the archive's filename. Confirm an object with file object.o, or use the compiler and archiver from the same toolchain. A correct index cannot reconcile incompatible machine code.
Done means
- You checked which ranlib executable and binutils version your PATH selects.
- You generated the archive index and got exit status 0.
nm -sornm --print-armapshows the expected symbols.- A small link using the archive succeeds, with the archive in the right order.
- You used deterministic mode where reproducible archive metadata matters.
- You kept a backup before changing an important archive and know how to restore it.