Static Linking Rationale
Zynx favors static linking to simplify deployment and improve runtime predictability. While static linking is the default, Zynx also supports dynamic linking when deployment requirements, platform constraints, or integration needs call for it. This document summarizes the rationale for choosing static linking as the default without prescribing it as the only valid approach.
Advantages
1. Faster Startup
Statically linked programs do not require the OS to find and resolve external symbols from shared objects (.so, .dylib, or .dll) at runtime. This significantly reduces startup latency for CLI tools and large applications.
2. Whole-Program Optimization
Linking the entire codebase at once provides the compiler and linker with maximum visibility for:
- Link-Time Optimization (LTO): Deep optimizations across module boundaries.
- Dead Code Elimination (DCE): Stripping out unused functions and data structures with precision.
3. Dependency Independence
A statically compiled Zynx application is a single, self-contained executable. It eliminates "dependency hell" and "works on my machine" issues by packaging everything it needs to run.
4. Security and Predictability
Static linking reduces the attack surface by mitigating vectors like LD_PRELOAD attacks. It ensures the code running in production is byte-for-byte identical to the version tested in CI.
5. Cloud-Native and Container-Ready
Statically linked binaries are the perfect fit for modern containerized environments. A Zynx application can be deployed in a minimal Docker image (e.g., FROM scratch), resulting in image sizes of just a few megabytes. This drastically reduces network transfer costs, image pull times, and the container's security footprint.
6. Simpler Runtime Packaging for Cross-Compilation
Static outputs simplify deployment for cross-compiled builds because the runtime dependency surface is smaller. You still need the correct target sysroot/toolchain (typically via managed SDKs) to compile and link for non-host targets.
7. Drop-in Deployment
Distributing a Zynx application is as simple as copying a single executable file. There is no need for complex installers, package managers (RPM/DEB), or ensuring the host machine has specific runtime environments (like JRE or Node.js) installed.
Trade-offs of Static Linking
While Zynx defaults to static linking for its reliability, static and dynamic linking each have architectural trade-offs.
Redundant Disk and RAM Usage (in multi-application environments): Link-time optimization (LTO) and dead code elimination (DCE) can make a single statically linked Zynx binary compact. However, running many independent statically linked applications on the same host duplicates common code (such as the standard library) on disk and in memory for each process. In many containerized or single-application deployments this overhead is acceptable, but it can be significant in dense multi-tenant environments.
Security Patching: If a critical vulnerability is found in a low-level dependency (for example, a cryptographic library), the operating system cannot update a single shared object to patch all statically linked binaries at once. Each affected statically linked application must be rebuilt and redeployed. With dynamic linking, an updated shared library can mitigate the issue for all dependents, at the cost of looser coupling between build-time and runtime environments.
Dynamic Modules in Zynx
Dynamic module loading is documented in the language reference: Dynamic Modules.