forked from wasm3/wasm3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add C++ wrappers, simplify linking external functions (wasm3#71)
* add a set of C++ wrappers, simplify linking external functions * m3_config_platforms.h: don't define min/max for C++
- Loading branch information
Showing
11 changed files
with
655 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build | ||
cmake-build-debug | ||
wasm/test_prog.wasm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
cmake_minimum_required(VERSION 3.9) | ||
project(wasm3_cpp_example) | ||
|
||
set(target ${CMAKE_PROJECT_NAME}) | ||
|
||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../../source ${CMAKE_BINARY_DIR}/m3) | ||
|
||
add_executable(${target} main.cpp) | ||
target_link_libraries(${target} PRIVATE m3) | ||
|
||
add_subdirectory(wasm3_cpp) | ||
target_link_libraries(${target} PRIVATE wasm3_cpp) | ||
|
||
target_compile_options(${target} PUBLIC -g) | ||
target_compile_options(m3 PUBLIC -g) | ||
target_compile_options(m3 PRIVATE -Dd_m3LogOutput=0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
## C++ wrapper | ||
|
||
This example shows how to embed WASM3 into a C++ application. It uses a header-only library, `wasm3_cpp.h`, provided in `wasm3_cpp` subdirectory. Like WASM3 itself, this library can be included into CMake projects using `add_subdirectory` function. | ||
|
||
The main code of the example in `main.cpp` initializes WASM3, loads a WebAssembly module, links two external functions to the module, and executes two functions defined in WebAssembly. | ||
|
||
The WebAssembly module source code is inside `wasm` subdirectory. | ||
|
||
### `wasm3_cpp.h` reference | ||
|
||
All the classes are located in `wasm3` namespace. | ||
|
||
#### Class `environment` | ||
|
||
`environment::environment()` — create a new WASM3 environment. Runtimes, modules are owned by an environment. | ||
|
||
`runtime environment::new_runtime(size_t stack_size_bytes)` — create new runtime inside the environment. | ||
|
||
`module environment::parse_module(std::istream &in)` or `module environment::parse_module(const uint8_t *data, size_t size)` — parse a WASM binary module. | ||
|
||
#### Class `runtime` | ||
|
||
`runtime` objects are created using `environment::new_runtime` method, see above. | ||
|
||
`void runtime::load(module &m)` — load a parsed module into the runtime. | ||
|
||
`function runtime::find_function(const char *name)` — find a function defined in one of the loaded modules, by name. Raises a `wasm3::error` exception if the function is not found. | ||
|
||
#### Class `module` | ||
|
||
`module` objects are created by `environment::parse_module`. Parsed modules can be loaded into a `runtime` object. One module can only be loaded into one runtime. | ||
|
||
Before loading a module, you may need to link some external functions to it: | ||
|
||
`template <auto Fn> void module::link<Fn>(const char *mod, const char *func)` — link a function `Fn` to module named `mod` under the name `func`. To link to any module, use `mod="*"`. | ||
|
||
`Fn` has to be either a non-member function or a static member function. At the moment WASM3 doesn't pass any context along with the external function call, so binding non-static member functions is not possible. | ||
|
||
Currently, the following types of arguments can be passed to functions linked this way: | ||
|
||
* int32_t | ||
* int64_t | ||
* float | ||
* double | ||
* const/non-const pointers | ||
|
||
Automatic conversion of other integral types may be implemented in the future. | ||
|
||
If the module doesn't reference an imported function named `func`, an exception is thrown. To link a function "optionally", i.e. without throwing an exception if the function is not imported, use `module::link_optional` instead. | ||
|
||
#### Class `function` | ||
|
||
`function` object can be obtained from a `runtime`, looking up the function by name. Function objects are used to call WebAssembly functions. | ||
|
||
`template <typename Ret> Ret function::call()` — call a WebAssembly function which doesn't take any arguments. The return value of the function is automatically converted to the type `Ret`. Note that you need to specify the return type when using this template function, and the type has to match the type returned by the WebAssembly function. | ||
|
||
`template <typename Ret, typename ...Args> Ret function::call(Args...)` — same as above, but also allows passing arguments to the WebAssembly function. Note that due to a limitation of WASM3 API, the arguments are first converted to strings, and then passed to WASM3. The strings are then converted to the appropriate types based on the WebAssembly function signature. This conversion is limited to the following types: `int32_t`, `int64_t`, `float`, `double`. | ||
|
||
`template <typename Ret, typename ...Args> Ret function::call_argv(Args...)` — same as above, except that this function takes arguments as C strings (`const char*`). | ||
|
||
### Building and running | ||
|
||
This directory is a CMake project, and can be built as follows: | ||
|
||
```bash | ||
mkdir build | ||
cd build | ||
cmake .. | ||
cmake --build . | ||
``` | ||
|
||
Then run the example: | ||
|
||
```bash | ||
./wasm3_cpp_example | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#include <cstdio> | ||
#include "wasm3_cpp.h" | ||
#include "wasm/test_prog.wasm.h" | ||
|
||
int sum(int a, int b) | ||
{ | ||
return a + b; | ||
} | ||
|
||
void ext_memcpy(void* dst, const void* arg, int64_t size) | ||
{ | ||
memcpy(dst, arg, (size_t) size); | ||
} | ||
|
||
int main(void) | ||
{ | ||
std::cout << "Loading WebAssembly..." << std::endl; | ||
|
||
try { | ||
wasm3::environment env; | ||
wasm3::runtime runtime = env.new_runtime(1024); | ||
wasm3::module mod = env.parse_module(test_prog_wasm, test_prog_wasm_len); | ||
runtime.load(mod); | ||
mod.link<sum>("*", "sum"); | ||
mod.link<ext_memcpy>("*", "ext_memcpy"); | ||
{ | ||
wasm3::function test_fn = runtime.find_function("test"); | ||
auto res = test_fn.call<int>(20, 10); | ||
std::cout << "result: " << res << std::endl; | ||
} | ||
{ | ||
wasm3::function memcpy_test_fn = runtime.find_function("test_memcpy"); | ||
auto res = memcpy_test_fn.call<int64_t>(); | ||
std::cout << "result: 0x" << std::hex << res << std::dec << std::endl; | ||
} | ||
} | ||
|
||
catch(wasm3::error &e) { | ||
std::cerr << "WASM3 error: " << e.what() << std::endl; | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
NAME=test_prog | ||
SRC=$(NAME).c | ||
WASM=$(NAME).wasm | ||
HEADER=$(NAME).wasm.h | ||
EMCC_FLAGS=-s STANDALONE_WASM -s ERROR_ON_UNDEFINED_SYMBOLS=0 -O3 | ||
|
||
all: $(HEADER) | ||
|
||
clean: | ||
rm -f $(HEADER) $(WASM) | ||
|
||
.PHONY: all clean | ||
|
||
$(WASM): $(SRC) | ||
emcc $< -o $@ $(EMCC_FLAGS) | ||
|
||
$(HEADER): $(WASM) | ||
xxd -i $< >$@ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#include <stddef.h> | ||
#include <stdint.h> | ||
|
||
extern int sum(int, int); | ||
extern int ext_memcpy(void*, const void*, size_t); | ||
|
||
#define WASM_EXPORT __attribute__((used)) __attribute__((visibility ("default"))) | ||
|
||
int WASM_EXPORT test(int32_t arg1, int32_t arg2) | ||
{ | ||
int x = arg1 + arg2; | ||
int y = arg1 - arg2; | ||
return sum(x, y) / 2; | ||
} | ||
|
||
int64_t WASM_EXPORT test_memcpy(void) | ||
{ | ||
int64_t x = 0; | ||
int32_t low = 0x01234567; | ||
int32_t high = 0x89abcdef; | ||
ext_memcpy(&x, &low, 4); | ||
ext_memcpy(((uint8_t*)&x) + 4, &high, 4); | ||
return x; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
unsigned char test_prog_wasm[] = { | ||
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x15, 0x04, 0x60, | ||
0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x00, 0x60, 0x03, 0x7f, 0x7f, | ||
0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x7e, 0x02, 0x1c, 0x02, 0x03, 0x65, | ||
0x6e, 0x76, 0x0a, 0x65, 0x78, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x63, 0x70, | ||
0x79, 0x00, 0x02, 0x03, 0x65, 0x6e, 0x76, 0x03, 0x73, 0x75, 0x6d, 0x00, | ||
0x00, 0x03, 0x04, 0x03, 0x01, 0x03, 0x00, 0x05, 0x06, 0x01, 0x01, 0x80, | ||
0x02, 0x80, 0x02, 0x06, 0x09, 0x01, 0x7f, 0x01, 0x41, 0x80, 0x8c, 0xc0, | ||
0x02, 0x0b, 0x07, 0x28, 0x04, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, | ||
0x02, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x04, 0x0b, 0x74, 0x65, | ||
0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x03, 0x06, | ||
0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x02, 0x0a, 0x71, 0x03, 0x03, | ||
0x00, 0x01, 0x0b, 0x59, 0x02, 0x01, 0x7f, 0x01, 0x7e, 0x23, 0x00, 0x41, | ||
0x10, 0x6b, 0x22, 0x00, 0x24, 0x00, 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, | ||
0x08, 0x20, 0x00, 0x41, 0xe7, 0x8a, 0x8d, 0x09, 0x36, 0x02, 0x04, 0x20, | ||
0x00, 0x41, 0xef, 0x9b, 0xaf, 0xcd, 0x78, 0x36, 0x02, 0x00, 0x20, 0x00, | ||
0x41, 0x08, 0x6a, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x41, 0x04, 0x10, 0x00, | ||
0x1a, 0x20, 0x00, 0x41, 0x08, 0x6a, 0x41, 0x04, 0x72, 0x20, 0x00, 0x41, | ||
0x04, 0x10, 0x00, 0x1a, 0x20, 0x00, 0x29, 0x03, 0x08, 0x21, 0x01, 0x20, | ||
0x00, 0x41, 0x10, 0x6a, 0x24, 0x00, 0x20, 0x01, 0x0b, 0x11, 0x00, 0x20, | ||
0x00, 0x20, 0x01, 0x6a, 0x20, 0x00, 0x20, 0x01, 0x6b, 0x10, 0x01, 0x41, | ||
0x02, 0x6d, 0x0b, 0x0b, 0x0a, 0x01, 0x00, 0x41, 0x80, 0x0c, 0x0b, 0x03, | ||
0xa0, 0x06, 0x50 | ||
}; | ||
unsigned int test_prog_wasm_len = 255; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
cmake_minimum_required(VERSION 3.5) | ||
add_library(wasm3_cpp INTERFACE) | ||
target_include_directories(wasm3_cpp INTERFACE include) | ||
target_compile_features(wasm3_cpp INTERFACE cxx_std_17) |
Oops, something went wrong.