Build and verify a MinGW archive index with ranlib
You will finish with a Windows-targeting static library that has a usable symbol index, then inspect that index with nm. The examples use the installed x86_64-w64-mingw32-ranlib from GNU Binutils 2.41.90.20240122, supplied by Debian package binutils-mingw-w64-x86-64.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, the MinGW-w64 binutils tools, and an archive such as libanswer.a. The workflow changes the archive file, so work on a copy if it is tracked, supplied by somebody else, or needed for a reproducible comparison. No command here needs sudo.
1. Confirm the installed command
The UCRT-flavoured alias has the same installed manual page and target behaviour, but the canonical command used below is x86_64-w64-mingw32-ranlib. Check both the path and version before debugging a build script:
$ command -v x86_64-w64-mingw32-ranlib
/usr/bin/x86_64-w64-mingw32-ranlib
$ x86_64-w64-mingw32-ranlib --version
GNU ranlib (GNU Binutils) 2.41.90.20240122
The installed package is version 2.41.90.20240122-1ubuntu1+11.4 on this machine. Version output is useful evidence when a build behaves differently on another host.
Checkpoint
If the command is missing, stop here and install or select the toolchain through your normal system process. Do not silently substitute the host's native ranlib; it may create an archive for the wrong object format.
2. Create or identify the archive
ranlib does not compile source files and does not create a library from nothing. It updates an existing archive by generating an index of symbols defined by relocatable object members. For a small, isolated test, create a MinGW object and archive it:
$ mkdir -p /tmp/ranlib-example
$ printf '%s\n' 'int answer(void) { return 42; }' > /tmp/ranlib-example/answer.c
$ x86_64-w64-mingw32-gcc -c /tmp/ranlib-example/answer.c \
-o /tmp/ranlib-example/answer.o
$ x86_64-w64-mingw32-ar rcs /tmp/ranlib-example/libanswer.a \
/tmp/ranlib-example/answer.o
For a real build, replace the path with your existing archive. Before running an archive-modifying command, check that the path is exactly the file you intend:
$ file /tmp/ranlib-example/libanswer.a
$ x86_64-w64-mingw32-ar t /tmp/ranlib-example/libanswer.a
answer.o
The archive is a binary file. Do not pass a directory, a source file, or a wildcard you have not inspected. If you need a reversible experiment, copy it first:
$ cp /path/to/libexample.a /tmp/libexample-test.a
3. Generate the symbol index
Run ranlib with one archive operand:
$ x86_64-w64-mingw32-ranlib /tmp/ranlib-example/libanswer.a
Successful operation is quiet and returns status zero. GNU ranlib is another form of GNU ar; this command is equivalent to x86_64-w64-mingw32-ar -s for the same archive.
There is no separate undo command. To undo this example, restore the copy you made before the change, or rebuild the archive with the same object members. Restoring a copy is safer than trying to edit the archive by hand.
Checkpoint
A zero exit status means that the archive was processed. It does not by itself prove that the index contains the symbol your linker needs.
4. Inspect the index and the members
Ask the matching MinGW nm to print the archive map:
$ x86_64-w64-mingw32-nm --print-armap /tmp/ranlib-example/libanswer.a
Archive index:
answer in answer.o
answer.o:
0000000000000000 T answer
The exact list can include format-specific sections such as .text and .pdata; the useful check is that the archive index names the exported object symbol and its member. The short spelling -s is equivalent to --print-armap:
$ x86_64-w64-mingw32-nm -s /tmp/ranlib-example/libanswer.a
...
Archive index:
answer in answer.o
...
If the archive has no index, the command may still list members, but a linker can need to scan more work or fail to resolve archive dependencies in the expected way. If the symbol is absent from the map, check that the object really defines it and that you used the matching target tools.
5. Choose deterministic metadata deliberately
The -D option makes the symbol-map member deterministic by writing zero values for its UID, GID and timestamp. If Binutils was configured with deterministic archives enabled, deterministic mode is already the default:
$ x86_64-w64-mingw32-ranlib -D /tmp/ranlib-example/libanswer.a
$ x86_64-w64-mingw32-nm --print-armap /tmp/ranlib-example/libanswer.a
Archive index:
answer in answer.o
Use -D when the command is part of a reproducible build and you want that choice to be visible in the build recipe. It does not make unrelated object files reproducible, and it does not sort or rewrite the archive members.
-U is the inverse: it requests non-deterministic metadata, including actual UID, GID, timestamp and file mode values for the index. That can make repeated outputs differ. Do not add -U merely to make a stale-looking index appear newer; use -t when you specifically need to update the symbol-map timestamp.
6. Diagnose the common failures
A missing or wrong archive path is an ordinary input error. The command exits non-zero and prints a diagnostic:
$ x86_64-w64-mingw32-ranlib /tmp/does-not-exist.a
x86_64-w64-mingw32-ranlib: '/tmp/does-not-exist.a': No such file
$ printf 'exit status: %s\n' "$?"
exit status: 1
Check the path with ls or file, then retry. Do not respond to a path error by using elevated privileges. Permissions can be the cause only when the file exists and your account cannot read or write it; in that case, fix ownership or the build directory through your normal administrative process.
If the index looks empty, inspect the archive members with ar t and inspect symbols with nm. An archive containing no relocatable object definitions has no useful symbol map. If the linker reports an undefined reference, confirm the library order in the link command as well as the index: ranlib cannot repair an incorrect dependency order or a symbol that was never compiled into the library.
The @file syntax can supply command-line options from a file, with whitespace separating options and quotes or backslashes preserving spaces. Keep such a response file under the same review and access controls as a shell script. It can itself refer to more @file inputs, so do not use an untrusted file path.
Done means
- You confirmed the target-specific
ranlibpath, version and package. - You checked that the archive path and object format were the ones you intended to modify.
- You generated the index and received exit status zero.
nm --print-armapshowed the expected symbol and archive member.- You chose
-D, the default, or-Uknowingly rather than relying on an unexplained timestamp change. - You have a copy or rebuild route if the archive must be restored.