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