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); +}