Build a Reliable Static Library Index with ranlib
After this guide, you will have a static archive containing an index of its object-file symbols, and a quick test that proves the index is usable. The examples use GNU ranlib from the installed binutils packages. Allow about 10 minutes if you already have a compiler, or 20 minutes 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 does not need elevated privileges unless the archive itself is writable only by root. Do not run it with sudo merely because a link failed: first check the file's ownership and permissions, 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 assuming that 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 have 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. Pick the name 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 the index-generation operation 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
Replace libsample.a with your real archive once you understand the operation. Before changing 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 another form of GNU ar: this operation is equivalent to ar -s libsample.a. The index is stored inside the archive, so the command changes the archive rather than producing a separate index file.
With GNU binutils configured for deterministic archives, deterministic mode is 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. Repeated builds are therefore less likely to differ only because metadata changed. If your build deliberately needs real archive metadata, -U disables deterministic mode. Do not add -U as a reflex; it makes reproducible output harder.
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 each exported function that a relocatable object defines. nm --print-armap libsample.a is the long form of the same inspection option. If the archive contains no suitable relocatable symbols, an empty or smaller index may be correct.
The index lets the linker find members by symbol instead of scanning every member in archive order. It also permits routines in the library to call each other without depending on where those members appear. It 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 check 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 from left to right, so placing libsample.a too early can cause an otherwise valid symbol to remain unresolved. That ordering problem is separate from 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 does 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 to get past the error. If you changed the wrong archive, stop using it and restore the saved copy:
$ cp --preserve=all libsample.a.before-ranlib libsample.a
Only use that restore command when the backup is known to be the intended pre-change version. It overwrites the current archive.
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 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 received 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.