The .a file is a relic: Why static archives were a bad idea all along
Workarounds and Tools Around .a Limitations
- Several commenters describe existing practices that approximate the article’s proposed “static bundle”:
- Using
ld -r(partial linking) or custom tools to merge all.ofiles in a.ainto a single relocatable object, then hiding non-public symbols viaobjcopy(e.g.,--localize-hidden), or similar utilities likearmerge. - This preserves dead-code elimination (unlike
--whole-archive) while avoiding symbol leakage and per-object linking quirks.
- Using
- Others routinely unpack, rename, and re-
arthird‑party archives (notably “messy” ones like Boost), but notearscripting is brittle, especially with duplicate object names.
Symbol Visibility, Initialization, and API Design
- Comments emphasize that many of the article’s “gotchas” are better framed as API design mistakes:
- Don’t rely on static initialization order or auto-run constructors; prefer explicit
init()calls, ideally idempotent. - Use prefixes for exported symbols and mark all non-API functions/variables
staticor hidden.
- Don’t rely on static initialization order or auto-run constructors; prefer explicit
- Some point out nontrivial complications: nested dependencies, multithreaded initialization, and hiding implementation details across layered libraries.
Static vs Dynamic Linking: Security, Portability, and “DLL Hell”
- Strong defense of static linking:
- Single, self-contained binary is easier to reason about, sign, and test; fewer moving parts and less runtime attack surface.
- Avoids DLL/soname “hell” and aligns with containers’ popularity (seen as a workaround for dynamic-link complexity).
- Counterpoints:
- Dynamic libs allow end users to upgrade/fix vulnerabilities without rebuilding everything.
- Static binaries can’t be patched at the library level; “more secure” is context-dependent.
- Multiple commenters stress that both models have legitimate uses (plugins, language runtimes, LGPL constraints, unikernels, etc.).
Metadata, pkg-config, and Tooling
- Several argue the real problem is poor tooling and metadata, not
.aitself:pkg-configis defended as simple and sufficient when used correctly; CMake is blamed for emitting bad metadata.- Others claim
pkg-configscales poorly across compilers/flags and push newer formats like CPS.
- One proposal: evolve static archives to carry dependency metadata (like DT_NEEDED/DT_RPATH), so static linking can resolve dependencies and conflicts more like dynamic linking.
Dead Code Elimination and Size
- Multiple commenters note that many “bloat” examples are mitigated by:
-ffunction-sections -fdata-sections -Wl,--gc-sectionsand/or LTO.- Or per-function
.ofiles (traditional in some libcs) and header‑only patterns combined with inlining and LTO.
Shared Objects as Static Inputs and Historical Context
- Some wonder why
.sofiles can’t just be statically linked; replies note:.soare outputs of a lossy link step, PIC semantics, and interposition constraints differ from PIE executables.
- Historical note:
.abehavior originated as a performance/memory optimization on very constrained systems and still speeds linking large codebases. - Several think the title (“relic” / “bad idea all along”) is overblown; the consensus leans toward “static linking is under-evolved and poorly tooled,” not fundamentally wrong.