diff --git a/docs/wasm-wasi-example.md b/docs/wasm-wasi-example.md index eae26de9d2..1dea658519 100644 --- a/docs/wasm-wasi-example.md +++ b/docs/wasm-wasi-example.md @@ -40,7 +40,7 @@ This is from a main function from a wasm module ```Containerfile FROM scratch COPY hello.wasm / -CMD ["/hello.wasm"] +ENTRYPOINT ["/hello.wasm"] ``` * Build wasm image using buildah ```console diff --git a/src/libcrun/handlers/handler-utils.c b/src/libcrun/handlers/handler-utils.c index 608644ec82..676037d9f8 100644 --- a/src/libcrun/handlers/handler-utils.c +++ b/src/libcrun/handlers/handler-utils.c @@ -19,6 +19,7 @@ #define _GNU_SOURCE #include +#include #include "../container.h" #include "../utils.h" #include "handler-utils.h" @@ -69,3 +70,28 @@ wasm_can_handle_container (libcrun_container_t *container, libcrun_error_t *err return 0; } + +wasm_encoding_t +wasm_interpret_header (const char *header, const size_t len) +{ + if (len < 8) + return WASM_ENC_INVALID; + + // Check for the WebAssembly magic bytes + // See: https://webassembly.github.io/spec/core/binary/modules.html#binary-module + if (memcmp (header, "\0asm", 4)) + return WASM_ENC_INVALID; + + /* The next four bytes are the WebAssembly version. + We don't care for the specific WebAssembly version + so we only read the value of the `layer` field which + was defined by the component spec. + See: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md#component-definitions + */ + if (header[6] == '\0' && header[7] == '\0') + return WASM_ENC_MODULE; + + // `layer` does not equal `0x00 0x00` so we are working + // with a component. + return WASM_ENC_COMPONENT; +} diff --git a/src/libcrun/handlers/handler-utils.h b/src/libcrun/handlers/handler-utils.h index 98e94d7ba1..d0a132b4d0 100644 --- a/src/libcrun/handlers/handler-utils.h +++ b/src/libcrun/handlers/handler-utils.h @@ -21,6 +21,15 @@ #include "../container.h" #include +typedef enum +{ + WASM_ENC_INVALID, + WASM_ENC_MODULE, + WASM_ENC_COMPONENT +} wasm_encoding_t; + int wasm_can_handle_container (libcrun_container_t *container, libcrun_error_t *err); +wasm_encoding_t wasm_interpret_header (const char *header, const size_t len); + #endif diff --git a/src/libcrun/handlers/wasmtime.c b/src/libcrun/handlers/wasmtime.c index 7bcf052e41..c2099b4a3f 100644 --- a/src/libcrun/handlers/wasmtime.c +++ b/src/libcrun/handlers/wasmtime.c @@ -29,9 +29,9 @@ #include #include #include -#include #include #include +#include #ifdef HAVE_DLOPEN # include @@ -44,48 +44,167 @@ #endif #if HAVE_DLOPEN && HAVE_WASMTIME +static void * +libwasmtime_load_symbol (void *cookie, char *const symbol); + +static void +libwasmtime_run_module (void *cookie, char *const argv[], wasm_engine_t *engine, wasm_byte_vec_t *wasm); + +static void +libwasmtime_run_component (void *cookie, char *const argv[], wasm_engine_t *engine, wasm_byte_vec_t *wasm); + static int libwasmtime_exec (void *cookie, libcrun_container_t *container arg_unused, const char *pathname, char *const argv[]) +{ + wasm_byte_vec_t error_message; + wasm_byte_vec_t wasm_bytes; + + wasm_engine_t *(*wasm_engine_new) () + = libwasmtime_load_symbol (cookie, "wasm_engine_new"); + wasmtime_error_t *(*wasmtime_wat2wasm) (const char *wat, size_t wat_len, wasm_byte_vec_t *out) + = libwasmtime_load_symbol (cookie, "wasmtime_wat2wasm"); + void (*wasm_byte_vec_new_uninitialized) (wasm_byte_vec_t *, size_t) + = libwasmtime_load_symbol (cookie, "wasm_byte_vec_new_uninitialized"); + void (*wasm_byte_vec_delete) (wasm_byte_vec_t *) + = libwasmtime_load_symbol (cookie, "wasm_byte_vec_delete"); + void (*wasmtime_error_message) (const wasmtime_error_t *error, wasm_name_t *message) + = libwasmtime_load_symbol (cookie, "wasmtime_error_message"); + void (*wasmtime_error_delete) (wasmtime_error_t *error) + = libwasmtime_load_symbol (cookie, "wasmtime_error_delete"); + + // Set up wasmtime context + wasm_engine_t *engine = wasm_engine_new (); + if (engine == NULL) + error (EXIT_FAILURE, 0, "could not create WebAssembly engine"); + + wasm_byte_vec_t wasm; + // Load and parse container entrypoint + FILE *file = fopen (pathname, "rbe"); + if (! file) + error (EXIT_FAILURE, 0, "error loading entrypoint"); + if (fseek (file, 0L, SEEK_END)) + error (EXIT_FAILURE, 0, "error fully loading entrypoint"); + size_t file_size = ftell (file); + if (file_size == (size_t) -1L) + error (EXIT_FAILURE, 0, "error getting entrypoint size"); + wasm_byte_vec_new_uninitialized (&wasm, file_size); + if (fseek (file, 0L, SEEK_SET)) + error (EXIT_FAILURE, 0, "error resetting entrypoint"); + if (fread (wasm.data, file_size, 1, file) != 1) + error (EXIT_FAILURE, 0, "error reading entrypoint"); + fclose (file); + + // If entrypoint contains a webassembly text format + // compile it on the fly and convert to equivalent + // binary format. + if (has_suffix (pathname, ".wat") > 0) + { + wasmtime_error_t *err = wasmtime_wat2wasm ((char *) wasm.data, file_size, &wasm_bytes); + if (err != NULL) + { + wasmtime_error_message (err, &error_message); + wasmtime_error_delete (err); + error (EXIT_FAILURE, 0, "failed while compiling wat to wasm binary : %.*s", (int) error_message.size, error_message.data); + } + wasm_byte_vec_delete (&wasm); + wasm = wasm_bytes; + } + + wasm_encoding_t wasm_enc = wasm_interpret_header (wasm.data, wasm.size); + if (wasm_enc == WASM_ENC_INVALID) + error (EXIT_FAILURE, 0, "invalid wasm binary header"); + + if (wasm_enc == WASM_ENC_MODULE) + libwasmtime_run_module (cookie, argv, engine, &wasm); + else if (wasm_enc == WASM_ENC_COMPONENT) + libwasmtime_run_component (cookie, argv, engine, &wasm); + else + error (EXIT_FAILURE, 0, "unsupported wasm encoding detected"); + + exit (EXIT_SUCCESS); +} + +static void * +libwasmtime_load_symbol (void *cookie, char *const symbol) +{ + void *sym = dlsym (cookie, symbol); + if (sym == NULL) + error (EXIT_FAILURE, 0, "could not find symbol in `libwasmtime.so`: %.*s", (int) strlen (symbol), symbol); + + return sym; +} + +# define WASMTIME_COMMON_SYMBOLS(cookie) \ + void (*wasm_engine_delete) (wasm_engine_t *) \ + = libwasmtime_load_symbol ((cookie), "wasm_engine_delete"); \ + void (*wasm_byte_vec_delete) (wasm_byte_vec_t *) \ + = libwasmtime_load_symbol ((cookie), "wasm_byte_vec_delete"); \ + wasmtime_store_t *(*wasmtime_store_new) (wasm_engine_t * engine, void *data, void (*finalizer) (void *)) \ + = libwasmtime_load_symbol ((cookie), "wasmtime_store_new"); \ + void (*wasmtime_store_delete) (wasmtime_store_t * store) \ + = libwasmtime_load_symbol ((cookie), "wasmtime_store_delete"); \ + wasmtime_context_t *(*wasmtime_store_context) (wasmtime_store_t * store) \ + = libwasmtime_load_symbol ((cookie), "wasmtime_store_context"); \ + void (*wasi_config_inherit_env) (wasi_config_t * config) \ + = libwasmtime_load_symbol ((cookie), "wasi_config_inherit_env"); \ + void (*wasmtime_error_message) (const wasmtime_error_t *error, wasm_name_t *message) \ + = libwasmtime_load_symbol ((cookie), "wasmtime_error_message"); \ + void (*wasmtime_error_delete) (wasmtime_error_t * error) \ + = libwasmtime_load_symbol ((cookie), "wasmtime_error_delete"); \ + bool (*wasi_config_preopen_dir) ( \ + wasi_config_t * config, \ + const char *path, \ + const char *guest_path, \ + wasi_dir_perms dir_perms, \ + wasi_file_perms file_perms) \ + = libwasmtime_load_symbol ((cookie), "wasi_config_preopen_dir"); + +static void +libwasmtime_run_module (void *cookie, char *const argv[], wasm_engine_t *engine, wasm_byte_vec_t *wasm) { size_t args_size = 0; char *const *arg; wasm_byte_vec_t error_message; - wasm_byte_vec_t wasm_bytes; - wasm_engine_t *(*wasm_engine_new) (); - wasmtime_error_t *(*wasmtime_wat2wasm) (const char *wat, size_t wat_len, wasm_byte_vec_t *out); - void (*wasm_engine_delete) (wasm_engine_t *); - void (*wasm_byte_vec_delete) (wasm_byte_vec_t *); - void (*wasm_byte_vec_new_uninitialized) (wasm_byte_vec_t *, size_t); - wasi_config_t *(*wasi_config_new) (const char *); - wasmtime_store_t *(*wasmtime_store_new) (wasm_engine_t *engine, void *data, void (*finalizer) (void *)); - wasmtime_context_t *(*wasmtime_store_context) (wasmtime_store_t *store); - wasmtime_linker_t *(*wasmtime_linker_new) (wasm_engine_t *engine); - wasmtime_error_t *(*wasmtime_linker_define_wasi) (wasmtime_linker_t *linker); + + // Load needed functions + WASMTIME_COMMON_SYMBOLS (cookie) + wasi_config_t *(*wasi_config_new) (const char *) + = libwasmtime_load_symbol (cookie, "wasi_config_new"); + wasmtime_linker_t *(*wasmtime_linker_new) (wasm_engine_t *engine) + = libwasmtime_load_symbol (cookie, "wasmtime_linker_new"); + wasmtime_error_t *(*wasmtime_linker_define_wasi) (wasmtime_linker_t *linker) + = libwasmtime_load_symbol (cookie, "wasmtime_linker_define_wasi"); wasmtime_error_t *(*wasmtime_module_new) ( wasm_engine_t *engine, const uint8_t *wasm, size_t wasm_len, - wasmtime_module_t **ret); - void (*wasi_config_inherit_argv) (wasi_config_t *config); - void (*wasi_config_inherit_env) (wasi_config_t *config); - void (*wasi_config_set_argv) (wasi_config_t *config, int argc, const char *argv[]); - void (*wasi_config_inherit_stdin) (wasi_config_t *config); - void (*wasi_config_inherit_stdout) (wasi_config_t *config); - void (*wasi_config_inherit_stderr) (wasi_config_t *config); - wasmtime_error_t *(*wasmtime_context_set_wasi) (wasmtime_context_t *context, wasi_config_t *wasi); + wasmtime_module_t **ret) + = libwasmtime_load_symbol (cookie, "wasmtime_module_new"); + void (*wasi_config_set_argv) (wasi_config_t *config, int argc, const char *argv[]) + = libwasmtime_load_symbol (cookie, "wasi_config_set_argv"); + void (*wasi_config_inherit_stdin) (wasi_config_t *config) + = libwasmtime_load_symbol (cookie, "wasi_config_inherit_stdin"); + void (*wasi_config_inherit_stdout) (wasi_config_t *config) + = libwasmtime_load_symbol (cookie, "wasi_config_inherit_stdout"); + void (*wasi_config_inherit_stderr) (wasi_config_t *config) + = libwasmtime_load_symbol (cookie, "wasi_config_inherit_stderr"); + wasmtime_error_t *(*wasmtime_context_set_wasi) (wasmtime_context_t *context, wasi_config_t *wasi) + = libwasmtime_load_symbol (cookie, "wasmtime_context_set_wasi"); wasmtime_error_t *(*wasmtime_linker_module) ( wasmtime_linker_t *linker, wasmtime_context_t *store, const char *name, size_t name_len, - const wasmtime_module_t *module); + const wasmtime_module_t *module) + = libwasmtime_load_symbol (cookie, "wasmtime_linker_module"); wasmtime_error_t *(*wasmtime_linker_get_default) ( const wasmtime_linker_t *linker, wasmtime_context_t *store, const char *name, size_t name_len, - wasmtime_func_t *func); + wasmtime_func_t *func) + = libwasmtime_load_symbol (cookie, "wasmtime_linker_get_default"); wasmtime_error_t *(*wasmtime_func_call) ( wasmtime_context_t *store, const wasmtime_func_t *func, @@ -93,57 +212,15 @@ libwasmtime_exec (void *cookie, libcrun_container_t *container arg_unused, size_t nargs, wasmtime_val_t *results, size_t nresults, - wasm_trap_t **trap); - void (*wasmtime_module_delete) (wasmtime_module_t *m); - void (*wasmtime_store_delete) (wasmtime_store_t *store); - void (*wasmtime_error_message) (const wasmtime_error_t *error, wasm_name_t *message); - void (*wasmtime_error_delete) (wasmtime_error_t *error); - bool (*wasi_config_preopen_dir) (wasi_config_t *config, const char *path, const char *guest_path); - - wasmtime_wat2wasm = dlsym (cookie, "wasmtime_wat2wasm"); - wasm_engine_new = dlsym (cookie, "wasm_engine_new"); - wasm_engine_delete = dlsym (cookie, "wasm_engine_delete"); - wasm_byte_vec_delete = dlsym (cookie, "wasm_byte_vec_delete"); - wasm_byte_vec_new_uninitialized = dlsym (cookie, "wasm_byte_vec_new_uninitialized"); - wasi_config_new = dlsym (cookie, "wasi_config_new"); - wasi_config_set_argv = dlsym (cookie, "wasi_config_set_argv"); - wasmtime_store_new = dlsym (cookie, "wasmtime_store_new"); - wasmtime_store_context = dlsym (cookie, "wasmtime_store_context"); - wasmtime_linker_new = dlsym (cookie, "wasmtime_linker_new"); - wasmtime_linker_define_wasi = dlsym (cookie, "wasmtime_linker_define_wasi"); - wasmtime_module_new = dlsym (cookie, "wasmtime_module_new"); - wasi_config_inherit_argv = dlsym (cookie, "wasi_config_inherit_argv"); - wasi_config_inherit_stdout = dlsym (cookie, "wasi_config_inherit_stdout"); - wasi_config_inherit_stdin = dlsym (cookie, "wasi_config_inherit_stdin"); - wasi_config_inherit_stderr = dlsym (cookie, "wasi_config_inherit_stderr"); - wasi_config_inherit_env = dlsym (cookie, "wasi_config_inherit_env"); - wasmtime_context_set_wasi = dlsym (cookie, "wasmtime_context_set_wasi"); - wasmtime_linker_module = dlsym (cookie, "wasmtime_linker_module"); - wasmtime_linker_get_default = dlsym (cookie, "wasmtime_linker_get_default"); - wasmtime_func_call = dlsym (cookie, "wasmtime_func_call"); - wasmtime_module_delete = dlsym (cookie, "wasmtime_module_delete"); - wasmtime_store_delete = dlsym (cookie, "wasmtime_store_delete"); - wasmtime_error_delete = dlsym (cookie, "wasmtime_error_delete"); - wasmtime_error_message = dlsym (cookie, "wasmtime_error_message"); - wasi_config_preopen_dir = dlsym (cookie, "wasi_config_preopen_dir"); - - if (wasm_engine_new == NULL || wasm_engine_delete == NULL || wasm_byte_vec_delete == NULL - || wasm_byte_vec_new_uninitialized == NULL || wasi_config_new == NULL || wasmtime_store_new == NULL - || wasmtime_store_context == NULL || wasmtime_linker_new == NULL || wasmtime_linker_define_wasi == NULL - || wasmtime_module_new == NULL || wasi_config_inherit_argv == NULL || wasi_config_inherit_stdout == NULL - || wasi_config_inherit_stdin == NULL || wasi_config_inherit_stderr == NULL - || wasi_config_inherit_env == NULL || wasmtime_context_set_wasi == NULL - || wasmtime_linker_module == NULL || wasmtime_linker_get_default == NULL || wasmtime_func_call == NULL - || wasmtime_module_delete == NULL || wasmtime_store_delete == NULL || wasi_config_set_argv == NULL - || wasmtime_error_delete == NULL || wasmtime_error_message == NULL || wasi_config_preopen_dir == NULL - || wasmtime_wat2wasm == NULL) - error (EXIT_FAILURE, 0, "could not find symbol in `libwasmtime.so`"); + wasm_trap_t **trap) + = libwasmtime_load_symbol (cookie, "wasmtime_func_call"); + void (*wasmtime_module_delete) (wasmtime_module_t *m) + = libwasmtime_load_symbol (cookie, "wasmtime_module_delete"); // Set up wasmtime context - wasm_engine_t *engine = wasm_engine_new (); - assert (engine != NULL); wasmtime_store_t *store = wasmtime_store_new (engine, NULL, NULL); - assert (store != NULL); + if (store == NULL) + error (EXIT_FAILURE, 0, "could not create WebAssembly store"); wasmtime_context_t *context = wasmtime_store_context (store); // Link with wasi functions defined @@ -156,48 +233,23 @@ libwasmtime_exec (void *cookie, libcrun_container_t *container arg_unused, error (EXIT_FAILURE, 0, "failed to link wasi: %.*s", (int) error_message.size, error_message.data); } - wasm_byte_vec_t wasm; - // Load and parse container entrypoint - FILE *file = fopen (pathname, "rbe"); - if (! file) - error (EXIT_FAILURE, 0, "error loading entrypoint"); - fseek (file, 0L, SEEK_END); - size_t file_size = ftell (file); - wasm_byte_vec_new_uninitialized (&wasm, file_size); - fseek (file, 0L, SEEK_SET); - if (fread (wasm.data, file_size, 1, file) != 1) - error (EXIT_FAILURE, 0, "error load"); - fclose (file); - - // If entrypoint contains a webassembly text format - // compile it on the fly and convert to equivalent - // binary format. - if (has_suffix (pathname, "wat") > 0) - { - wasmtime_error_t *err = wasmtime_wat2wasm ((char *) &wasm_bytes, file_size, &wasm); - if (err != NULL) - { - wasmtime_error_message (err, &error_message); - wasmtime_error_delete (err); - error (EXIT_FAILURE, 0, "failed while compiling wat to wasm binary : %.*s", (int) error_message.size, error_message.data); - } - wasm = wasm_bytes; - } - // Compile wasm modules wasmtime_module_t *module = NULL; - err = wasmtime_module_new (engine, (uint8_t *) wasm.data, wasm.size, &module); - if (! module) + err = wasmtime_module_new (engine, (uint8_t *) wasm->data, wasm->size, &module); + if (err != NULL) { wasmtime_error_message (err, &error_message); wasmtime_error_delete (err); error (EXIT_FAILURE, 0, "failed to compile module: %.*s", (int) error_message.size, error_message.data); } - wasm_byte_vec_delete (&wasm); + if (module == NULL) + error (EXIT_FAILURE, 0, "internal error: module is NULL"); + wasm_byte_vec_delete (wasm); // Init WASI program wasi_config_t *wasi_config = wasi_config_new ("crun_wasi_program"); - assert (wasi_config); + if (wasi_config == NULL) + error (EXIT_FAILURE, 0, "could not create WASI configuration"); // Calculate argc for `wasi_config_set_argv` for (arg = argv; *arg != NULL; ++arg) @@ -208,7 +260,12 @@ libwasmtime_exec (void *cookie, libcrun_container_t *container arg_unused, wasi_config_inherit_stdin (wasi_config); wasi_config_inherit_stdout (wasi_config); wasi_config_inherit_stderr (wasi_config); - wasi_config_preopen_dir (wasi_config, ".", "."); + wasi_config_preopen_dir ( + wasi_config, + ".", + ".", + WASMTIME_WASI_DIR_PERMS_READ | WASMTIME_WASI_DIR_PERMS_WRITE, + WASMTIME_WASI_FILE_PERMS_READ | WASMTIME_WASI_FILE_PERMS_WRITE); wasm_trap_t *trap = NULL; err = wasmtime_context_set_wasi (context, wasi_config); if (err != NULL) @@ -249,8 +306,175 @@ libwasmtime_exec (void *cookie, libcrun_container_t *container arg_unused, wasmtime_module_delete (module); wasmtime_store_delete (store); wasm_engine_delete (engine); +} - exit (EXIT_SUCCESS); +static void +libwasmtime_run_component (void *cookie, char *const argv[], wasm_engine_t *engine, wasm_byte_vec_t *wasm) +{ + const char *const wasi_cli_run_interface = "wasi:cli/run@0.2.0"; + const char *const wasi_cli_run_interface_run = "run"; + char *const *arg; + wasm_byte_vec_t error_message; + + // Load needed functions + WASMTIME_COMMON_SYMBOLS (cookie) + wasmtime_error_t *(*wasmtime_component_new) ( + const wasm_engine_t *engine, + const uint8_t *buf, + size_t len, + wasmtime_component_t **component_out) + = libwasmtime_load_symbol (cookie, "wasmtime_component_new"); + wasmtime_wasip2_config_t *(*wasmtime_wasip2_config_new) (void) + = libwasmtime_load_symbol (cookie, "wasmtime_wasip2_config_new"); + void (*wasmtime_wasip2_config_inherit_stdin) (wasmtime_wasip2_config_t *config) + = libwasmtime_load_symbol (cookie, "wasmtime_wasip2_config_inherit_stdin"); + void (*wasmtime_wasip2_config_inherit_stdout) (wasmtime_wasip2_config_t *config) + = libwasmtime_load_symbol (cookie, "wasmtime_wasip2_config_inherit_stdout"); + void (*wasmtime_wasip2_config_inherit_stderr) (wasmtime_wasip2_config_t *config) + = libwasmtime_load_symbol (cookie, "wasmtime_wasip2_config_inherit_stderr"); + void (*wasmtime_wasip2_config_arg) (wasmtime_wasip2_config_t *config, const char *arg, size_t arg_len) + = libwasmtime_load_symbol (cookie, "wasmtime_wasip2_config_arg"); + void (*wasmtime_context_set_wasip2) (wasmtime_context_t *context, wasmtime_wasip2_config_t *config) + = libwasmtime_load_symbol (cookie, "wasmtime_context_set_wasip2"); + wasmtime_component_linker_t *(*wasmtime_component_linker_new) (wasm_engine_t *engine) + = libwasmtime_load_symbol (cookie, "wasmtime_component_linker_new"); + wasmtime_error_t *(*wasmtime_component_linker_add_wasip2) (wasmtime_component_linker_t *linker) + = libwasmtime_load_symbol (cookie, "wasmtime_component_linker_add_wasip2"); + wasmtime_error_t *(*wasmtime_component_linker_instantiate) ( + const wasmtime_component_linker_t *linker, + wasmtime_context_t *context, + const wasmtime_component_t *component, + wasmtime_component_instance_t *instance_out) + = libwasmtime_load_symbol (cookie, "wasmtime_component_linker_instantiate"); + wasmtime_component_export_index_t *(*wasmtime_component_instance_get_export_index) ( + const wasmtime_component_instance_t *instance, + wasmtime_context_t *context, + const wasmtime_component_export_index_t *instance_export_index, + const char *name, + size_t name_len) + = libwasmtime_load_symbol (cookie, "wasmtime_component_instance_get_export_index"); + bool (*wasmtime_component_instance_get_func) ( + const wasmtime_component_instance_t *instance, + wasmtime_context_t *context, + const wasmtime_component_export_index_t *export_index, + wasmtime_component_func_t *func_out) + = libwasmtime_load_symbol (cookie, "wasmtime_component_instance_get_func"); + wasmtime_error_t *(*wasmtime_component_func_call) ( + const wasmtime_component_func_t *func, + wasmtime_context_t *context, + const wasmtime_component_val_t *args, + size_t args_size, + wasmtime_component_val_t *results, + size_t results_size) + = libwasmtime_load_symbol (cookie, "wasmtime_component_func_call"); + void (*wasmtime_component_export_index_delete) (wasmtime_component_export_index_t *export_index) + = libwasmtime_load_symbol (cookie, "wasmtime_component_export_index_delete"); + void (*wasmtime_component_delete) (wasmtime_component_t *c) + = libwasmtime_load_symbol (cookie, "wasmtime_component_delete"); + void (*wasmtime_component_linker_delete) (wasmtime_component_linker_t *linker) + = libwasmtime_load_symbol (cookie, "wasmtime_component_linker_delete"); + + // Set up wasmtime context + wasmtime_store_t *store = wasmtime_store_new (engine, NULL, NULL); + if (store == NULL) + error (EXIT_FAILURE, 0, "could not create WebAssembly store"); + wasmtime_context_t *context = wasmtime_store_context (store); + + // Compile wasm component + wasmtime_component_t *component = NULL; + wasmtime_error_t *err = wasmtime_component_new (engine, (uint8_t *) wasm->data, wasm->size, &component); + if (err != NULL) + { + wasmtime_error_message (err, &error_message); + wasmtime_error_delete (err); + error (EXIT_FAILURE, 0, "failed to compile component: %.*s", (int) error_message.size, error_message.data); + } + if (component == NULL) + error (EXIT_FAILURE, 0, "internal error: component is NULL"); + wasm_byte_vec_delete (wasm); + + // Set up WASIp2 config + wasmtime_wasip2_config_t *wasi_config = wasmtime_wasip2_config_new (); + if (wasi_config == NULL) + error (EXIT_FAILURE, 0, "could not create WASIp2 configuration"); + + wasi_config_inherit_env ((wasi_config_t *) wasi_config); + wasmtime_wasip2_config_inherit_stdin (wasi_config); + wasmtime_wasip2_config_inherit_stdout (wasi_config); + wasmtime_wasip2_config_inherit_stderr (wasi_config); + wasi_config_preopen_dir ( + (wasi_config_t *) wasi_config, + ".", + ".", + WASMTIME_WASI_DIR_PERMS_READ | WASMTIME_WASI_DIR_PERMS_WRITE, + WASMTIME_WASI_FILE_PERMS_READ | WASMTIME_WASI_FILE_PERMS_WRITE); + + for (arg = argv; *arg != NULL; ++arg) + wasmtime_wasip2_config_arg (wasi_config, *arg, strlen (*arg)); + + wasmtime_context_set_wasip2 (context, wasi_config); + + // Get wasi exposing linker + wasmtime_component_linker_t *linker = wasmtime_component_linker_new (engine); + err = wasmtime_component_linker_add_wasip2 (linker); + if (err != NULL) + { + wasmtime_error_message (err, &error_message); + wasmtime_error_delete (err); + error (EXIT_FAILURE, 0, "failed to add WASIp2 to linker: %.*s", (int) error_message.size, error_message.data); + } + + // Instantiate the component + wasmtime_component_instance_t component_inst = {}; + err = wasmtime_component_linker_instantiate (linker, context, component, &component_inst); + if (err != NULL) + { + wasmtime_error_message (err, &error_message); + wasmtime_error_delete (err); + error (EXIT_FAILURE, 0, "failed to instantiate component: %.*s", (int) error_message.size, error_message.data); + } + + // Get index of the run interface in wasi/cli world + wasmtime_component_export_index_t *run_interface_idx = wasmtime_component_instance_get_export_index ( + &component_inst, + context, + NULL, + wasi_cli_run_interface, + strlen (wasi_cli_run_interface)); + if (run_interface_idx == NULL) + error (EXIT_FAILURE, 0, "failed to fetch export index of %.*s", (int) strlen (wasi_cli_run_interface), wasi_cli_run_interface); + // Get index of the run function + wasmtime_component_export_index_t *run_func_idx = wasmtime_component_instance_get_export_index ( + &component_inst, + context, + run_interface_idx, + wasi_cli_run_interface_run, + strlen (wasi_cli_run_interface_run)); + if (run_func_idx == NULL) + error (EXIT_FAILURE, 0, "failed to fetch export index of %.*s", (int) strlen (wasi_cli_run_interface_run), wasi_cli_run_interface_run); + + // Actually retrieve the func + wasmtime_component_func_t run_func = {}; + if (! wasmtime_component_instance_get_func (&component_inst, context, run_func_idx, &run_func)) + error (EXIT_FAILURE, 0, "failed to retrieve run function"); + + // Call the func + wasmtime_component_val_t result = {}; + err = wasmtime_component_func_call (&run_func, context, NULL, 0, &result, 1); + if (err != NULL) + { + wasmtime_error_message (err, &error_message); + wasmtime_error_delete (err); + error (EXIT_FAILURE, 0, "error calling run function: %.*s", (int) error_message.size, error_message.data); + } + + // Clean everything + wasmtime_component_export_index_delete (run_func_idx); + wasmtime_component_export_index_delete (run_interface_idx); + wasmtime_component_linker_delete (linker); + wasmtime_component_delete (component); + wasmtime_store_delete (store); + wasm_engine_delete (engine); } static int