Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Custom Embedded Applications

For most standalone binaries, graphix package build-standalone is the simplest approach — see Standalone Binaries. This section covers the more advanced case where you need full control: custom module resolvers, embedded REPLs, compiler flags, or integration with your own Rust application.

Using the graphix-shell crate you can build a custom Graphix application. All installed packages are automatically registered, so your application gets the full standard library and any additional packages out of the box.

Basic Application

#![allow(unused)]
fn main() {
use anyhow::Result;
use graphix_compiler::expr::Source;
use graphix_rt::NoExt;
use graphix_shell::{Mode, ShellBuilder};
use netidx::{
    publisher::{DesiredAuth, PublisherBuilder},
    subscriber::Subscriber,
};

pub async fn run(cfg: netidx::config::Config, auth: DesiredAuth) -> Result<()> {
    let publisher = PublisherBuilder::new(cfg.clone())
        .desired_auth(auth.clone())
        .build()
        .await?;
    let subscriber = Subscriber::new(cfg, auth)?;
    ShellBuilder::<NoExt>::default()
        .mode(Mode::Script(Source::from("main.gx")))
        .publisher(publisher)
        .subscriber(subscriber)
        .no_init(true)
        .build()?
        .run()
        .await
}
}

Module Resolvers

If you want to bundle additional Graphix source files into your binary (beyond what packages provide), you can add module resolvers. A VFS resolver maps virtual paths to source code:

#![allow(unused)]
fn main() {
use arcstr::literal;
use graphix_compiler::expr::ModuleResolver;
use fxhash::FxHashMap;
use netidx_core::path::Path;

fn my_modules() -> ModuleResolver {
    ModuleResolver::VFS(FxHashMap::from_iter([
        (Path::from("/myapp"), literal!(include_str!("myapp/mod.gx"))),
        (Path::from("/myapp/util"), literal!(include_str!("myapp/util.gx"))),
    ]))
}

ShellBuilder::<NoExt>::default()
    .module_resolvers(vec![my_modules()])
    .mode(Mode::Script(Source::from("main.gx")))
    .publisher(publisher)
    .subscriber(subscriber)
    .build()?
    .run()
    .await
}

You can have as many module resolvers as you like. When loading modules they are checked in order, so earlier ones shadow later ones.

Note that for most cases, creating a package is preferable to manually constructing VFS resolvers. Packages handle module registration automatically through the defpackage! macro.

Custom REPL

You can build a REPL with pre-loaded modules by setting the mode to Mode::Repl:

#![allow(unused)]
fn main() {
ShellBuilder::<NoExt>::default()
    .module_resolvers(vec![my_modules()])
    .mode(Mode::Repl)
    .publisher(publisher)
    .subscriber(subscriber)
    .build()?
    .run()
    .await
}

This gives you a REPL with the standard library, all installed packages, and your additional modules available.

Compiler Flags

You can enable or disable compiler flags:

#![allow(unused)]
fn main() {
use graphix_compiler::CFlag;

ShellBuilder::<NoExt>::default()
    .enable_flags(CFlag::WarnUnused | CFlag::WarnUnhandled)
    .mode(Mode::Repl)
    // ...
}