Build and Inspect a MinGW-W64 Static Library with ar
x86_64-w64-mingw32-ar packs your Windows x86-64 object files into a single static library you can hand to the linker later. This guide covers GNU Binutils 2.41.90.20240122, from Debian package binutils-mingw-w64-x86-64 version 2.41.90.20240122-1ubuntu1+11.4. The x86_64-w64-mingw32ucrt-ar name is an alias for the same archive tool in the installed manpage set.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell, the MinGW-W64 binutils package, and files you are allowed to read. The examples write only to a new working directory and need no elevated privileges. Swap in your own object files when you are ready.
1. Confirm the toolchain before changing files
Check both the command and the package version first:
$ x86_64-w64-mingw32-ar --version
GNU ar (GNU Binutils) 2.41.90.20240122
$ dpkg-query -W -f='${Package} ${Version}\n' binutils-mingw-w64-x86-64
binutils-mingw-w64-x86-64 2.41.90.20240122-1ubuntu1+11.4
An archive is not a compiler output directory, it is one file containing members such as .o files. You can pass it to a linker later, but ar itself does not compile source code or link an executable.
Checkpoint
If the version command fails, stop here and fix the toolchain path or package install. Do not fall back to the host's unprefixed ar without checking its target format.
2. Create a normal static archive
Use r to replace a member with the same name or insert it if it is new. Add c to say that creating the archive is expected, and s to create or update the archive's symbol index:
$ mkdir -p build/lib-demo
$ cd build/lib-demo
$ x86_64-w64-mingw32-ar rcs libdemo.a calc.o strings.o
In a real build, calc.o and strings.o come from the MinGW-W64 compiler. If either file is missing, ar reports an error and leaves any existing matching member untouched. New members are appended by default.
Read the compact command as operation r plus modifiers c and s. You can write it with a leading dash if you prefer, but keep operation and modifiers together so the command stays easy to spot in build logs.
Checkpoint
The command should return status 0 and create libdemo.a. Verify that without opening a file browser:
$ test -s libdemo.a && printf '%s\n' 'archive created'
archive created
3. Inspect members and the index
Use t to list member names. Add v for permissions, owner, group, size and timestamp, or O for archive offsets:
$ x86_64-w64-mingw32-ar t libdemo.a
calc.o
strings.o
$ x86_64-w64-mingw32-ar tv libdemo.a
rw-r--r-- 0/0 123 Jan 1 01:00 1970 calc.o
rw-r--r-- 0/0 456 Jan 1 01:00 1970 strings.o
The zero ownership and epoch-like timestamp look odd but are expected: deterministic archives are on by default, which keeps repeated builds reproducible when the inputs and options match. Need real metadata preserved instead? U disables deterministic mode, at the cost of making the result depend on local file metadata.
A library needs an object-file index for normal linking. The s modifier creates it during the update. To rebuild the index on an existing archive, run the equivalent of ranlib:
$ x86_64-w64-mingw32-ar s libdemo.a
$ x86_64-w64-mingw32-nm -s libdemo.a
Deliberately built the archive with S? Then it has no symbol table and cannot be linked until you rebuild the index. Useful while assembling a large library in stages, but drop S on the final update, or run ar s afterwards.
Checkpoint
ar t libdemo.a should show every intended member, and the final archive should have an index before it reaches the linker.
4. Update or remove a member carefully
Run the same rcs command once an object has been rebuilt:
$ x86_64-w64-mingw32-ar rcs libdemo.a calc.o strings.o
Members with matching names get replaced, new names get appended. Add u as rcsu only when timestamp comparison genuinely helps. The installed manual disallows qu, and deterministic mode makes u a no-op anyway because replacement is always selected. Check the result with t after an update.
Warning
Deletion is irreversible from the archive's point of view.
$ cp libdemo.a libdemo.a.before-delete
$ x86_64-w64-mingw32-ar d libdemo.a strings.o
$ x86_64-w64-mingw32-ar t libdemo.a
calc.o
That copy is your recovery path. Made a mistake? Restore it with an ordinary file move or copy from libdemo.a.before-delete. Do not delete the backup until the consuming build has passed. No sudo needed unless you deliberately put the archive somewhere your user cannot write.
5. Extract a member into a controlled directory
Extraction writes files to disk, so use a new directory and name the member explicitly when you only need one:
$ mkdir -p extracted
$ x86_64-w64-mingw32-ar x --output extracted libdemo.a calc.o
$ test -f extracted/calc.o && printf '%s\n' 'member extracted'
member extracted
--output picks the destination, but x is still required. Leave it out and the current directory is used instead. Add o if the extracted file needs to keep its original archive date rather than the extraction time.
Warning
Do not extract an untrusted archive into a directory containing anything important. GNU ar restricts paths in archives during ordinary extraction, including rejecting absolute paths and parent-directory components, but a full-path archive built with P is less portable and needs particular care. Review the listing first, then extract to a disposable directory.
Thin archives are a separate case. A thin archive stores references to the original member files rather than their contents, so its members cannot be extracted with x. That suits a local build tree whose objects stay put, not a self-contained library you plan to copy elsewhere.
6. Keep paths and target formats explicit
By default, matching goes by member name rather than the full input path. The P modifier preserves full paths, but archives built that way are not POSIX compliant and may not work with older tools. Avoid it unless the path is part of a deliberate, tested archive layout.
Need to inspect an archive for a different object format? Use --target with a supported BFD name. Ask the installed binary for its accepted targets rather than guessing:
$ x86_64-w64-mingw32-ar --help | sed -n '/supported targets:/p'
x86_64-w64-mingw32-ar: supported targets: pe-x86-64 pei-x86-64 pe-bigobj-x86-64 ...
Keep the target setting consistent with the objects you are packaging. A successful archive operation does not prove a later linker can combine incompatible object formats.
Done means
- Confirmed the toolchain. The version and target-specific
x86_64-w64-mingw32-arcommand were checked. - Built the archive. It was created with
r,cands, and its member list was checked. - Verified the index. The symbol index is present, or the deliberate
Schoice was followed byar s. - Backed up before deleting. Updates and deletions have a verified listing, with a backup made before destructive changes.
- Extracted safely. Extraction, when needed, went to a controlled directory, and thin archives were not treated as self-contained.