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 .o files in a .a into a single relocatable object, then hiding non-public symbols via objcopy (e.g., --localize-hidden), or similar utilities like armerge.
    • This preserves dead-code elimination (unlike --whole-archive) while avoiding symbol leakage and per-object linking quirks.
  • Others routinely unpack, rename, and re-ar third‑party archives (notably “messy” ones like Boost), but note ar scripting 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 static or hidden.
  • 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 .a itself:
    • pkg-config is defended as simple and sufficient when used correctly; CMake is blamed for emitting bad metadata.
    • Others claim pkg-config scales 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-sections and/or LTO.
    • Or per-function .o files (traditional in some libcs) and header‑only patterns combined with inlining and LTO.

Shared Objects as Static Inputs and Historical Context

  • Some wonder why .so files can’t just be statically linked; replies note:
    • .so are outputs of a lossy link step, PIC semantics, and interposition constraints differ from PIE executables.
  • Historical note: .a behavior 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.