Linking against a library and getting "no index" or a stale symbol is usually a job for ar, the tool that builds and edits static archives. You will create one from relocatable object files, inspect its members and symbol index, replace one member safely, and extract a copy for checking. The examples use GNU ar from GNU Binutils 2.42, installed here as package version 2.42-4ubuntu2.10. The prefixed commands aarch64-linux-gnu-ar and x86_64-linux-gnu-ar provide the same manual and command interface for their target toolchains.
Allow about fifteen minutes. You need a shell, a C compiler for the small test objects, and enough space in a working directory. Everything below is an ordinary user operation. Do not use sudo: a library in your project directory should normally be owned by your build user.
Confirm which executable will run and record its version before relying on details in a build script:
$ command -v ar
/usr/bin/ar
$ ar --version | head -1
GNU ar (GNU Binutils for Ubuntu) 2.42
The three installed manpages name the same GNU Binutils 2.42 implementation. The examples therefore describe this machine's behaviour, rather than assuming that every non-GNU ar accepts the same modifiers.
Checkpoint: if command -v ar points into a cross-toolchain directory, use that exact binary consistently. A library made for one object format is not automatically suitable for a different target.
Make two tiny relocatable objects. Keeping the source and output together makes the later archive listing easy to understand:
$ mkdir -p build-ar/src
$ printf '%s\n' 'int alpha(void) { return 1; }' > build-ar/src/alpha.c
$ printf '%s\n' 'int beta(void) { return 2; }' > build-ar/src/beta.c
$ gcc -c build-ar/src/alpha.c -o build-ar/src/alpha.o
$ gcc -c build-ar/src/beta.c -o build-ar/src/beta.o
$ file build-ar/src/alpha.o
build-ar/src/alpha.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
Use the compiler for the target you intend to link. For an AArch64 library, for example, compile with your AArch64 compiler and then use aarch64-linux-gnu-ar. The archive container does not convert object files between architectures.
Run rcs with the archive name followed by the object files:
$ cd build-ar
$ ar rcs libsample.a src/alpha.o src/beta.o
$ ar t libsample.a
alpha.o
beta.o
The letters mean replace or insert (r), create the archive if needed (c), and write or update its object-file index (s). The index helps the linker find definitions without requiring objects to appear in a particular order. GNU ar stores the member names without the src/ prefix in this normal archive.
Checkpoint: ask ar for the detailed table and inspect the index with nm:
$ ar tv libsample.a
rw-r--r-- 0/0 1224 Jan 1 01:00 1970 alpha.o
rw-r--r-- 0/0 1224 Jan 1 01:00 1970 beta.o
$ nm -s libsample.a
Archive index:
alpha in alpha.o
beta in beta.o
Exact object sizes and dates depend on the compiler and archive settings. The useful checks are the two member names and the symbol names in the archive index. On this installation deterministic archives are enabled by default, so the displayed owner and 1970 timestamp are expected. Use U only when you explicitly need real metadata rather than reproducible output.
Rebuild alpha.o, then use r again. A matching member name is replaced; a new name is appended:
$ printf '%s\n' 'int alpha(void) { return 10; }' > src/alpha.c
$ gcc -c src/alpha.c -o src/alpha.o
$ ar rv libsample.a src/alpha.o
r - src/alpha.o
$ ar t libsample.a
alpha.o
beta.o
Do not use q when you mean replacement. Quick append is intended to add members at the end and, in other implementations, may not refresh a symbol table. GNU ar treats qs as a synonym for r, but writing rcs makes the intended update clearer.
The u modifier restricts r to input files newer than matching archive members. It is not allowed with q, and it is ineffective when deterministic archive mode is in use because replacement always happens. For a deliberate rebuild, omit u.
Extraction writes files into the current directory unless you select another one. Use the long output option so the working tree stays tidy:
$ mkdir -p unpack
$ ar x --output unpack libsample.a alpha.o
$ file unpack/alpha.o
unpack/alpha.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
Omit alpha.o to extract every member. By default extracted files receive the extraction time. Add the o modifier, as in ar xo --output unpack libsample.a, to preserve the original member dates.
Extraction can overwrite an existing file with the same name. Before extracting into a non-empty directory, check it with ls, choose a new directory, or make a backup. If an extraction goes wrong, remove only the newly extracted copy after checking the path. The archive itself is not modified by x.
A thin archive stores references to the original object files instead of copying their contents. It can save time and space in a local build tree, but the referenced objects must remain where the archive expects them:
$ ar rcsT libthin.a src/alpha.o src/beta.o
$ ar t libthin.a
src/alpha.o
src/beta.o
T is the deprecated short alias for --thin; prefer ar rcs --thin libthin.a src/alpha.o src/beta.o when the distinction matters. A thin archive cannot be extracted with x. It is also a different format from a normal archive, and GNU ar cannot convert an existing archive from one format to the other in place. Create a new archive if you need to change format.
Do not copy a thin archive without also preserving the referenced objects and their relative paths. For a portable deliverable, use a normal archive and verify it with ar t before publishing it.
If the linker reports that a library has no index, add one with ar s libsample.a or run ranlib libsample.a, then check with nm -s libsample.a. If a member is missing, run ar t libsample.a without a member filter: a filtered listing shows only the first matching member when duplicate names exist.
If replacement affects the wrong object, remember that ordinary archives match by member name, not by the original path. The P modifier preserves full paths, but such archives are not POSIX compliant and may not work with other tools. Prefer unique object basenames for portable libraries.
For a failed command, check its status immediately with printf 'status: %s\n' "$?". Do not delete the only copy of a library while investigating. Recreate a normal archive from the original object files if its contents are suspect; that is the recovery path for an accidentally chosen thin archive or a damaged output.
ar --version identifies the intended GNU Binutils toolchain.ar t libsample.a lists the expected object members.nm -s libsample.a shows a usable archive symbol index.r and did not create a duplicate member.