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