Move all examples to a top-level directory (#1286)
* Move all examples to a top-level directory This commit moves all API examples (Rust and C) to a top-level `examples` directory. This is intended to make it more discoverable and conventional as to where examples are located. Additionally all examples are now available in both Rust and C to see how to execute the example in the language you're familiar with. The intention is that as more languages are supported we'd add more languages as examples here too. Each example is also accompanied by either a `*.wat` file which is parsed as input, or a Rust project in a `wasm` folder which is compiled as input. A simple driver crate was also added to `crates/misc` which executes all the examples on CI, ensuring the C and Rust examples all execute successfully.
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
//! Example of instantiating of the WebAssembly module and
|
||||
//! invoking its exported function.
|
||||
|
||||
use wasmtime::*;
|
||||
|
||||
const WAT: &str = r#"
|
||||
(module
|
||||
(func $gcd (param i32 i32) (result i32)
|
||||
(local i32)
|
||||
block ;; label = @1
|
||||
block ;; label = @2
|
||||
local.get 0
|
||||
br_if 0 (;@2;)
|
||||
local.get 1
|
||||
local.set 2
|
||||
br 1 (;@1;)
|
||||
end
|
||||
loop ;; label = @2
|
||||
local.get 1
|
||||
local.get 0
|
||||
local.tee 2
|
||||
i32.rem_u
|
||||
local.set 0
|
||||
local.get 2
|
||||
local.set 1
|
||||
local.get 0
|
||||
br_if 0 (;@2;)
|
||||
end
|
||||
end
|
||||
local.get 2
|
||||
)
|
||||
(export "gcd" (func $gcd))
|
||||
)
|
||||
"#;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// Load our WebAssembly (parsed WAT in our case), and then load it into a
|
||||
// `Module` which is attached to a `Store` cache.
|
||||
let store = Store::default();
|
||||
let module = Module::new(&store, WAT)?;
|
||||
|
||||
// Find index of the `gcd` export.
|
||||
let gcd_index = module
|
||||
.exports()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, export)| export.name().to_string() == "gcd")
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
// Instantiate the module.
|
||||
let instance = Instance::new(&module, &[])?;
|
||||
|
||||
// Invoke `gcd` export
|
||||
let gcd = instance.exports()[gcd_index].func().expect("gcd");
|
||||
let result = gcd.call(&[Val::from(6i32), Val::from(27i32)])?;
|
||||
|
||||
println!("{:?}", result);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
//! Translation of hello example
|
||||
|
||||
use anyhow::{ensure, Context as _, Result};
|
||||
use wasmtime::*;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Configure the initial compilation environment, creating the global
|
||||
// `Store` structure. Note that you can also tweak configuration settings
|
||||
// with a `Config` and an `Engine` if desired.
|
||||
println!("Initializing...");
|
||||
let store = Store::default();
|
||||
|
||||
// Compile the wasm binary into an in-memory instance of a `Module`.
|
||||
println!("Compiling module...");
|
||||
let wat = r#"
|
||||
(module
|
||||
(func $hello (import "" "hello"))
|
||||
(func (export "run") (call $hello))
|
||||
)
|
||||
"#;
|
||||
let module = Module::new(&store, wat).context("> Error compiling module!")?;
|
||||
|
||||
// Here we handle the imports of the module, which in this case is our
|
||||
// `HelloCallback` type and its associated implementation of `Callback.
|
||||
println!("Creating callback...");
|
||||
let hello_func = Func::wrap0(&store, || {
|
||||
println!("Calling back...");
|
||||
println!("> Hello World!");
|
||||
});
|
||||
|
||||
// Once we've got that all set up we can then move to the instantiation
|
||||
// phase, pairing together a compiled module as well as a set of imports.
|
||||
// Note that this is where the wasm `start` function, if any, would run.
|
||||
println!("Instantiating module...");
|
||||
let imports = vec![hello_func.into()];
|
||||
let instance = Instance::new(&module, &imports).context("> Error instantiating module!")?;
|
||||
|
||||
// Next we poke around a bit to extract the `run` function from the module.
|
||||
println!("Extracting export...");
|
||||
let exports = instance.exports();
|
||||
ensure!(!exports.is_empty(), "> Error accessing exports!");
|
||||
let run_func = exports[0].func().context("> Error accessing exports!")?;
|
||||
|
||||
// And last but not least we can call it!
|
||||
println!("Calling export...");
|
||||
run_func.call(&[])?;
|
||||
|
||||
println!("Done.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
//! Translation of the memory example
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Error};
|
||||
use wasmtime::*;
|
||||
|
||||
fn get_export_memory(exports: &[Extern], i: usize) -> Result<Memory, Error> {
|
||||
if exports.len() <= i {
|
||||
bail!("> Error accessing memory export {}!", i);
|
||||
}
|
||||
Ok(exports[i]
|
||||
.memory()
|
||||
.with_context(|| format!("> Error accessing memory export {}!", i))?
|
||||
.clone())
|
||||
}
|
||||
|
||||
fn get_export_func(exports: &[Extern], i: usize) -> Result<Func, Error> {
|
||||
if exports.len() <= i {
|
||||
bail!("> Error accessing function export {}!", i);
|
||||
}
|
||||
Ok(exports[i]
|
||||
.func()
|
||||
.with_context(|| format!("> Error accessing function export {}!", i))?
|
||||
.clone())
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($actual:expr, $expected:expr) => {
|
||||
if $actual != $expected {
|
||||
bail!("> Error on result, expected {}, got {}", $expected, $actual);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! check_ok {
|
||||
($func:expr, $($p:expr),*) => {
|
||||
if let Err(_) = $func.call(&[$($p.into()),*]) {
|
||||
bail!("> Error on result, expected return");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! check_trap {
|
||||
($func:expr, $($p:expr),*) => {
|
||||
if let Ok(_) = $func.call(&[$($p.into()),*]) {
|
||||
bail!("> Error on result, expected trap");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! call {
|
||||
($func:expr, $($p:expr),*) => {
|
||||
match $func.call(&[$($p.into()),*]) {
|
||||
Ok(result) => {
|
||||
let result: i32 = result[0].unwrap_i32();
|
||||
result
|
||||
}
|
||||
Err(_) => { bail!("> Error on result, expected return"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
// Initialize.
|
||||
println!("Initializing...");
|
||||
let store = Store::default();
|
||||
|
||||
// Load binary.
|
||||
println!("Loading binary...");
|
||||
let wat = r#"
|
||||
(module
|
||||
(memory (export "memory") 2 3)
|
||||
|
||||
(func (export "size") (result i32) (memory.size))
|
||||
(func (export "load") (param i32) (result i32)
|
||||
(i32.load8_s (local.get 0))
|
||||
)
|
||||
(func (export "store") (param i32 i32)
|
||||
(i32.store8 (local.get 0) (local.get 1))
|
||||
)
|
||||
|
||||
(data (i32.const 0x1000) "\01\02\03\04")
|
||||
)
|
||||
"#;
|
||||
|
||||
// Compile.
|
||||
println!("Compiling module...");
|
||||
let module = Module::new(&store, &wat).context("> Error compiling module!")?;
|
||||
|
||||
// Instantiate.
|
||||
println!("Instantiating module...");
|
||||
let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
|
||||
|
||||
// Extract export.
|
||||
println!("Extracting export...");
|
||||
let exports = instance.exports();
|
||||
ensure!(!exports.is_empty(), "> Error accessing exports!");
|
||||
let memory = get_export_memory(&exports, 0)?;
|
||||
let size_func = get_export_func(&exports, 1)?;
|
||||
let load_func = get_export_func(&exports, 2)?;
|
||||
let store_func = get_export_func(&exports, 3)?;
|
||||
|
||||
// Check initial memory.
|
||||
println!("Checking memory...");
|
||||
check!(memory.size(), 2u32);
|
||||
check!(memory.data_size(), 0x20000usize);
|
||||
check!(unsafe { memory.data_unchecked_mut()[0] }, 0);
|
||||
check!(unsafe { memory.data_unchecked_mut()[0x1000] }, 1);
|
||||
check!(unsafe { memory.data_unchecked_mut()[0x1003] }, 4);
|
||||
|
||||
check!(call!(size_func,), 2);
|
||||
check!(call!(load_func, 0), 0);
|
||||
check!(call!(load_func, 0x1000), 1);
|
||||
check!(call!(load_func, 0x1003), 4);
|
||||
check!(call!(load_func, 0x1ffff), 0);
|
||||
check_trap!(load_func, 0x20000);
|
||||
|
||||
// Mutate memory.
|
||||
println!("Mutating memory...");
|
||||
unsafe {
|
||||
memory.data_unchecked_mut()[0x1003] = 5;
|
||||
}
|
||||
|
||||
check_ok!(store_func, 0x1002, 6);
|
||||
check_trap!(store_func, 0x20000, 0);
|
||||
|
||||
check!(unsafe { memory.data_unchecked()[0x1002] }, 6);
|
||||
check!(unsafe { memory.data_unchecked()[0x1003] }, 5);
|
||||
check!(call!(load_func, 0x1002), 6);
|
||||
check!(call!(load_func, 0x1003), 5);
|
||||
|
||||
// Grow memory.
|
||||
println!("Growing memory...");
|
||||
memory.grow(1)?;
|
||||
check!(memory.size(), 3u32);
|
||||
check!(memory.data_size(), 0x30000usize);
|
||||
|
||||
check!(call!(load_func, 0x20000), 0);
|
||||
check_ok!(store_func, 0x20000, 0);
|
||||
check_trap!(load_func, 0x30000);
|
||||
check_trap!(store_func, 0x30000, 0);
|
||||
|
||||
memory.grow(1).unwrap_err();
|
||||
memory.grow(0).unwrap();
|
||||
|
||||
// Create stand-alone memory.
|
||||
// TODO(wasm+): Once Wasm allows multiple memories, turn this into import.
|
||||
println!("Creating stand-alone memory...");
|
||||
let memorytype = MemoryType::new(Limits::new(5, Some(5)));
|
||||
let memory2 = Memory::new(&store, memorytype);
|
||||
check!(memory2.size(), 5u32);
|
||||
memory2.grow(1).unwrap_err();
|
||||
memory2.grow(0).unwrap();
|
||||
|
||||
// Shut down.
|
||||
println!("Shutting down...");
|
||||
drop(store);
|
||||
|
||||
println!("Done.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
//! Translation of multi example
|
||||
|
||||
use anyhow::{ensure, format_err, Context as _, Result};
|
||||
use std::rc::Rc;
|
||||
use wasmtime::*;
|
||||
|
||||
struct Callback;
|
||||
|
||||
impl Callable for Callback {
|
||||
fn call(&self, args: &[Val], results: &mut [Val]) -> Result<(), Trap> {
|
||||
println!("Calling back...");
|
||||
println!("> {} {}", args[0].unwrap_i32(), args[1].unwrap_i64());
|
||||
|
||||
results[0] = Val::I64(args[1].unwrap_i64() + 1);
|
||||
results[1] = Val::I32(args[0].unwrap_i32() + 1);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
const WAT: &str = r#"
|
||||
(module
|
||||
(func $f (import "" "f") (param i32 i64) (result i64 i32))
|
||||
|
||||
(func $g (export "g") (param i32 i64) (result i64 i32)
|
||||
(call $f (local.get 0) (local.get 1))
|
||||
)
|
||||
|
||||
(func $round_trip_many
|
||||
(export "round_trip_many")
|
||||
(param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
|
||||
(result i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
|
||||
local.get 0
|
||||
local.get 1
|
||||
local.get 2
|
||||
local.get 3
|
||||
local.get 4
|
||||
local.get 5
|
||||
local.get 6
|
||||
local.get 7
|
||||
local.get 8
|
||||
local.get 9)
|
||||
)
|
||||
"#;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Initialize.
|
||||
println!("Initializing...");
|
||||
let engine = Engine::new(Config::new().wasm_multi_value(true));
|
||||
let store = Store::new(&engine);
|
||||
|
||||
// Compile.
|
||||
println!("Compiling module...");
|
||||
let module = Module::new(&store, WAT).context("Error compiling module!")?;
|
||||
|
||||
// Create external print functions.
|
||||
println!("Creating callback...");
|
||||
let callback_type = FuncType::new(
|
||||
Box::new([ValType::I32, ValType::I64]),
|
||||
Box::new([ValType::I64, ValType::I32]),
|
||||
);
|
||||
let callback_func = Func::new(&store, callback_type, Rc::new(Callback));
|
||||
|
||||
// Instantiate.
|
||||
println!("Instantiating module...");
|
||||
let imports = vec![callback_func.into()];
|
||||
let instance =
|
||||
Instance::new(&module, imports.as_slice()).context("Error instantiating module!")?;
|
||||
|
||||
// Extract exports.
|
||||
println!("Extracting export...");
|
||||
let exports = instance.exports();
|
||||
ensure!(!exports.is_empty(), "Error accessing exports!");
|
||||
let g = exports[0].func().context("> Error accessing export $g!")?;
|
||||
let round_trip_many = exports[1]
|
||||
.func()
|
||||
.context("> Error accessing export $round_trip_many")?;
|
||||
|
||||
// Call `$g`.
|
||||
println!("Calling export \"g\"...");
|
||||
let args = vec![Val::I32(1), Val::I64(3)];
|
||||
let results = g
|
||||
.call(&args)
|
||||
.map_err(|e| format_err!("> Error calling g! {:?}", e))?;
|
||||
|
||||
println!("Printing result...");
|
||||
println!("> {} {}", results[0].unwrap_i64(), results[1].unwrap_i32());
|
||||
|
||||
debug_assert_eq!(results[0].unwrap_i64(), 4);
|
||||
debug_assert_eq!(results[1].unwrap_i32(), 2);
|
||||
|
||||
// Call `$round_trip_many`.
|
||||
println!("Calling export \"round_trip_many\"...");
|
||||
let args = vec![
|
||||
Val::I64(0),
|
||||
Val::I64(1),
|
||||
Val::I64(2),
|
||||
Val::I64(3),
|
||||
Val::I64(4),
|
||||
Val::I64(5),
|
||||
Val::I64(6),
|
||||
Val::I64(7),
|
||||
Val::I64(8),
|
||||
Val::I64(9),
|
||||
];
|
||||
let results = round_trip_many
|
||||
.call(&args)
|
||||
.map_err(|e| format_err!("> Error calling round_trip_many! {:?}", e))?;
|
||||
|
||||
println!("Printing result...");
|
||||
print!(">");
|
||||
for r in results.iter() {
|
||||
print!(" {}", r.unwrap_i64());
|
||||
}
|
||||
println!();
|
||||
|
||||
debug_assert_eq!(results.len(), 10);
|
||||
debug_assert!(args
|
||||
.iter()
|
||||
.zip(results.iter())
|
||||
.all(|(a, r)| a.i64() == r.i64()));
|
||||
|
||||
// Shut down.
|
||||
println!("Shutting down...");
|
||||
drop(store);
|
||||
|
||||
// All done.
|
||||
println!("Done.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
use std::env;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn run_example(name: &'static str) {
|
||||
let cargo = env::var("CARGO").unwrap_or("cargo".to_string());
|
||||
let pkg_dir = env!("CARGO_MANIFEST_DIR");
|
||||
assert!(
|
||||
Command::new(cargo)
|
||||
.current_dir(pkg_dir)
|
||||
.stdout(Stdio::null())
|
||||
.args(&["run", "-q", "--example", name])
|
||||
.status()
|
||||
.expect("success")
|
||||
.success(),
|
||||
"failed to execute the example '{}'",
|
||||
name,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_hello_example() {
|
||||
run_example("hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_gcd_example() {
|
||||
run_example("gcd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_memory_example() {
|
||||
run_example("memory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_multi_example() {
|
||||
run_example("multi");
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
###############################################################################
|
||||
# Configuration
|
||||
|
||||
# Inherited from wasm-c-api/Makefile to just run C examples
|
||||
|
||||
WASM_FLAGS = -DWASM_API_DEBUG # -DWASM_API_DEBUG_LOG
|
||||
C_FLAGS = ${WASM_FLAGS} -Wall -Werror -ggdb -O -fsanitize=address
|
||||
CC_FLAGS = -std=c++11 ${C_FLAGS}
|
||||
LD_FLAGS = -fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor
|
||||
|
||||
C_COMP = clang
|
||||
|
||||
WASMTIME_API_MODE = debug
|
||||
|
||||
|
||||
# Base directories
|
||||
WASMTIME_API_DIR = ..
|
||||
WASM_DIR = wasm-c-api
|
||||
EXAMPLE_DIR = ${WASM_DIR}/example
|
||||
OUT_DIR = ${WASM_DIR}/out
|
||||
|
||||
# Example config
|
||||
EXAMPLE_OUT = ${OUT_DIR}/example
|
||||
EXAMPLES = \
|
||||
hello \
|
||||
callback \
|
||||
trap \
|
||||
start \
|
||||
reflect \
|
||||
global \
|
||||
table \
|
||||
memory \
|
||||
hostref \
|
||||
finalize \
|
||||
serialize \
|
||||
threads \
|
||||
# multi \
|
||||
|
||||
# Wasm config
|
||||
WASM_INCLUDE = ${WASM_DIR}/include
|
||||
WASM_SRC = ${WASM_DIR}/src
|
||||
WASM_OUT = ${OUT_DIR}
|
||||
WASM_C_LIBS = wasm-bin wasm-rust-api
|
||||
WASM_CC_LIBS = $(error unsupported C++)
|
||||
|
||||
|
||||
# Compiler config
|
||||
ifeq (${WASMTIME_API_MODE},release)
|
||||
CARGO_BUILD_FLAGS = --release
|
||||
else
|
||||
CARGO_BUILD_FLAGS =
|
||||
endif
|
||||
|
||||
ifeq (${C_COMP},clang)
|
||||
CC_COMP = clang++
|
||||
LD_GROUP_START =
|
||||
LD_GROUP_END =
|
||||
else ifeq (${C_COMP},gcc)
|
||||
CC_COMP = g++
|
||||
LD_GROUP_START = -Wl,--start-group
|
||||
LD_GROUP_END = -Wl,--end-group
|
||||
else
|
||||
$(error C_COMP set to unknown compiler, must be clang or gcc)
|
||||
endif
|
||||
|
||||
WASMTIME_BIN_DIR = ${WASMTIME_API_DIR}/../../target/${WASMTIME_API_MODE}
|
||||
WASMTIME_C_LIB_DIR = ${WASMTIME_BIN_DIR}
|
||||
WASMTIME_C_LIBS = wasmtime
|
||||
WASMTIME_CC_LIBS = $(error unsupported c++)
|
||||
|
||||
WASMTIME_C_BINS = ${WASMTIME_C_LIBS:%=${WASMTIME_C_LIB_DIR}/lib%.a}
|
||||
|
||||
###############################################################################
|
||||
# Examples
|
||||
#
|
||||
# To build Wasm APIs and run all examples:
|
||||
# make all
|
||||
#
|
||||
# To run only C examples:
|
||||
# make c
|
||||
#
|
||||
# To run only C++ examples:
|
||||
# make cc
|
||||
#
|
||||
# To run individual C example (e.g. hello):
|
||||
# make run-hello-c
|
||||
#
|
||||
# To run individual C++ example (e.g. hello):
|
||||
# make run-hello-cc
|
||||
#
|
||||
|
||||
.PHONY: all cc c
|
||||
all: cc c
|
||||
cc: ${EXAMPLES:%=run-%-cc}
|
||||
c: ${EXAMPLES:%=run-%-c}
|
||||
|
||||
# Running a C / C++ example
|
||||
run-%-c: ${EXAMPLE_OUT}/%-c ${EXAMPLE_OUT}/%.wasm
|
||||
@echo ==== C ${@:run-%-c=%} ====; \
|
||||
cd ${EXAMPLE_OUT}; ./${@:run-%=%}
|
||||
@echo ==== Done ====
|
||||
|
||||
run-%-cc: ${EXAMPLE_OUT}/%-cc ${EXAMPLE_OUT}/%.wasm
|
||||
@echo ==== C++ ${@:run-%-cc=%} ====; \
|
||||
cd ${EXAMPLE_OUT}; ./${@:run-%=%}
|
||||
@echo ==== Done ====
|
||||
|
||||
# Compiling C / C++ example
|
||||
${EXAMPLE_OUT}/%-c.o: ${EXAMPLE_DIR}/%.c ${WASM_INCLUDE}/wasm.h
|
||||
mkdir -p ${EXAMPLE_OUT}
|
||||
${C_COMP} -c ${C_FLAGS} -I. -I${WASM_INCLUDE} $< -o $@
|
||||
|
||||
${EXAMPLE_OUT}/%-cc.o: ${EXAMPLE_DIR}/%.cc ${WASM_INCLUDE}/wasm.hh
|
||||
mkdir -p ${EXAMPLE_OUT}
|
||||
${CC_COMP} -c ${CC_FLAGS} -I. -I${WASM_INCLUDE} $< -o $@
|
||||
|
||||
# Linking C / C++ example
|
||||
.PRECIOUS: ${EXAMPLES:%=${EXAMPLE_OUT}/%-c}
|
||||
${EXAMPLE_OUT}/%-c: ${EXAMPLE_OUT}/%-c.o ${WASMTIME_C_BINS}
|
||||
${CC_COMP} ${CC_FLAGS} ${LD_FLAGS} $< -o $@ \
|
||||
${LD_GROUP_START} \
|
||||
${WASMTIME_C_BINS} \
|
||||
${LD_GROUP_END} \
|
||||
-ldl -pthread
|
||||
|
||||
# Installing Wasm binaries
|
||||
.PRECIOUS: ${EXAMPLES:%=${EXAMPLE_OUT}/%.wasm}
|
||||
${EXAMPLE_OUT}/%.wasm: ${EXAMPLE_DIR}/%.wasm
|
||||
cp $< $@
|
||||
|
||||
###############################################################################
|
||||
# Wasm C / C++ API
|
||||
#
|
||||
# To build both C / C++ APIs:
|
||||
# make wasm
|
||||
|
||||
.PHONY: wasm wasm-c wasm-cc
|
||||
wasm: wasm-c wasm-cc
|
||||
wasm-c: ${WASMTIME_C_BIN}
|
||||
wasm-cc: ${WASMTIME_CC_BIN}
|
||||
|
||||
${WASMTIME_C_BINS}: CARGO_RUN
|
||||
cd ${WASMTIME_API_DIR}; cargo build --lib ${CARGO_BUILD_FLAGS}
|
||||
|
||||
.PHONY: CARGO_RUN
|
||||
CARGO_RUN:
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Clean-up
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf ${OUT_DIR}
|
||||
|
||||
###############################################################################
|
||||
# Other examples
|
||||
|
||||
WASM_EXT_INCLUDE = ${WASMTIME_API_DIR}/include
|
||||
|
||||
run-config-debug-c: ${EXAMPLE_OUT}/config-debug-c ${EXAMPLE_OUT}/fib-wasm.wasm
|
||||
@echo ==== C config ====; \
|
||||
cd ${EXAMPLE_OUT}; ./config-debug-c
|
||||
@echo ==== Done ====
|
||||
|
||||
${EXAMPLE_OUT}/fib-wasm.wasm: fib-wasm.wasm
|
||||
cp $< $@
|
||||
|
||||
${EXAMPLE_OUT}/config-debug-c.o: config-debug.c ${WASM_INCLUDE}/wasm.h ${WASM_EXT_INCLUDE}/wasmtime.h
|
||||
mkdir -p ${EXAMPLE_OUT}
|
||||
${C_COMP} -c ${C_FLAGS} -I. -I${WASM_INCLUDE} -I${WASM_EXT_INCLUDE} $< -o $@
|
||||
@@ -1,99 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <wasm.h>
|
||||
#include "wasmtime.h"
|
||||
|
||||
#define own
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
// Configuring engine to support generating of DWARF info.
|
||||
// lldb can be used to attach to the program and observe
|
||||
// original fib-wasm.c source code and variables.
|
||||
wasm_config_t* config = wasm_config_new();
|
||||
wasmtime_config_debug_info_set(config, true);
|
||||
|
||||
// Initialize.
|
||||
printf("Initializing...\n");
|
||||
wasm_engine_t* engine = wasm_engine_new_with_config(config);
|
||||
wasm_store_t* store = wasm_store_new(engine);
|
||||
|
||||
// Load binary.
|
||||
printf("Loading binary...\n");
|
||||
FILE* file = fopen("fib-wasm.wasm", "r");
|
||||
if (!file) {
|
||||
printf("> Error loading module!\n");
|
||||
return 1;
|
||||
}
|
||||
fseek(file, 0L, SEEK_END);
|
||||
size_t file_size = ftell(file);
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
wasm_byte_vec_t binary;
|
||||
wasm_byte_vec_new_uninitialized(&binary, file_size);
|
||||
if (fread(binary.data, file_size, 1, file) != 1) {
|
||||
printf("> Error loading module!\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
// Compile.
|
||||
printf("Compiling module...\n");
|
||||
own wasm_module_t* module = wasm_module_new(store, &binary);
|
||||
if (!module) {
|
||||
printf("> Error compiling module!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_byte_vec_delete(&binary);
|
||||
|
||||
// Instantiate.
|
||||
printf("Instantiating module...\n");
|
||||
own wasm_instance_t* instance =
|
||||
wasm_instance_new(store, module, NULL, NULL);
|
||||
if (!instance) {
|
||||
printf("> Error instantiating module!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Extract export.
|
||||
printf("Extracting export...\n");
|
||||
own wasm_extern_vec_t exports;
|
||||
wasm_instance_exports(instance, &exports);
|
||||
if (exports.size == 0) {
|
||||
printf("> Error accessing exports!\n");
|
||||
return 1;
|
||||
}
|
||||
// Getting second export (first is memory).
|
||||
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[1]);
|
||||
if (run_func == NULL) {
|
||||
printf("> Error accessing export!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_module_delete(module);
|
||||
wasm_instance_delete(instance);
|
||||
|
||||
// Call.
|
||||
printf("Calling fib...\n");
|
||||
wasm_val_t params[1] = { {.kind = WASM_I32, .of = {.i32 = 6}} };
|
||||
wasm_val_t results[1];
|
||||
if (wasm_func_call(run_func, params, results)) {
|
||||
printf("> Error calling function!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_extern_vec_delete(&exports);
|
||||
|
||||
printf("> fib(6) = %d\n", results[0].of.i32);
|
||||
|
||||
// Shut down.
|
||||
printf("Shutting down...\n");
|
||||
wasm_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
|
||||
// All done.
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Compile with:
|
||||
// clang --target=wasm32 fib-wasm.c -o fib-wasm.wasm -g \
|
||||
// -Wl,--no-entry,--export=fib -nostdlib -fdebug-prefix-map=$PWD=.
|
||||
|
||||
int fib(int n) {
|
||||
int i, t, a = 0, b = 1;
|
||||
for (i = 0; i < n; i++) {
|
||||
t = a;
|
||||
a = b;
|
||||
b += t;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
Binary file not shown.
@@ -9,6 +9,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define own
|
||||
|
||||
typedef uint8_t wasmtime_strategy_t;
|
||||
enum wasmtime_strategy_enum { // Strategy
|
||||
WASMTIME_STRATEGY_AUTO,
|
||||
@@ -51,13 +53,15 @@ WASMTIME_CONFIG_PROP(cranelift_opt_level, wasmtime_opt_level_t)
|
||||
// optional.
|
||||
//
|
||||
// Returns `true` if conversion succeeded, or `false` if it failed.
|
||||
bool wasmtime_wat2wasm(
|
||||
WASM_API_EXTERN bool wasmtime_wat2wasm(
|
||||
wasm_engine_t *engine,
|
||||
const wasm_byte_vec_t *wat,
|
||||
own wasm_byte_vec_t *ret,
|
||||
own wasm_byte_vec_t *error_message,
|
||||
own wasm_byte_vec_t *error_message
|
||||
);
|
||||
|
||||
#undef own
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
9
crates/misc/run-examples/Cargo.toml
Normal file
9
crates/misc/run-examples/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "run-examples"
|
||||
version = "0.1.0"
|
||||
authors = ["The Wasmtime Project Developers"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
cc = "1.0"
|
||||
6
crates/misc/run-examples/build.rs
Normal file
6
crates/misc/run-examples/build.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
println!(
|
||||
"cargo:rustc-env=TARGET={}",
|
||||
std::env::var("TARGET").unwrap()
|
||||
);
|
||||
}
|
||||
83
crates/misc/run-examples/src/main.rs
Normal file
83
crates/misc/run-examples/src/main.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let examples = std::fs::read_dir("examples").unwrap();
|
||||
let examples = examples
|
||||
.map(|e| {
|
||||
let e = e.unwrap();
|
||||
let path = e.path();
|
||||
let dir = e.metadata().unwrap().is_dir();
|
||||
(path.file_stem().unwrap().to_str().unwrap().to_owned(), dir)
|
||||
})
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
println!("======== Building libwasmtime.a ===========");
|
||||
run(Command::new("cargo").args(&["build", "-p", "wasmtime-c-api"]));
|
||||
|
||||
for (example, is_dir) in examples {
|
||||
if example == "README" {
|
||||
continue;
|
||||
}
|
||||
if is_dir {
|
||||
println!("======== Rust wasm file `{}` ============", example);
|
||||
run(Command::new("cargo")
|
||||
.arg("build")
|
||||
.arg("-p")
|
||||
.arg(format!("example-{}-wasm", example))
|
||||
.arg("--target")
|
||||
.arg("wasm32-unknown-unknown"));
|
||||
}
|
||||
println!("======== Rust example `{}` ============", example);
|
||||
run(Command::new("cargo")
|
||||
.arg("run")
|
||||
.arg("--example")
|
||||
.arg(&example));
|
||||
|
||||
println!("======== C example `{}` ============", example);
|
||||
let mut cmd = cc::Build::new()
|
||||
.opt_level(0)
|
||||
.cargo_metadata(false)
|
||||
.target(env!("TARGET"))
|
||||
.host(env!("TARGET"))
|
||||
.include("crates/c-api/include")
|
||||
.include("crates/c-api/wasm-c-api/include")
|
||||
.define("WASM_API_EXTERN", Some("")) // static linkage, not dynamic
|
||||
.warnings(false)
|
||||
.get_compiler()
|
||||
.to_command();
|
||||
if is_dir {
|
||||
cmd.arg(format!("examples/{}/main.c", example));
|
||||
} else {
|
||||
cmd.arg(format!("examples/{}.c", example));
|
||||
}
|
||||
let exe = if cfg!(windows) {
|
||||
cmd.arg("target/debug/wasmtime.lib")
|
||||
.arg("ws2_32.lib")
|
||||
.arg("advapi32.lib")
|
||||
.arg("userenv.lib")
|
||||
.arg("ntdll.lib")
|
||||
.arg("shell32.lib")
|
||||
.arg("ole32.lib");
|
||||
"./main.exe"
|
||||
} else {
|
||||
cmd.arg("target/debug/libwasmtime.a").arg("-o").arg("foo");
|
||||
"./foo"
|
||||
};
|
||||
if cfg!(target_os = "linux") {
|
||||
cmd.arg("-lpthread").arg("-ldl").arg("-lm");
|
||||
}
|
||||
run(&mut cmd);
|
||||
|
||||
run(&mut Command::new(exe));
|
||||
}
|
||||
}
|
||||
|
||||
fn run(cmd: &mut Command) {
|
||||
let s = cmd.status().unwrap();
|
||||
if !s.success() {
|
||||
eprintln!("failed to run {:?}", cmd);
|
||||
eprintln!("status: {}", s);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user