Skip to content

Proposal: .aea compiled module artifacts, so installed stdlib modules are not recompiled downstream #1746

Description

@nicolas-maman

Carried in docs/proposed-aea-lib.md, which is a design proposal rather than documentation of anything the toolchain does. The site generator publishes every top-level doc, so it was being served as a documentation page describing a feature that does not exist. Moved here verbatim.


Problem

make install currently gives downstream users two different kinds of
stdlib material:

  • $(PREFIX)/lib/aether/libaether.a: precompiled C runtime and C-backed
    stdlib support.
  • $(PREFIX)/share/aether/std/.../module.ae: Aether-authored stdlib
    modules installed as source.

That means top-level C-backed modules such as std.cryptography are already
available through the installed archive, while Aether-authored modules such as
std.cryptography.md2, std.cryptography.sha3, std.cryptography.blake2,
and the KDF/hash submodules are compiled again by each downstream application
that imports them.

This is functional, but it is not the experience users expect from a
first-class installed standard library. Java users do not think about whether
a package came from source or from a .jar; the import experience is the same.
Aether should aim for that same level of artifact transparency.

Goal

Compiled Aether stdlib modules should behave as if their sources were
co-located with the importing program.

For example:

import std.cryptography.md2

should mean the same thing whether the resolver uses:

  • a local source tree,
  • an installed share/aether/std/cryptography/md2/module.ae, or
  • an installed compiled module artifact.

The artifact is an implementation detail and cache boundary, not a new import
surface.

Non-goal

Do not make this a flattened C-grade experience.

An artifact such as:

$(PREFIX)/lib/aether/std.cryptography.md2.aea

must not degrade the user-facing model into "generated C plus a linker
archive". Users should not need to know generated C symbol names, object file
layout, or link ordering to import a normal Aether module.

Desired Developer Experience

The import path remains the API:

import std.cryptography.md2
import std.cryptography.sha3
import std.cryptography.pbkdf2

Diagnostics remain Aether diagnostics:

  • module names are reported as std.cryptography.md2, not generated C files;
  • exported functions are reported with their Aether signatures;
  • source locations map back to the original .ae module where possible;
  • ae help, doc generation, and import resolution see the same exported
    surface they would see from source.

Build tools should not have a separate "compiled stdlib import" path. The
normal module resolver should choose the best compatible backing artifact.

Proposed Artifact Shape

Use a first-class compiled Aether module archive, tentatively .aea.

One possible installed layout:

$(PREFIX)/lib/aether/modules/std/cryptography/md2.aea
$(PREFIX)/lib/aether/modules/std/cryptography/sha3.aea
$(PREFIX)/lib/aether/modules/std/cryptography/pbkdf2.aea

The exact path is open, but it should preserve module hierarchy rather than
flattening everything into opaque filenames.

Each .aea should contain structured metadata and compiler-owned payloads,
for example:

module.json
typed-ir.aeir
objects/<target-triple>.o
docs.json
source.map

Where:

  • module.json records module name, compiler version, Aether ABI version,
    target compatibility, build flags, imports, exports, and source hash.
  • typed-ir.aeir is a typed Aether IR payload, not generated C as the public
    contract.
  • objects/<target-triple>.o is an optional native object cache for targets
    where the artifact producer built one.
  • docs.json records exported docs and signatures for ae help and docgen.
  • source.map maps diagnostics and generated code back to original Aether
    source locations.

The object cache is allowed to be disposable. The typed IR and metadata are
the important first-class module boundary.

Resolver Behavior

Suggested precedence:

  1. local project source;
  2. explicit --lib source or artifact paths;
  3. compatible installed .aea artifact;
  4. installed source fallback under $(PREFIX)/share/aether/std/.../module.ae.

This preserves today's source-based behavior while allowing an installed
toolchain to skip recompiling stdlib Aether modules when a compatible artifact
exists.

Compatibility checks should include at least:

  • compiler version or IR format version;
  • Aether ABI version;
  • target triple or target family;
  • relevant compile flags and feature gates;
  • dependency artifact hashes;
  • stdlib/toolchain version.

If the artifact is missing or incompatible, the resolver should fall back to
source when source is installed.

Why This Matters

The current model pushes a compilation chore onto downstream applications.
Every clean build of an application that imports Aether-authored stdlib modules
must recompile those modules into the application.

That has costs:

  • slower downstream clean builds;
  • repeated work across applications;
  • less obvious installed artifact boundaries;
  • a split mental model where C-backed stdlib feels prebuilt but Aether-backed
    stdlib feels source-distributed.

A first-class .aea format fixes that without changing imports.

Open Design Questions

  • What typed IR is stable enough to serialize across patch releases?
  • Is .aea a per-module artifact, a package-level artifact, or both?
  • Should native object caches be mandatory or opportunistic?
  • How much whole-program analysis currently assumes source ASTs are available?
  • How are generic instantiations, closures, builders, and effect/capability
    checks represented in the artifact?
  • How does --emit=lib plus --with=fs,net,os capability gating interact
    with precompiled artifacts?
  • How does artifact invalidation work for local overlays, patched stdlib
    trees, and cross-compilation?

Success Criteria

This feature is successful when:

  • import std.cryptography.md2 works identically from source or .aea;
  • downstream applications do not need to recompile installed stdlib Aether
    modules on every clean build;
  • diagnostics and docs remain Aether-native;
  • installed source remains a fallback and debugging aid;
  • build tools can treat .aea as a normal module-resolver result, not a
    special linker-only input.

Filed while removing plan and proposal documents from docs/. Nothing about the proposal is decided by this move; it is a proposal in the place proposals belong.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions