1 /* 2 Example of compiling, instantiating, and linking two WebAssembly modules 3 together. 4 5 You can build using cmake: 6 7 mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-linking 8 */ 9 10 #include <assert.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <wasi.h> 14 #include <wasm.h> 15 #include <wasmtime.h> 16 17 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 18 19 static void exit_with_error(const char *message, wasmtime_error_t *error, 20 wasm_trap_t *trap); 21 static void read_wat_file(wasm_byte_vec_t *bytes, const char *file); 22 23 int main() { 24 // Set up our context 25 wasm_engine_t *engine = wasm_engine_new(); 26 assert(engine != NULL); 27 wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL); 28 assert(store != NULL); 29 wasmtime_context_t *context = wasmtime_store_context(store); 30 31 wasm_byte_vec_t linking1_wasm, linking2_wasm; 32 read_wat_file(&linking1_wasm, "examples/linking1.wat"); 33 read_wat_file(&linking2_wasm, "examples/linking2.wat"); 34 35 // Compile our two modules 36 wasmtime_error_t *error; 37 wasmtime_module_t *linking1_module = NULL; 38 wasmtime_module_t *linking2_module = NULL; 39 error = wasmtime_module_new(engine, (uint8_t *)linking1_wasm.data, 40 linking1_wasm.size, &linking1_module); 41 if (error != NULL) 42 exit_with_error("failed to compile linking1", error, NULL); 43 error = wasmtime_module_new(engine, (uint8_t *)linking2_wasm.data, 44 linking2_wasm.size, &linking2_module); 45 if (error != NULL) 46 exit_with_error("failed to compile linking2", error, NULL); 47 wasm_byte_vec_delete(&linking1_wasm); 48 wasm_byte_vec_delete(&linking2_wasm); 49 50 // Configure WASI and store it within our `wasmtime_store_t` 51 wasi_config_t *wasi_config = wasi_config_new(); 52 assert(wasi_config); 53 wasi_config_inherit_argv(wasi_config); 54 wasi_config_inherit_env(wasi_config); 55 wasi_config_inherit_stdin(wasi_config); 56 wasi_config_inherit_stdout(wasi_config); 57 wasi_config_inherit_stderr(wasi_config); 58 wasm_trap_t *trap = NULL; 59 error = wasmtime_context_set_wasi(context, wasi_config); 60 if (error != NULL) 61 exit_with_error("failed to instantiate wasi", NULL, trap); 62 63 // Create our linker which will be linking our modules together, and then add 64 // our WASI instance to it. 65 wasmtime_linker_t *linker = wasmtime_linker_new(engine); 66 error = wasmtime_linker_define_wasi(linker); 67 if (error != NULL) 68 exit_with_error("failed to link wasi", error, NULL); 69 70 // Instantiate `linking2` with our linker. 71 wasmtime_instance_t linking2; 72 error = wasmtime_linker_instantiate(linker, context, linking2_module, 73 &linking2, &trap); 74 if (error != NULL || trap != NULL) 75 exit_with_error("failed to instantiate linking2", error, trap); 76 77 // Register our new `linking2` instance with the linker 78 error = wasmtime_linker_define_instance(linker, context, "linking2", 79 strlen("linking2"), &linking2); 80 if (error != NULL) 81 exit_with_error("failed to link linking2", error, NULL); 82 83 // Instantiate `linking1` with the linker now that `linking2` is defined 84 wasmtime_instance_t linking1; 85 error = wasmtime_linker_instantiate(linker, context, linking1_module, 86 &linking1, &trap); 87 if (error != NULL || trap != NULL) 88 exit_with_error("failed to instantiate linking1", error, trap); 89 90 // Lookup our `run` export function 91 wasmtime_extern_t run; 92 bool ok = wasmtime_instance_export_get(context, &linking1, "run", 3, &run); 93 assert(ok); 94 assert(run.kind == WASMTIME_EXTERN_FUNC); 95 error = wasmtime_func_call(context, &run.of.func, NULL, 0, NULL, 0, &trap); 96 if (error != NULL || trap != NULL) 97 exit_with_error("failed to call run", error, trap); 98 99 // Clean up after ourselves at this point 100 wasmtime_linker_delete(linker); 101 wasmtime_module_delete(linking1_module); 102 wasmtime_module_delete(linking2_module); 103 wasmtime_store_delete(store); 104 wasm_engine_delete(engine); 105 return 0; 106 } 107 108 static void read_wat_file(wasm_byte_vec_t *bytes, const char *filename) { 109 wasm_byte_vec_t wat; 110 // Load our input file to parse it next 111 FILE *file = fopen(filename, "r"); 112 if (!file) { 113 printf("> Error loading file!\n"); 114 exit(1); 115 } 116 fseek(file, 0L, SEEK_END); 117 size_t file_size = ftell(file); 118 wasm_byte_vec_new_uninitialized(&wat, file_size); 119 fseek(file, 0L, SEEK_SET); 120 if (fread(wat.data, file_size, 1, file) != 1) { 121 printf("> Error loading module!\n"); 122 exit(1); 123 } 124 fclose(file); 125 126 // Parse the wat into the binary wasm format 127 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, bytes); 128 if (error != NULL) 129 exit_with_error("failed to parse wat", error, NULL); 130 wasm_byte_vec_delete(&wat); 131 } 132 133 static void exit_with_error(const char *message, wasmtime_error_t *error, 134 wasm_trap_t *trap) { 135 fprintf(stderr, "error: %s\n", message); 136 wasm_byte_vec_t error_message; 137 if (error != NULL) { 138 wasmtime_error_message(error, &error_message); 139 wasmtime_error_delete(error); 140 } else { 141 wasm_trap_message(trap, &error_message); 142 wasm_trap_delete(trap); 143 } 144 fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data); 145 wasm_byte_vec_delete(&error_message); 146 exit(1); 147 } 148