C/C++

Note: This document is about how to embed WAMR into C/C++ host applications, for other languages, please refer to: Embed WAMR into Python, Embed WAMR into Go.

All the embedding APIs supported by the runtime are defined under folder core/iwasm/includearrow-up-right. The API details are available in the header files.

Embed WAMR into developer's project

WAMR is designed to be easy embeddable in any project, a typical way of building WAMR is to use cmake, developer can configure features by setting cmake variables and then include the script runtime_lib.cmake under folder build-scriptsarrow-up-right in his CMakeList.txt, for example:

set (WAMR_BUILD_PLATFORM "linux")
set (WAMR_BUILD_TARGET "X86_64")
set (WAMR_BUILD_INTERP 1)
set (WAMR_BUILD_FAST_INTERP 1)
set (WAMR_BUILD_AOT 1)
set (WAMR_BUILD_LIBC_BUILTIN 1)
set (WAMR_BUILD_LIBC_WASI 1)
set (WAMR_BUILD_SIMD 1)
set (WAMR_ROOT_DIR path/to/wamr/root)

include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})

# include bh_read_file.h
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)

add_executable (your_project main.c ${UNCOMMON_SHARED_SOURCE})

target_link_libraries (your_project vmlib -lm)

Examples can be found in CMakeLists.txt of linux platformarrow-up-right and other platformsarrow-up-right. The available features to configure can be found in Build WAMR vmcore.

Developer can also use Makefile to embed WAMR, by defining macros and including directories, and adding the source files, examples can be found in makefile of alios-things platformarrow-up-right and makefile of nuttx platformarrow-up-right.

The runtime initialization

The wasm_runtime_init() uses the default memory allocator os_malloc/os_free function from the core/shared/platformarrow-up-right for the runtime memory management.

WAMR supports to restrict its all memory allocations in a raw buffer. It ensures the dynamic memories used by the WASM applications won't harm the system availability, which is extremely important for embedded systems. This can be done by using wasm_runtime_full_init(). This function also allows you to configure the native API's for exporting to WASM app, and set the maximum thread number when multi-thread feature is enabled.

Refer to the following sample:

Native calls WASM functions and passes parameters

After a module is instantiated, the runtime embedder can lookup the target WASM function by name, and create execution environment to call the function.

There are several ways to call WASM function:

  1. Function call with parameters in an array of 32 bits elements and size:

The parameters are transferred in an array of 32 bits elements. For parameters that occupy 4 or fewer bytes, each parameter can be a single array element. For parameters in types like double or int64, each parameter will take two array elements. The function return value will be sent back in the first one or two elements of the array according to the value type. See the sample code below:

  1. Function call with results and arguments both in wasm_val_t struct and size:

  1. Function call with variant argument support:

Pass buffer to WASM function

If we need to transfer a buffer to WASM function, we can pass the buffer address through a parameter. Attention: The sandbox will forbid the WASM code to access outside memory, we must allocate the buffer from WASM instance's own memory space and pass the buffer address in instance's space (not the runtime native address).

There are two runtime APIs available for this purpose.

Usage sample:

Pass structured data to WASM function

We can't pass structure data or class objects through the pointer since the memory layout can different in two worlds. The way to do it is serialization. Refer to export_native_api.md for the details.

Execute wasm functions in multiple threads

It isn't safe to use an exec_env object in multiple threads concurrently. To run a multi-threaded application, you basically need a separate exec_env for each threads.

Approaches to manage exec_env objects and threads

WAMR supports two approaches to manage exec_env and threads as described below. While they are not exclusive, you usually only need to use one of them.

Make your WASM application manage threads

You can make your WASM application spawn threads by itself, typically using pthread APIs like pthread_create. See pthread library and pthread implementationsarrow-up-right for more details. In this case, WAMR manages exec_env for the spawned threads.

Make your embedder manage threads

The spawn exec_env and spawn thread APIs are available for the embedder. You can use these APIs to manage the threads. See Thread related embedder APIarrow-up-right for details.

Other notes about threads

  • You can manage the maximum number of threads

  • To share memory among threads, you need to build your WASM application with shared memory

    For example, it can be done with --shared-memory and -pthread.

  • The corresponding threading feature should be enabled while building the runtime

    • WAMR lib-pthread (legacy)

    • wasi-threads

    • wasm_runtime_spawn_exec_env and wasm_runtime_spawn_thread

The deinitialization procedure

Native calling WASM function working flow

WAMR embed diagram

Last updated