A static library is just an archive of object files, and llvm-ar-18 is the tool that builds and inspects one. You will finish with a small archive, a repeatable way to inspect it, and a safe method for extracting or removing members. The examples use the installed llvm-ar-18 from Ubuntu package llvm-18, which reports LLVM version 18.1.3.
Allow about fifteen minutes. You need a shell and two object files, or any other ordinary files you are happy to copy into a test archive. Nothing here needs elevated privileges.
Confirm the command in your path is the one you actually intend to use. This is read-only:
$ command -v llvm-ar-18
/usr/bin/llvm-ar-18
$ llvm-ar-18 --version
Ubuntu LLVM version 18.1.3
Optimized build.
The local manual is generated from LLVM documentation and labels the tool llvm-ar, while this installation exposes the versioned command. The operation syntax is compact: one operation such as r or t, followed by any permitted modifiers, then the archive name and optional member names.
Checkpoint: if command -v finds a different path, stop and check your package or PATH before creating an archive.
Make a disposable workspace and two input files. If you are testing a real build, keep the source files outside the archive directory so you can compare them afterwards:
$ mkdir -p /tmp/llvm-ar-demo
$ cd /tmp/llvm-ar-demo
$ printf 'alpha\n' > alpha.txt
$ printf 'beta\n' > beta.txt
$ llvm-ar-18 rcs libdemo.a alpha.txt beta.txt
r replaces a member with the same name, or inserts a new one.c suppresses the warning that would normally announce creation of a missing archive.s creates the archive index linkers use to find externally visible symbols. LLVM ar builds that index by default anyway, but spelling out rcs makes the intended library-building operation obvious to anyone reading the script later.For object files, the same pattern is normally written as llvm-ar-18 rcs libexample.a file1.o file2.o. The files do not have to be objects though, the archive format happily holds other file types.
Verify both the member names and the exit status before using the archive in a build:
$ llvm-ar-18 t libdemo.a
alpha.txt
beta.txt
$ printf 'exit status: %s\n' "$?"
exit status: 0
Use t for a name-only table. Add v when ownership, mode, size and timestamp matter:
$ llvm-ar-18 tv libdemo.a
rw-r--r-- 0/0 6 Jan 1 01:00 1970 alpha.txt
rw-r--r-- 0/0 5 Jan 1 01:00 1970 beta.txt
Those zero ownership fields and 1970 timestamps are expected: LLVM ar writes deterministic archives by default, using zero timestamps and UIDs/GIDs so repeated builds are easier to compare. The U modifier opts into real timestamps and ownership values; reach for it only when another tool genuinely requires them.
The O modifier adds each member's byte offset inside the archive. Handy when diagnosing an archive made by another tool, not something you need for routine verification:
$ llvm-ar-18 tvO libdemo.a
rw-r--r-- 0/0 6 Jan 1 01:00 1970 alpha.txt 0x44
rw-r--r-- 0/0 5 Jan 1 01:00 1970 beta.txt 0x86
Extraction writes files into the current directory unless you pass --output. Pick a fresh destination so an archive member cannot silently overwrite a working file you actually care about:
$ mkdir extracted
$ llvm-ar-18 x --output extracted libdemo.a
$ find extracted -maxdepth 1 -type f -printf '%f: ' -exec cat {} \;
alpha.txt: alpha
beta.txt: beta
x extracts every member when no member names follow the archive. To extract just one, give its exact name after the archive, for example llvm-ar-18 x --output extracted libdemo.a alpha.txt. Extracted files get the extraction time by default; add o if you need the member's stored modification time preserved instead.
Warning: extraction can overwrite files already sitting in the destination. Use a new empty directory, or back things up first. To undo this example, remove only the disposable extracted directory after checking its contents, and do not run a broad recursive delete anywhere near source or build outputs.
To update an existing member, prepare the replacement and run r again:
$ printf 'new alpha\n' > alpha.txt.new
$ llvm-ar-18 r libdemo.a alpha.txt.new
$ llvm-ar-18 t libdemo.a
alpha.txt
beta.txt
alpha.txt.new
The member name comes from the input file name, so that inserted alpha.txt.new instead of replacing alpha.txt. Rename the prepared file first if the archive member needs to keep its original name:
$ mv alpha.txt.new alpha.txt
$ llvm-ar-18 rcs libdemo.a alpha.txt
$ llvm-ar-18 t libdemo.a
alpha.txt
beta.txt
Warning: before replacing a library a build actually depends on, copy it to a backup such as libdemo.a.bak first. If the result is wrong, restore it with mv libdemo.a.bak libdemo.a. That restore changes state, so double-check the path and backup name before running it.
Delete named members with d:
$ llvm-ar-18 d libdemo.a beta.txt
$ llvm-ar-18 t libdemo.a
alpha.txt
Deletion is destructive to the archive file. It will not touch the original input file on disk, but it can remove the only archived copy you had. Keep a backup when the archive is not disposable. A requested name that is absent is not treated as an error by the local manual, so verify the table afterwards rather than trusting the exit status alone.
A thin archive stores references to external files instead of copying their contents in. Create one explicitly with --thin:
$ llvm-ar-18 --thin rcs libthin.a alpha.txt beta.txt
$ llvm-ar-18 t libthin.a
alpha.txt
beta.txt
$ file libthin.a
# file reports a thin archive; the exact description varies by file(1) version
The member list looks like an ordinary archive, but moving or deleting alpha.txt can make the thin archive unusable. Keep referenced files at the paths the build expects, and treat the thin archive and those files as one unit. When you modify a thin archive without --thin, the local manual says it gets converted to a regular archive; make that choice explicit in scripts rather than relying on an accidental conversion.
Do not reach for --thin merely to shrink a library without checking your linker and packaging workflow. A thin archive is not self-contained and cannot safely replace a regular archive in a hand-off or release bundle.
pwd, then check each path with ls -l.r, q and d do nothing when no files are supplied.S only when you deliberately want no index, for example while investigating a format issue. A library meant for normal linking should keep its symbol table. When an archive mixes LLVM bitcode and native objects, LLVM ar includes both kinds of externally visible symbols in the index.--plugin option to add support for an unfamiliar format, and do not use the unsupported filename-truncation option f from another ar implementation. Check llvm-ar-18 --help on the installed version first.llvm-ar-18 --version identified the installed LLVM 18.1.3 executable.rcs and its member list checked with t.