4.5 KiB
libarchive.xcframework — S0 / S2 validation
Measured 2026-09-23 on Mac16,5 / macOS 26 (26A428), 16 cores. Artifact:
Lakr233/libarchive.xcframeworkreleaseupstream.27cbc7827172.2(package release0.1.1), slicemacos-arm64_x86_64.These two questions gate the
vphone-archivework: it is the program that is meant to replacegtar,bsdtar,unzipandzstdin one go, and both answers below decide whether that is possible at all.
S0 — is libzstd statically compiled in? YES
This is the blocking prerequisite. It matters because a libarchive built
without libzstd does not report "unsupported" — it silently routes .zst
through __archive_write_program and shells out to a zstd(1) on PATH.
That degradation is invisible to otool -L, and only fails on a machine that
does not have Homebrew — which is precisely the machine we care about.
Symbol evidence
archive_write_add_filter_zstd.c.o and archive_read_support_filter_zstd.c.o
reference only the ZSTD_* API and zero __archive_write_program_*
symbols. The in-library compressor (_archive_compressor_zstd_open /
_write / _close / _flush) is present, and libzstd's own implementation
(_ZSTD_compressStream2, _ZSTD_decompressStream, …) is defined in the
archive rather than undefined. 450 defined ZSTD_* symbols in total.
Runtime evidence (the one that counts)
A probe linking the static archive, run with no zstd(1) reachable:
$ env -i PATH=/usr/bin:/bin ./s0_zstd_probe out.tzst
details : libarchive 3.8.9 ... liblzma/5.8.3 ... libzstd/1.5.7 ...
entry : probe.txt
filter : zstd
format : GNU tar format
round trip: 180 bytes, byte-identical
OK
The same environment, the same file, the system tar:
$ env -i PATH=/usr/bin:/bin /usr/bin/tar -tf out.tzst
tar: Error opening archive: Can't initialize filter; unable to run program "zstd -d -qq"
That side-by-side is the whole argument for vphone-archive in one screen:
the system's libarchive is 3.7.4 with no libzstd in its version details
and has to spawn an external program; ours carries libzstd/1.5.7 and does
not. R15 is closed, and P0.5 does not have to start by adding a static
libzstd to the xcframework.
S2 — does the bundled liblzma have the multithreaded encoder? YES
vm export --max is xz level 9 with threads=0. If the MT encoder were
missing, threads=0 would silently fall back to one core — correct output,
minutes slower on a large bundle, and nothing in the API reports it.
lzma_version_string()→5.8.3,lzma_cputhreads()→16lzma_stream_encoder_mt()returnsLZMA_OK, so the encoder is linked in, not merely declared in the headerarchive_write_add_filter_xz.c.oreferences_lzma_stream_encoder_mtand_lzma_cputhreads, so libarchive's own build detected it too (HAVE_LZMA_STREAM_ENCODER_MT) and thethreadsoption is not a no-op
⚠️ The measurement trap — read this before re-running the probe
The first run said no MT benefit, and that was wrong.
| payload | threads=1 | threads=0 | speedup |
|---|---|---|---|
| 192 MiB | 18.90s | 18.31s | 1.03x |
| 1 GiB | 91.26s | 18.87s | 4.84x |
xz parallelises across blocks, and the automatic block size at preset 9 is roughly 3x the 64 MiB dictionary — about 192 MiB. A 192 MiB payload is one single block, so there is nothing to split and no amount of working MT support can show a speedup. The library was fine; the probe was too small.
Two things follow:
- Any future re-validation must use a payload well above ~192 MiB, or it will reproduce the same false negative.
vm export --maxon a bundle smaller than one block gets no MT benefit. That is arithmetic, not a regression — do not go looking for a bug.
Fallout for the admission rule (D2)
The probe binary's full dynamic dependency set, linking the static archive:
/usr/lib/libz.1.dylib /usr/lib/libbz2.1.0.dylib
/usr/lib/libiconv.2.dylib /usr/lib/libxml2.2.dylib
/System/Library/Frameworks/{CoreFoundation,Security}.framework
/usr/lib/libSystem.B.dylib
Every entry is under /usr/lib or /System/Library, so a vphone-archive
built this way passes the admission rule as-is.
Note that -llzma is not needed: the vendored liblzma is self-sufficient,
and linking without it produces a binary with no dynamic liblzma reference at
all. This is one fewer dynamic dependency than the migration plan assumed —
the plan's §2.1.1 table expected xz to link the system liblzma.5.