Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Readme.md

Example: Multiplatform

This demonstrates using cargo container to wrap apps in multiple platforms, displaying a "dialog".

Quickstart

cargo install --path .

cd example\multiplatform
cargo container setup
cargo container build
cargo container test

:: Run the debug platforms\console generated executable
target\debug\alpha.exe

:: Run the debug platforms\windows generated executable
target\x86_64-pc-windows-msvc\debug\alpha.exe

Overview

Source File Description
app-common/ Multiplatform library consumed by apps
apps/*/ Example crates to wrap
platforms/*/ Example generators of platform specific boilerplate
Container.toml "Workspace" defining what to build
Cargo.toml (generated) Root workspace generated from Container.toml
platforms/Cargo.toml The "extra" workspace here ensures we can rerun the generators if they were buggy and broke the root workspace via bad/conflicting generated packages

Apps

In this example, each "app" (alpha, beta, delta) exposes:

pub fn init(ctx: impl app_common::DialogProvider) { ... }

There is nothing special about this function signature - it only needs to match whatever the accompanying generated packages expect. This might be pub fns, this might be inventory-registered flags... anything!

Platforms

Each of these generates Cargo.toml [package]s wrapping the aforementioned apps.

console

Displays the 'dialog' via stdout, waits for response via stdin

fn main() { app::init(app_common::ConsoleDialogProvider) }

stdweb

Displays the dialog as a javascript alert in the browser, via stdweb.

fn main() { app::init(app_common::StdWebDialogProvider) }

web-sys

Displays the dialog as a javascript alert in the browser, via web-sys.

#[wasm_bindgen(start)] pub fn start() { app::init(app_common::WebSysDialogProvider) }

windows

Displays the dialog as a message box. Will cross-compile to windows on non-windows platforms.

#![windows_subsystem="windows"] fn main() { app::init(app_common::WindowsDialogProvider) }

Generated Files

Generated File Config Platform Host Target
Cargo.lock * * * *
Cargo.toml * * * *
target/debug/alpha.exe debug console windows windows
target/debug/alpha debug console linux linux
target/x86_64-pc-windows-msvc/debug/alpha.exe debug windows windows windows
target/x86_64-pc-windows-gnu/debug/alpha.exe debug windows linux windows
target/wasm32-unknown-unknown/debug/alpha-stdweb.html debug stdweb * browser
target/wasm32-unknown-unknown/debug/alpha-web-sys/index.html debug web-sys * browser
target/release/... release
target/*/release/... release

Advanced Ideas

In this demo, I abuse traits for monomorphization. Perhaps instead you'd prefer global Mutex<Box<dyn Whatever>>s? This can lead to issues if app uses a different version of app_common. (e.g. reqwest might use tokio 0.2 and explode at runtime because you've only initialized a tokio 0.3 runtime)

fn main() {
    let dp : Box<dyn DialogProvider> = Box::new(ConsoleDialogProvider);
    app_common::set_dialog_provider(dp);
    app::init();
}

Alternatively, maybe you can make app_common entirely self configuring:

fn main() {
    app::init();
}

Multiple entry points for different frontends is also possible:

// Different platform feature-sets?
pub fn init_console(ctx: impl GamepadInput) { ... }
pub fn init_desktop(ctx: impl GamepadInput + KeyboardInput + MouseInput) { ... }

// Different contexts
pub fn render_2d(ctx: impl RenderContext2D) { ... }
pub fn render_3d(ctx: impl RenderContext3D) { ... }