diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index d5081298e4..052a114fd7 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -39,7 +39,7 @@ enum wasmtime_opt_level_enum { // OptLevel }; typedef uint8_t wasmtime_profiling_strategy_t; -enum wasmtime_profiling_strategy_t { // ProfilingStrategy +enum wasmtime_profiling_strategy_enum { // ProfilingStrategy WASMTIME_PROFILING_STRATEGY_NONE, WASMTIME_PROFILING_STRATEGY_JITDUMP, WASMTIME_PROFILING_STRATEGY_VTUNE, diff --git a/crates/misc/run-examples/src/main.rs b/crates/misc/run-examples/src/main.rs index f782b929cb..a0cc098ab7 100644 --- a/crates/misc/run-examples/src/main.rs +++ b/crates/misc/run-examples/src/main.rs @@ -51,42 +51,52 @@ fn main() { .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); + println!("======== C/C++ example `{}` ============", example); + for extension in ["c", "cc"].iter() { + 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(); - run(&mut Command::new(exe)); + let file = if is_dir { + format!("examples/{}/main.{}", example, extension) + } else { + format!("examples/{}.{}", example, extension) + }; + + if extension == &"cc" && !std::path::Path::new(&file).exists() { + // cc files are optional so we can skip them. + continue; + } + + cmd.arg(file); + 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)); + } } } diff --git a/examples/hello.cc b/examples/hello.cc new file mode 100644 index 0000000000..57cfc5f360 --- /dev/null +++ b/examples/hello.cc @@ -0,0 +1,133 @@ +/* +Example of instantiating of the WebAssembly module and invoking its exported +function. + +You can compile and run this example on Linux with: + + cargo build --release -p wasmtime + cc examples/hello.cc \ + -I crates/c-api/include \ + -I crates/c-api/wasm-c-api/include \ + target/release/libwasmtime.a \ + -lpthread -ldl -lm \ + -o hello + ./hello + +Note that on Windows and macOS the command will be similar, but you'll need +to tweak the `-lpthread` and such annotations as well as the name of the +`libwasmtime.a` file on Windows. +*/ + +#include +#include +#include +#include +#include + +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); + +static wasm_trap_t* hello_callback(const wasm_val_t args[], wasm_val_t results[]) { + printf("Calling back...\n"); + printf("> Hello World!\n"); + return NULL; +} + +int main() { + int ret = 0; + // Set up our compilation context. Note that we could also work with a + // `wasm_config_t` here to configure what feature are enabled and various + // compilation settings. + printf("Initializing...\n"); + wasm_engine_t *engine = wasm_engine_new(); + assert(engine != NULL); + + // With an engine we can create a *store* which is a long-lived group of wasm + // modules. + wasm_store_t *store = wasm_store_new(engine); + assert(store != NULL); + + // Read our input file, which in this case is a wasm text file. + FILE* file = fopen("examples/hello.wat", "r"); + assert(file != NULL); + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t wat; + wasm_byte_vec_new_uninitialized(&wat, file_size); + assert(fread(wat.data, file_size, 1, file) == 1); + fclose(file); + + // Parse the wat into the binary wasm format + wasm_byte_vec_t wasm; + wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm); + if (error != NULL) + exit_with_error("failed to parse wat", error, NULL); + wasm_byte_vec_delete(&wat); + + // Now that we've got our binary webassembly we can compile our module. + printf("Compiling module...\n"); + wasm_module_t *module = NULL; + error = wasmtime_module_new(store, &wasm, &module); + wasm_byte_vec_delete(&wasm); + if (error != NULL) + exit_with_error("failed to compile module", error, NULL); + + // Next up we need to create the function that the wasm module imports. Here + // we'll be hooking up a thunk function to the `hello_callback` native + // function above. + printf("Creating callback...\n"); + wasm_functype_t *hello_ty = wasm_functype_new_0_0(); + wasm_func_t *hello = wasm_func_new(store, hello_ty, hello_callback); + + // With our callback function we can now instantiate the compiled module, + // giving us an instance we can then execute exports from. Note that + // instantiation can trap due to execution of the `start` function, so we need + // to handle that here too. + printf("Instantiating module...\n"); + wasm_trap_t *trap = NULL; + wasm_instance_t *instance = NULL; + const wasm_extern_t *imports[] = { wasm_func_as_extern(hello) }; + error = wasmtime_instance_new(store, module, imports, 1, &instance, &trap); + if (instance == NULL) + exit_with_error("failed to instantiate", error, trap); + + // Lookup our `run` export function + printf("Extracting export...\n"); + wasm_extern_vec_t externs; + wasm_instance_exports(instance, &externs); + assert(externs.size == 1); + wasm_func_t *run = wasm_extern_as_func(externs.data[0]); + assert(run != NULL); + + // And call it! + printf("Calling export...\n"); + error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap); + if (error != NULL || trap != NULL) + exit_with_error("failed to call function", error, trap); + + // Clean up after ourselves at this point + printf("All finished!\n"); + ret = 0; + + wasm_extern_vec_delete(&externs); + wasm_instance_delete(instance); + wasm_module_delete(module); + wasm_store_delete(store); + wasm_engine_delete(engine); + return ret; +} + +static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { + fprintf(stderr, "error: %s\n", message); + wasm_byte_vec_t error_message; + if (error != NULL) { + wasmtime_error_message(error, &error_message); + wasmtime_error_delete(error); + } else { + wasm_trap_message(trap, &error_message); + wasm_trap_delete(trap); + } + fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); + wasm_byte_vec_delete(&error_message); + exit(1); +}