1 /* 2 Example of instantiating of the WebAssembly module and invoking its exported 3 function. 4 5 You can compile and run this example on Linux with: 6 7 cargo build --release -p wasmtime-c-api 8 cc examples/hello.c \ 9 -I crates/c-api/include \ 10 -I crates/c-api/wasm-c-api/include \ 11 target/release/libwasmtime.a \ 12 -lpthread -ldl -lm \ 13 -o hello 14 ./hello 15 16 Note that on Windows and macOS the command will be similar, but you'll need 17 to tweak the `-lpthread` and such annotations as well as the name of the 18 `libwasmtime.a` file on Windows. 19 */ 20 21 #include <assert.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <wasm.h> 25 #include <wasmtime.h> 26 27 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap); 28 29 static wasm_trap_t* hello_callback(const wasm_val_t args[], wasm_val_t results[]) { 30 printf("Calling back...\n"); 31 printf("> Hello World!\n"); 32 return NULL; 33 } 34 35 int serialize(wasm_byte_vec_t* buffer) { 36 // Set up our compilation context. Note that we could also work with a 37 // `wasm_config_t` here to configure what feature are enabled and various 38 // compilation settings. 39 printf("Initializing...\n"); 40 wasm_engine_t *engine = wasm_engine_new(); 41 assert(engine != NULL); 42 43 // Read our input file, which in this case is a wasm text file. 44 FILE* file = fopen("examples/hello.wat", "r"); 45 assert(file != NULL); 46 fseek(file, 0L, SEEK_END); 47 size_t file_size = ftell(file); 48 fseek(file, 0L, SEEK_SET); 49 wasm_byte_vec_t wat; 50 wasm_byte_vec_new_uninitialized(&wat, file_size); 51 assert(fread(wat.data, file_size, 1, file) == 1); 52 fclose(file); 53 54 // Parse the wat into the binary wasm format 55 wasm_byte_vec_t wasm; 56 wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &wasm); 57 if (error != NULL) 58 exit_with_error("failed to parse wat", error, NULL); 59 wasm_byte_vec_delete(&wat); 60 61 // Now that we've got our binary webassembly we can compile our module 62 // and serialize into buffer. 63 printf("Compiling and serializing module...\n"); 64 wasm_module_t *module = NULL; 65 error = wasmtime_module_new(engine, &wasm, &module); 66 wasm_byte_vec_delete(&wasm); 67 if (error != NULL) 68 exit_with_error("failed to compile module", error, NULL); 69 error = wasmtime_module_serialize(module, buffer); 70 wasm_module_delete(module); 71 if (error != NULL) 72 exit_with_error("failed to serialize module", error, NULL); 73 74 printf("Serialized.\n"); 75 76 wasm_engine_delete(engine); 77 return 0; 78 } 79 80 int deserialize(wasm_byte_vec_t* buffer) { 81 // Set up our compilation context. Note that we could also work with a 82 // `wasm_config_t` here to configure what feature are enabled and various 83 // compilation settings. 84 printf("Initializing...\n"); 85 wasm_engine_t *engine = wasm_engine_new(); 86 assert(engine != NULL); 87 88 // With an engine we can create a *store* which is a long-lived group of wasm 89 // modules. 90 wasm_store_t *store = wasm_store_new(engine); 91 assert(store != NULL); 92 93 // Deserialize compiled module. 94 printf("Deserialize module...\n"); 95 wasm_module_t *module = NULL; 96 wasmtime_error_t *error = wasmtime_module_deserialize(engine, buffer, &module); 97 if (error != NULL) 98 exit_with_error("failed to compile module", error, NULL); 99 100 // Next up we need to create the function that the wasm module imports. Here 101 // we'll be hooking up a thunk function to the `hello_callback` native 102 // function above. 103 printf("Creating callback...\n"); 104 wasm_functype_t *hello_ty = wasm_functype_new_0_0(); 105 wasm_func_t *hello = wasm_func_new(store, hello_ty, hello_callback); 106 107 // With our callback function we can now instantiate the compiled module, 108 // giving us an instance we can then execute exports from. Note that 109 // instantiation can trap due to execution of the `start` function, so we need 110 // to handle that here too. 111 printf("Instantiating module...\n"); 112 wasm_trap_t *trap = NULL; 113 wasm_instance_t *instance = NULL; 114 const wasm_extern_t *imports[] = { wasm_func_as_extern(hello) }; 115 error = wasmtime_instance_new(store, module, imports, 1, &instance, &trap); 116 if (instance == NULL) 117 exit_with_error("failed to instantiate", error, trap); 118 119 // Lookup our `run` export function 120 printf("Extracting export...\n"); 121 wasm_extern_vec_t externs; 122 wasm_instance_exports(instance, &externs); 123 assert(externs.size == 1); 124 wasm_func_t *run = wasm_extern_as_func(externs.data[0]); 125 assert(run != NULL); 126 127 // And call it! 128 printf("Calling export...\n"); 129 error = wasmtime_func_call(run, NULL, 0, NULL, 0, &trap); 130 if (error != NULL || trap != NULL) 131 exit_with_error("failed to call function", error, trap); 132 133 // Clean up after ourselves at this point 134 printf("All finished!\n"); 135 136 wasm_extern_vec_delete(&externs); 137 wasm_instance_delete(instance); 138 wasm_module_delete(module); 139 wasm_store_delete(store); 140 wasm_engine_delete(engine); 141 return 0; 142 } 143 144 int main() { 145 wasm_byte_vec_t buffer; 146 if (serialize(&buffer)) { 147 return 1; 148 } 149 if (deserialize(&buffer)) { 150 return 1; 151 } 152 wasm_byte_vec_delete(&buffer); 153 return 0; 154 } 155 156 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { 157 fprintf(stderr, "error: %s\n", message); 158 wasm_byte_vec_t error_message; 159 if (error != NULL) { 160 wasmtime_error_message(error, &error_message); 161 wasmtime_error_delete(error); 162 } else { 163 wasm_trap_message(trap, &error_message); 164 wasm_trap_delete(trap); 165 } 166 fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); 167 wasm_byte_vec_delete(&error_message); 168 exit(1); 169 } 170