Build AArch64 Static Libraries with gcc-ar-13
aarch64-linux-gnu-gcc-ar-13 wraps ar so archiving AArch64 objects, including LTO ones, picks up the right GCC plugin automatically. You'll create a static library, inspect its members and symbol index, and see why plain ar can quietly break a link-time-optimised build. It's installed here as GCC package version 13.3.0-6ubuntu2~24.04.1cross1 with GNU Binutils 2.42.
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 AArch64 cross-compiler tools, and writable space for a small build. The commands create or replace an archive in the current directory; they don't need sudo, but pick a directory whose contents you can recover.
1. Confirm the wrapper and target
$ command -v aarch64-linux-gnu-gcc-ar-13
/usr/bin/aarch64-linux-gnu-gcc-ar-13
$ aarch64-linux-gnu-gcc-ar-13 --version
GNU ar (GNU Binutils for Ubuntu) 2.42
The manpage describes this as a wrapper around ar that adds the right --plugin option for GCC 13. It takes the normal ar options and arguments, just aimed at this compiler's plugin, it's not a different archive format under a new name.
Checkpoint
If the command is missing, stop here. Don't substitute the host ar until you've confirmed it targets AArch64 and your build genuinely doesn't need the GCC plugin.
2. Prepare object files first
Compile source to relocatable objects before touching the archiver. This keeps inputs in a build directory and writes only calc.o and message.o:
$ mkdir -p build/aarch64
$ aarch64-linux-gnu-gcc-13 -c calc.c -o build/aarch64/calc.o
$ aarch64-linux-gnu-gcc-13 -c message.c -o build/aarch64/message.o
$ file build/aarch64/math.o build/aarch64/message.o
build/aarch64/calc.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
build/aarch64/message.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
Your file wording may differ. What matters: both are relocatable AArch64 objects and the compiler exited clean. Keep the object files around, the archive stores members but isn't a substitute for your normal build outputs.
3. Create the archive and its symbol index
Use the familiar ar operation string rcs: replace or insert each named member, create the archive if it doesn't exist, and write an index:
$ aarch64-linux-gnu-gcc-ar-13 rcs build/aarch64/libexample.a \
build/aarch64/calc.o build/aarch64/message.o
$ test -s build/aarch64/libexample.a
$ aarch64-linux-gnu-gcc-ar-13 tv build/aarch64/libexample.a
rw-r--r-- 0/0 0000 Jan 1 01:00 1970 build/aarch64/calc.o
rw-r--r-- 0/0 0000 Jan 1 01:00 1970 build/aarch64/message.o
Dates and sizes there are just example output; the real result is one archive with the requested members. The s modifier writes the archive symbol table, letting a linker find a needed member without scanning every object.
Warning
Don't read rcs as a harmless append. The r replaces members with matching names. If the archive already holds objects you care about, copy it first or pick a new output name:
$ cp --preserve=all build/aarch64/libexample.a build/aarch64/libexample.a.bak
$ aarch64-linux-gnu-gcc-ar-13 rcs build/aarch64/libexample.a build/aarch64/calc.o
Recovery
Restore the backup after confirming nothing is using the archive, with cp --preserve=all build/aarch64/libexample.a.bak build/aarch64/libexample.a. That overwrites the current archive, so check both paths before running it.
4. Inspect members and symbols
Stick with the wrapper for archive work so the same plugin-aware tool covers the whole workflow. List members with t:
$ aarch64-linux-gnu-gcc-ar-13 t build/aarch64/libexample.a
build/aarch64/calc.o
build/aarch64/message.o
For a more useful check, ask the matching nm for the archive index and object symbols:
$ aarch64-linux-gnu-gcc-nm -s build/aarch64/libexample.a
Archive index:
add in build/aarch64/calc.o
format_message in build/aarch64/message.o
Your symbols will differ. An empty or stale index is a build problem even when the archive file itself exists, rebuild it with the wrapper's s operation if a prior command skipped it:
$ aarch64-linux-gnu-gcc-ar-13 s build/aarch64/libexample.a
The installed manpage covers gcc-ar-13, not gcc-nm; it's shown here because GCC ships matching plugin-aware wrappers for archive inspection. Check that companion command with command -v before scripting against it.
5. Keep LTO objects intact in a static library
When the library is part of an LTO build, compile with -flto and archive with gcc-ar. GCC's own documentation specifies these wrappers for static libraries carrying GIMPLE bytecode, so the archiver can load the compiler plugin:
$ aarch64-linux-gnu-gcc-13 -O2 -flto -c answer.c -o build/aarch64/answer.o
$ aarch64-linux-gnu-gcc-ar-13 rcs build/aarch64/libanswer.a build/aarch64/answer.o
$ aarch64-linux-gnu-gcc-ar-13 t build/aarch64/libanswer.a
build/aarch64/answer.o
$ aarch64-linux-gnu-gcc-nm -s build/aarch64/libanswer.a
Archive index:
answer in build/aarch64/answer.o
That confirms the member and index exist. It doesn't prove a later link will actually perform whole-program optimisation, the final link still needs an LTO-capable linker and the right options, usually -flto plus -fuse-linker-plugin where the toolchain requires it.
For a library meant to work with both LTO and ordinary linking, check how your compiler produces LTO objects. GCC 13 targets with linker-plugin support commonly use non-fat LTO objects. Never infer compatibility from the archive listing alone, run a small link test with the same compiler and target flags the real application uses.
Common traps
- Archive succeeds, link fails. Check three things separately: the objects are AArch64 relocatable, the archive was built with
aarch64-linux-gnu-gcc-ar-13or a deliberate equivalent, and the final link uses the AArch64 GCC driver with compatible plugin support. - Wrong architecture in the archive. Feeding AArch64 objects to a native x86-64 link doesn't make the archiver report the mismatch, it just stores members. Architecture gets checked when objects are compiled or linked, not archived.
- Destructive operations. The wrapper has no separate manifest or config file; options like
t,v,r,dandxall belong toar. Copy the archive and pick an empty extraction directory before usingdto delete members orxto extract over existing files.
Done means
- Wrapper confirmed:
aarch64-linux-gnu-gcc-ar-13 --versionreports the installed GNU Binutils version. - Archive contents right: it contains the intended AArch64 object members.
- Index present: checked with
gcc-nm -sor a successful link. - LTO handled: any LTO objects were archived with the GCC wrapper, and the final link plan includes compatible LTO support.
- Nothing overwritten by accident: no existing archive was replaced without a deliberate backup or a new output path.