Library Loading¶
Lonala namespaces are loaded from an embedded tar archive bundled into the root task ELF.
Archive Format¶
The standard library is packaged as a USTAR tar archive (lonalib.tar) with no compression. Files are organized by namespace path:
lonalib.tar
├── lona/
│ ├── core.lona # Bootstrap (loaded first)
│ ├── init.lona # Init process
│ └── ...
└── ...
Namespace resolution follows Clojure conventions:
| Namespace | File Path |
|---|---|
lona.core |
lona/core.lona |
lona.process |
lona/process.lona |
my.app.server |
my/app/server.lona |
Embedding¶
The archive is embedded at compile time using Rust's include_bytes! macro:
This places the archive in the ELF's .rodata section, which seL4 maps read-only when loading the root task. Benefits:
- Single artifact — one ELF file to deploy
- Cross-platform — works identically on x86_64 and aarch64
- Zero-copy — archive bytes accessed directly from mapped memory
Namespace Resolution¶
The NamespaceSource trait abstracts namespace lookup, enabling multiple backend implementations:
/// Abstraction for namespace file lookup.
pub trait NamespaceSource {
/// Resolve a namespace to its source bytes.
/// e.g., "lona.core" → contents of lona/core.lona
fn resolve(&self, namespace: &str) -> Option<&[u8]>;
}
TarSource¶
The TarSource struct wraps the embedded archive and implements NamespaceSource:
pub struct TarSource<'a> {
archive: TarArchiveRef<'a>,
}
impl TarSource<'static> {
/// Create from embedded archive
pub fn embedded() -> Result<Self, TarSourceError>;
}
impl<'a> TarSource<'a> {
/// Iterate over all entries
pub fn entries(&self) -> impl Iterator<Item = ArchiveEntry<'a>>;
}
impl NamespaceSource for TarSource<'_> {
fn resolve(&self, namespace: &str) -> Option<&[u8]>;
}
Each ArchiveEntry provides:
- filename() — returns the file path
- data() — returns the file contents as &[u8]
ChainedSource¶
The ChainedSource struct combines multiple sources with priority ordering (first match wins):
pub struct ChainedSource<'a> {
sources: &'a [&'a dyn NamespaceSource],
}
impl<'a> ChainedSource<'a> {
/// Create from a slice of sources (first match wins)
pub const fn new(sources: &'a [&'a dyn NamespaceSource]) -> Self;
}
impl NamespaceSource for ChainedSource<'_> {
fn resolve(&self, namespace: &str) -> Option<&[u8]>;
}
This enables patterns like local filesystem overriding embedded sources during development.
Build Process¶
build.rscreateslonalib.tarfromlib/directory using USTAR format- Cargo embeds the tar via
include_bytes! - Root task initializes
TarSourceat boot and lists embedded files