When you install Aether (make install or ./install.sh), the
toolchain + headers + sources + module descriptors land under a
single $PREFIX (default ~/.aether):
$PREFIX/
├── bin/ # toolchain binaries
│ ├── ae # the user-facing CLI (`ae build`, `ae run`, …)
│ ├── aetherc # the compiler (lower-level; ae usually wraps)
│ └── aether-lsp # language server (install.sh only, if built;
│ # `make install` does not install it)
│
├── lib/aether/
│ └── libaether.a # prebuilt static archive, link target for downstream
│ # programs / libraries that compile against the runtime
│
├── include/aether/ # public headers, mirrors source-tree layout
│ ├── runtime/
│ └── std/
│
└── share/aether/
├── MANIFEST # authoritative list of link-suitable .c files
├── runtime/ # runtime C sources (the actor scheduler, memory,
│ # panic/try-catch, sandbox, etc.)
├── std/ # stdlib sources + module.ae descriptors
└── contrib/ # contrib module.ae descriptors + headers
# (matching libaether_<x>.a archives come from
# `make install-contrib`; this dir alone gives
# downstream `import contrib.X` resolution
# without the .a archive)
Two consumption shapes, in priority order:
-
Link against
libaether.a(recommended). Every Aether runtime + stdlib.cfile that ships compiles into this single archive. The canonical recipe for the include + link flags is:gcc your.c $(ae cflags) -o your-programae cflagsresolves to the right-I<prefix>/include/aether/...plus-L<prefix>/lib/aether -laetherplus the OS-level deps (-pthread -lm, plus-lssl -lcrypto -lz -lnghttp2 -ldlif the build picked them up at install time). It works identically for in-tree dev builds,~/.aetheruser installs, and/usr/localsystem installs.Do not hand-craft
-L/-l:libaether.alives at<prefix>/lib/aether/libaether.a(under theaether/subdir, not flat under<prefix>/lib/), so a bare-laetherwill fail to resolve without the explicit-L<prefix>/lib/aether.tools/ae.citself uses this same path, seecmd_cflagsfor the construction.ae buildis tolerant of a package that ships the archive flat at<prefix>/lib/libaether.ainstead: it tries the canonical nested path first and falls back to the flat one before resorting to the compile-from-source path below. The nested layout is still the canonical oneinstall.shandmake installproduce. -
Compile from source, falling through to the
.cfiles inshare/aether/. This is whatae builddoes whenlibaether.aisn't found. It's also what tooling like aetherBuild'saeb-linkdoes.In this mode, read
share/aether/MANIFESTto discover which.cfiles to compile. The MANIFEST is the authoritative list, one path per non-comment, non-empty line, paths relative toshare/aether/. Naivefind runtime -name '*.c'walks would pull in benchmarks, orphaned poller hubs, and other source that isn't link-suitable.# Read MANIFEST + build the link command: cd $PREFIX/share/aether src=$(grep -v -E '^(#|$)' MANIFEST) gcc your.c $src -I $PREFIX/include/aether/runtime -I $PREFIX/include/aether/std \ -pthread -lm -lssl -lcrypto -lz -lnghttp2 \ -o your-program
# Aether MANIFEST, link-suitable C source files for
# downstream consumers compiling against the runtime/std
# source tree (e.g. aetherBuild's aeb-link). Generated by
# the Makefile; do not edit by hand. Regenerated on every
# `make stdlib`.
#
# Format: one path per non-comment, non-empty line. Paths
# are relative to this install root (share/aether/ on a
# system install; the repo root in the source tree).
# Lines starting with '#' are comments.
# Runtime sources:
runtime/scheduler/multicore_scheduler.c
runtime/scheduler/scheduler_optimizations.c
runtime/aether_runtime.c
…
# Standard library sources:
std/string/aether_string.c
std/http/server/h2/aether_h2.c
…
The MANIFEST is generated from RUNTIME_SRC + STD_SRC in the
Makefile so it always matches what we actually link into
libaether.a. The build target is build/MANIFEST; both
make install and install.sh copy it into
$PREFIX/share/aether/MANIFEST.
make install and install.sh deliberately trim a few directories
that aren't link-suitable:
runtime/examples/standalone benches with their ownmain(). Compiling these into a downstream link would produce duplicate-mainlink errors.runtime/io/orphaned poller dispatch hub plus four platform variants from an earlier design iteration. The active poller variants live underruntime/scheduler/aether_io_poller_*.c; the orphaned dir would produce missing-typedef errors if a downstream tool tried to compile it.contrib/<X>/{tests,benchmarks,example_*.ae,test_*.sh,build.sh, ci.sh,*.m}, contrib source-tree noise..cfiles are also dropped EXCEPT the host-language bridges atcontrib/host/<lang>/aether_host_<lang>.c. The bridges ship as source becausemake installdoes NOT also build/installlibaether_host_<lang>.aonlymake install-contribdoes that, and it's a separate opt-in step (because each bridge needs the matching dev library:python3-dev,liblua5.4-dev, etc.). Downstream apps thatimport contrib.host.<lang>from a plainmake installtree compile the bridge as source into their own build. The matchinglibaether_<X>.aarchives carry the C side for everything else; onlymodule.aedescriptors + public headers ship undershare/aether/contrib/.
Apps that #include runtime/std headers and link against
libaether.a from a plain make install tree must compile with
the same preprocessor defines the install was built with,
otherwise the header-side macros and the library-side symbols
disagree. The flag that matters:
-
-DAETHER_HAS_SANDBOX, gatesaether_sandbox_check(). When defined,runtime/aether_sandbox.hprovides astatic inline aether_sandbox_check()that consults the global_aether_sandbox_checker(defined inlibaether.a); when undefined, the header replaces it with a no-op macro that always returns 1. There's no linker error on skew, the function is inline in both branches, so a build that compiles the header without the flag silently loses sandbox enforcement even when linked against a sandbox-enabled library. The shippedlibaether.ais always built with this flag (seeCFLAGSin the Makefile, which carries-DAETHER_HAS_SANDBOX), so downstream consumers should compile with it too. -
Any future
AETHER_HAS_*flags introduced for optional runtime subsystems will follow the same pattern.
The version stamp at lib/aether/VERSION catches the
ae-vs-libaether version skew separately; the define skew is its
own thing and silent unless a symbol is actually missing.
The MANIFEST never references trimmed paths, the regression test
at tests/integration/install_manifest/ verifies this on every
build.
Three options were considered for cleaning up the install layout:
-
(A) Drop runtime/std sources entirely. Header-only
include/+ prebuiltlibaether.a+module.aeresolver descriptors. Cleanest, but breaks the source-fallback path intools/ae.cthat runs whenlibaether.ais missing (e.g. cross-built / partial installs). -
(B) Ship
MANIFEST(the shipped choice). Conservative, keeps the source-fallback path working as a backstop, gives downstream tools an authoritative list, no breakage. -
(C) Status quo + docs only. Low-touch, but doesn't help consumers who write naive
findwalks and trip onruntime/examples//runtime/io/.
Chose B. If a future downstream consumer needs the static-only shape, Option A can land additively (the MANIFEST stays useful either way).