Index a GCC 13 Static Library with gcc-ranlib
A static archive without a symbol index still links, right up until the linker cannot find a function you know is in there. x86_64-linux-gnu-gcc-ranlib-13 writes that index: it is a GCC 13 wrapper around ranlib whose only real trick is supplying the GCC plugin option for you.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide applies to the installed Ubuntu toolchain checked here: gcc-13 and gcc-13-x86-64-linux-gnu are version 13.3.0-6ubuntu2~24.04.1. The wrapper invokes the ranlib found through PATH, so the exact version printed by the delegated program can differ from the Debian package version. Allow about five minutes if GCC and binutils are already installed.
1. Know what the wrapper changes
The four installed manpage names in this toolchain describe the same program. The wrapper accepts ranlib options and archive arguments, then adds an appropriate --plugin option for GCC 13. It does not compile source, create an archive, or install a library: creating an archive is the job of ar, indexing it is the job of ranlib or the equivalent ar -s.
Check the executable and its delegated version first:
$ command -v x86_64-linux-gnu-gcc-ranlib-13
/usr/bin/x86_64-linux-gnu-gcc-ranlib-13
$ x86_64-linux-gnu-gcc-ranlib-13 --version
GNU ranlib (GNU Binutils) 2.47.20260726
...
Your version text may differ. What matters here is that the command exists and exits successfully. If it is missing, check the installed GCC and cross-toolchain packages before changing PATH.
2. Create a test object
Use a temporary directory so the exercise does not alter a project. This command needs no elevated privileges.
$ workdir=$(mktemp -d)
$ cd "$workdir"
$ cat > answer.c <<'EOF'
int answer(void) { return 42; }
EOF
$ x86_64-linux-gnu-gcc-13 -c answer.c -o answer.o
Checkpoint
answer.o should now exist. A compiler error here concerns the source or compiler, not ranlib. Confirm the target file before continuing:
$ test -f answer.o && echo "object ready"
object ready
3. Make the archive
Create a conventional static library with ar. The r operation replaces or adds members, and c creates the archive without a warning if it is new.
$ x86_64-linux-gnu-ar rcs libanswer.a answer.o
$ x86_64-linux-gnu-ar t libanswer.a
answer.o
If your installation uses a different ar name, inspect the available names with command -v. Do not guess a path in a build script: tool names vary between distributions.
4. Write the symbol index
Run the GCC 13 wrapper against the archive. This changes libanswer.a in place by writing or refreshing its archive index; it does not change answer.o.
$ x86_64-linux-gnu-gcc-ranlib-13 libanswer.a
$ echo $?
0
There is normally no output on success. A non-zero status means the archive could not be read or updated, or that an option was invalid.
Warning
There is no separate undo command for an in-place index update. Keep the original archive, or rebuild it, if a failed operation matters to your workflow.
5. Verify the index and link
Use nm to print the archive map. The symbol from answer.o should appear, proving the index names the function a linker can find.
$ x86_64-linux-gnu-nm -s libanswer.a
Archive index:
answer
answer.o:
0000000000000000 T answer
Output formatting can vary with binutils, but look for an Archive index: section and the answer symbol. If it is absent, rerun the wrapper against the exact archive you are inspecting: a frequent trap is updating one copy and linking another.
Finish with a link test. This creates a second temporary executable and makes the result observable:
$ cat > main.c <<'EOF'
int answer(void);
int main(void) { return answer() == 42 ? 0 : 1; }
EOF
$ x86_64-linux-gnu-gcc-13 main.c -L. -lanswer -o check-answer
$ ./check-answer
$ echo $?
0
-L. makes the current temporary directory eligible for library lookup, while -lanswer selects libanswer.a. If the link reports an undefined reference, check the archive name, the library search path and the symbol spelling before blaming the index.
6. Use the extra options
The wrapper passes ranlib options through:
--helpshows the installed usage.--versionshows the delegated binutils version.-Dwrites deterministic archive metadata: UID, GID and timestamp fields in the symbol-map member become zero, which helps reproducible builds. The local ranlib documentation says this is on by default when binutils was configured for deterministic archives.-Urequests the opposite of-D.
$ x86_64-linux-gnu-gcc-ranlib-13 --help
$ x86_64-linux-gnu-gcc-ranlib-13 -D libanswer.a
Do not pass a source file and expect compilation, and do not use this command to add or remove archive members: use the appropriate compiler or ar command for that. Ordinary archive work does not require sudo; elevated privileges can leave root-owned build artefacts that your normal account cannot replace.
Common traps
- Command not found: confirm the cross compiler tools are installed and inspect
PATH. The aliasesgcc-ranlib,gcc-ranlib-13andx86_64-linux-gnu-gcc-ranlibmay resolve to the same wrapper, but use the versioned triplet name when a build must select GCC 13 explicitly. - No archive index: make sure
arcreated a real archive and that ranlib received the archive path, not the object path. Runx86_64-linux-gnu-ar t libanswer.athenx86_64-linux-gnu-nm -s libanswer.a. - Plugin error: inspect
PATHand the GCC installation rather than adding a random--pluginpath. The wrapper exists to supply the appropriate plugin argument for its GCC 13 installation. - Link still fails: confirm the library is named
libanswer.a, that-Lpoints at its directory, and that the object exports the expected symbol. Runnm answer.oto compare the symbol name.
Done means
- Wrapper works:
x86_64-linux-gnu-gcc-ranlib-13 --versionexits successfully. - Archive complete: it contains the intended object member.
- Index present:
nm -sshows the archive index and expected symbol. - Link test passed: a test link and execution return status zero.
- Cleanup done: the temporary directory was removed with
rm -rf -- "$workdir"once the test was complete, using the workdir path, not a guess.