xref: /wasmtime-44.0.1/examples/multi.c (revision ef70686b)
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/multi.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 multi
14    ./multi
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 You can also build using cmake:
20 
21 mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-multi
22 
23 Also note that this example was taken from
24 https://github.com/WebAssembly/wasm-c-api/blob/master/example/multi.c
25 originally
26 */
27 
28 #include <inttypes.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <wasm.h>
33 #include <wasmtime.h>
34 
35 static void exit_with_error(const char *message, wasmtime_error_t *error,
36                             wasm_trap_t *trap);
37 
38 // A function to be called from Wasm code.
39 wasm_trap_t *callback(void *env, wasmtime_caller_t *caller,
40                       const wasmtime_val_t *args, size_t nargs,
41                       wasmtime_val_t *results, size_t nresults) {
42   printf("Calling back...\n");
43   printf("> %" PRIu32 " %" PRIu64 "\n", args[0].of.i32, args[1].of.i64);
44   printf("\n");
45 
46   results[0] = args[1];
47   results[1] = args[0];
48   return NULL;
49 }
50 
51 // A function closure.
52 wasm_trap_t *closure_callback(void *env, wasmtime_caller_t *caller,
53                               const wasmtime_val_t *args, size_t nargs,
54                               wasmtime_val_t *results, size_t nresults) {
55   int i = *(int *)env;
56   printf("Calling back closure...\n");
57   printf("> %d\n", i);
58 
59   results[0].kind = WASMTIME_I32;
60   results[0].of.i32 = (int32_t)i;
61   return NULL;
62 }
63 
64 int main(int argc, const char *argv[]) {
65   // Initialize.
66   printf("Initializing...\n");
67   wasm_engine_t *engine = wasm_engine_new();
68   wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
69   wasmtime_context_t *context = wasmtime_store_context(store);
70 
71   // Load our input file to parse it next
72   FILE *file = fopen("examples/multi.wat", "r");
73   if (!file) {
74     printf("> Error loading file!\n");
75     return 1;
76   }
77   fseek(file, 0L, SEEK_END);
78   size_t file_size = ftell(file);
79   fseek(file, 0L, SEEK_SET);
80   wasm_byte_vec_t wat;
81   wasm_byte_vec_new_uninitialized(&wat, file_size);
82   if (fread(wat.data, file_size, 1, file) != 1) {
83     printf("> Error loading module!\n");
84     return 1;
85   }
86   fclose(file);
87 
88   // Parse the wat into the binary wasm format
89   wasm_byte_vec_t binary;
90   wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
91   if (error != NULL)
92     exit_with_error("failed to parse wat", error, NULL);
93   wasm_byte_vec_delete(&wat);
94 
95   // Compile.
96   printf("Compiling module...\n");
97   wasmtime_module_t *module = NULL;
98   error =
99       wasmtime_module_new(engine, (uint8_t *)binary.data, binary.size, &module);
100   if (error)
101     exit_with_error("failed to compile module", error, NULL);
102   wasm_byte_vec_delete(&binary);
103 
104   // Create external print functions.
105   printf("Creating callback...\n");
106   wasm_functype_t *callback_type =
107       wasm_functype_new_2_2(wasm_valtype_new_i32(), wasm_valtype_new_i64(),
108                             wasm_valtype_new_i64(), wasm_valtype_new_i32());
109   wasmtime_func_t callback_func;
110   wasmtime_func_new(context, callback_type, callback, NULL, NULL,
111                     &callback_func);
112   wasm_functype_delete(callback_type);
113 
114   // Instantiate.
115   printf("Instantiating module...\n");
116   wasmtime_extern_t imports[1];
117   imports[0].kind = WASMTIME_EXTERN_FUNC;
118   imports[0].of.func = callback_func;
119   wasmtime_instance_t instance;
120   wasm_trap_t *trap = NULL;
121   error = wasmtime_instance_new(context, module, imports, 1, &instance, &trap);
122   if (error != NULL || trap != NULL)
123     exit_with_error("failed to instantiate", error, trap);
124   wasmtime_module_delete(module);
125 
126   // Extract export.
127   printf("Extracting export...\n");
128   wasmtime_extern_t run;
129   bool ok = wasmtime_instance_export_get(context, &instance, "g", 1, &run);
130   assert(ok);
131   assert(run.kind == WASMTIME_EXTERN_FUNC);
132 
133   // Call.
134   printf("Calling export...\n");
135   wasmtime_val_t args[2];
136   args[0].kind = WASMTIME_I32;
137   args[0].of.i32 = 1;
138   args[1].kind = WASMTIME_I64;
139   args[1].of.i64 = 2;
140   wasmtime_val_t results[2];
141   error = wasmtime_func_call(context, &run.of.func, args, 2, results, 2, &trap);
142   if (error != NULL || trap != NULL)
143     exit_with_error("failed to call run", error, trap);
144 
145   // Print result.
146   printf("Printing result...\n");
147   printf("> %" PRIu64 " %" PRIu32 "\n", results[0].of.i64, results[1].of.i32);
148 
149   assert(results[0].kind == WASMTIME_I64);
150   assert(results[0].of.i64 == 2);
151   assert(results[1].kind == WASMTIME_I32);
152   assert(results[1].of.i32 == 1);
153 
154   // Shut down.
155   printf("Shutting down...\n");
156   wasmtime_store_delete(store);
157   wasm_engine_delete(engine);
158 
159   // All done.
160   printf("Done.\n");
161   return 0;
162 }
163 
164 static void exit_with_error(const char *message, wasmtime_error_t *error,
165                             wasm_trap_t *trap) {
166   fprintf(stderr, "error: %s\n", message);
167   wasm_byte_vec_t error_message;
168   if (error != NULL) {
169     wasmtime_error_message(error, &error_message);
170     wasmtime_error_delete(error);
171   } else {
172     wasm_trap_message(trap, &error_message);
173     wasm_trap_delete(trap);
174   }
175   fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data);
176   wasm_byte_vec_delete(&error_message);
177   exit(1);
178 }
179