mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2026-04-18 18:18:44 +00:00
Add sample usage: how to use pre-built WAMR library in user mode
As an alternative way to compile WAMR directly into the Zephyr app, given a compiled WAMR library, demonstrate how to integrate such a pre-built library into the Zephyr app and use it in user mode.
This commit is contained in:
parent
389d2060df
commit
bc6c044dd4
14
.github/workflows/compilation_on_zephyr.yml
vendored
14
.github/workflows/compilation_on_zephyr.yml
vendored
|
|
@ -127,3 +127,17 @@ jobs:
|
||||||
sleep 5
|
sleep 5
|
||||||
pkill qemu-system-arc
|
pkill qemu-system-arc
|
||||||
working-directory: modules/wasm-micro-runtime
|
working-directory: modules/wasm-micro-runtime
|
||||||
|
|
||||||
|
- name: Build a sample application(user-mode, prebuilt library approach)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
pushd product-mini/platforms/zephyr/user-mode
|
||||||
|
west build . -b qemu_arc/qemu_arc_hs -p always -- -DWAMR_BUILD_TARGET=ARC -DWAMR_USE_PREBUILT_LIB=1
|
||||||
|
popd
|
||||||
|
|
||||||
|
.github/scripts/run_qemu_arc.sh \
|
||||||
|
../../zephyr-sdk \
|
||||||
|
product-mini/platforms/zephyr/user-mode/build/zephyr/zephyr.elf &
|
||||||
|
sleep 5
|
||||||
|
pkill qemu-system-arc
|
||||||
|
working-directory: modules/wasm-micro-runtime
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,31 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
project(wamr_user_mode LANGUAGES C)
|
project(wamr_user_mode LANGUAGES C)
|
||||||
|
|
||||||
# Add the wamr-lib directory
|
# Option: use pre-built library integration path.
|
||||||
|
# The library is still compiled from source under lib-wamr-zephyr/, but instead
|
||||||
|
# of relying on zephyr_library_app_memory() to register the partition, the
|
||||||
|
# resulting .a is imported as a pre-built library and the partition is registered
|
||||||
|
# manually via set_property(). This demonstrates how to integrate a WAMR library
|
||||||
|
# that was built externally (e.g. copied from another build).
|
||||||
|
#
|
||||||
|
# Usage: west build ... -- -DWAMR_USE_PREBUILT_LIB=1
|
||||||
|
option(WAMR_USE_PREBUILT_LIB
|
||||||
|
"Use pre-built library approach for app_smem partition registration" OFF)
|
||||||
|
|
||||||
|
# Always build the library from source, but conditionally skip
|
||||||
|
# zephyr_library_app_memory() inside the subdirectory when using pre-built mode.
|
||||||
add_subdirectory(lib-wamr-zephyr)
|
add_subdirectory(lib-wamr-zephyr)
|
||||||
|
|
||||||
|
if(WAMR_USE_PREBUILT_LIB)
|
||||||
|
# Manually replicate what zephyr_library_app_memory(wamr_partition) does:
|
||||||
|
# tell gen_app_partitions.py to place this library's globals into wamr_partition.
|
||||||
|
set_property(TARGET zephyr_property_target
|
||||||
|
APPEND PROPERTY COMPILE_OPTIONS
|
||||||
|
"-l" "libwamr_lib.a" "wamr_partition")
|
||||||
|
|
||||||
|
message(STATUS "WAMR: using pre-built library approach for partition registration")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Link the wamr library to the app target
|
# Link the wamr library to the app target
|
||||||
target_link_libraries(app PRIVATE wamr_lib)
|
target_link_libraries(app PRIVATE wamr_lib)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,16 +45,148 @@ When creating a Zephyr thread, set the thread option to `K_USER` and the timeout
|
||||||
|
|
||||||
In a user-mode Zephyr thread, the application can only access a restricted partition of memory it granted to. It creates a sandbox for the WAMR runtime to run in, and the WAMR runtime can only access that memory space, meaning that all global variables in the WAMR runtime and both runtime and wasm app heap memory will be allocated from it. In this way, an extra layer of security is added to the wasm application on top of the wasm sandbox provided by WAMR.
|
In a user-mode Zephyr thread, the application can only access a restricted partition of memory it granted to. It creates a sandbox for the WAMR runtime to run in, and the WAMR runtime can only access that memory space, meaning that all global variables in the WAMR runtime and both runtime and wasm app heap memory will be allocated from it. In this way, an extra layer of security is added to the wasm application on top of the wasm sandbox provided by WAMR.
|
||||||
|
|
||||||
|
### Using a pre-built WAMR library in user mode
|
||||||
|
|
||||||
|
If the WAMR library is pre-built as a static archive (`.a` file) rather than
|
||||||
|
compiled inline via `add_subdirectory`, the library's global variables still
|
||||||
|
need to be placed into the `app_smem` section so they are accessible from the
|
||||||
|
user-mode thread. This is useful when you want to treat the WAMR runtime as a
|
||||||
|
binary dependency copied from an external build.
|
||||||
|
|
||||||
|
#### How `zephyr_library_app_memory` works internally
|
||||||
|
|
||||||
|
`zephyr_library_app_memory(partition)` is a thin wrapper that appends metadata
|
||||||
|
to a CMake target property:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# zephyr/cmake/modules/extensions.cmake
|
||||||
|
set_property(TARGET zephyr_property_target
|
||||||
|
APPEND PROPERTY COMPILE_OPTIONS
|
||||||
|
"-l" <library_filename> "<partition_name>")
|
||||||
|
```
|
||||||
|
|
||||||
|
Zephyr's build system passes this metadata as `-l libname.a partition` arguments
|
||||||
|
to `gen_app_partitions.py`, which generates a linker script fragment with
|
||||||
|
wildcard patterns that collect the library's `.data` and `.bss` sections into
|
||||||
|
the named partition:
|
||||||
|
|
||||||
|
```ld
|
||||||
|
"*libwamr_lib.a:*"(.data .data.* .sdata .sdata.*)
|
||||||
|
"*libwamr_lib.a:*"(.bss .bss.* .sbss .sbss.* COMMON COMMON.*)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using the built-in `WAMR_USE_PREBUILT_LIB` option
|
||||||
|
|
||||||
|
This sample's CMakeLists.txt supports a `WAMR_USE_PREBUILT_LIB` option. When
|
||||||
|
enabled, the library is still compiled from source under `lib-wamr-zephyr/`,
|
||||||
|
but partition registration bypasses `zephyr_library_app_memory()` and uses the
|
||||||
|
manual `set_property()` approach instead. This demonstrates the same integration
|
||||||
|
path you would use with an externally built `.a` file.
|
||||||
|
|
||||||
|
Build from source with `zephyr_library_app_memory` (default):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
west build -b qemu_x86 . -p always
|
||||||
|
```
|
||||||
|
|
||||||
|
Build from source with pre-built library partition registration:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
west build -b qemu_x86 . -p always -- -DWAMR_USE_PREBUILT_LIB=1
|
||||||
|
```
|
||||||
|
|
||||||
|
The application code (`main.c`) is unchanged in both cases — define the
|
||||||
|
partition with `K_APPMEM_PARTITION_DEFINE(wamr_partition)`, set up the memory
|
||||||
|
domain, and create a user-mode thread as usual.
|
||||||
|
|
||||||
|
#### Applying this to your own project
|
||||||
|
|
||||||
|
To use a pre-built WAMR library in a standalone Zephyr application, add the
|
||||||
|
following to your CMakeLists.txt:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# Import the pre-built library
|
||||||
|
add_library(wamr_lib STATIC IMPORTED GLOBAL)
|
||||||
|
set_target_properties(wamr_lib PROPERTIES
|
||||||
|
IMPORTED_LOCATION /path/to/libwamr_lib.a
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tell gen_app_partitions.py to place this library's globals into wamr_partition.
|
||||||
|
# This replicates what zephyr_library_app_memory(wamr_partition) does for
|
||||||
|
# libraries built through zephyr_library_named().
|
||||||
|
set_property(TARGET zephyr_property_target
|
||||||
|
APPEND PROPERTY COMPILE_OPTIONS
|
||||||
|
"-l" "libwamr_lib.a" "wamr_partition")
|
||||||
|
|
||||||
|
# Link it to the app
|
||||||
|
target_link_libraries(app PRIVATE wamr_lib)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Notes
|
||||||
|
|
||||||
|
- The library filename in the `-l` argument must match the archive filename
|
||||||
|
that the linker sees (e.g. `libwamr_lib.a`).
|
||||||
|
- The pre-built library must be compiled with the same Zephyr toolchain and
|
||||||
|
flags (architecture, sysroot, etc.) as the application.
|
||||||
|
- For Zephyr 4.x, if building the library inline via `add_subdirectory`, add
|
||||||
|
`add_dependencies(wamr_lib zephyr_generated_headers)` to avoid build race
|
||||||
|
conditions with generated headers like `heap_constants.h`.
|
||||||
|
|
||||||
### Example Targets
|
### Example Targets
|
||||||
|
|
||||||
x86_64 QEMU (x86_64) is a 64-bit x86 target for emulating the x86_64 platform.
|
#### qemu_x86 (Zephyr 4.x with Zephyr SDK 1.0+)
|
||||||
|
|
||||||
|
Build for the `qemu_x86` board (32-bit x86, the default `WAMR_BUILD_TARGET`):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
west build -b qemu_x86 . -p always
|
||||||
|
```
|
||||||
|
|
||||||
|
To use the pre-built library approach instead:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
west build -b qemu_x86 . -p always -- -DWAMR_USE_PREBUILT_LIB=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Run on QEMU using `west`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
west build -t run
|
||||||
|
```
|
||||||
|
|
||||||
|
> Press `CTRL+a, x` to exit QEMU.
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
|
||||||
|
```
|
||||||
|
*** Booting Zephyr OS build v4.4.0-rc2 ***
|
||||||
|
wamr_partition start addr: 1257472, size: 45056
|
||||||
|
User mode thread: start
|
||||||
|
Hello world!
|
||||||
|
buf ptr: 0x1458
|
||||||
|
buf: 1234
|
||||||
|
User mode thread: elapsed 10
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: The boot message order may vary. `wamr_partition` size should be around
|
||||||
|
> 45056 bytes (40 KB global heap + other library globals).
|
||||||
|
|
||||||
|
#### qemu_x86_tiny (older Zephyr / manual QEMU)
|
||||||
|
|
||||||
|
Build for the `qemu_x86_tiny` board:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
west build -b qemu_x86_tiny . -p always -- -DWAMR_BUILD_TARGET=X86_32
|
west build -b qemu_x86_tiny . -p always -- -DWAMR_BUILD_TARGET=X86_32
|
||||||
```
|
```
|
||||||
|
|
||||||
Use qemu to run the image.
|
Run QEMU manually:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
qemu-system-i386 -m 32 -cpu qemu32,+nx,+pae -machine pc -device isa-debug-exit,iobase=0xf4,iosize=0x04 -no-reboot -nographic -net none -pidfile qemu.pid -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -icount shift=5,align=off,sleep=off -rtc clock=vm -kernel ./build/zephyr/zephyr.elf
|
qemu-system-i386 -m 32 -cpu qemu32,+nx,+pae -machine pc \
|
||||||
|
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
|
||||||
|
-no-reboot -nographic -net none -pidfile qemu.pid \
|
||||||
|
-chardev stdio,id=con,mux=on -serial chardev:con \
|
||||||
|
-mon chardev=con,mode=readline \
|
||||||
|
-icount shift=5,align=off,sleep=off -rtc clock=vm \
|
||||||
|
-kernel ./build/zephyr/zephyr.elf
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,8 @@ endif()
|
||||||
# Specify the memory partition where all globals(including the WAMR global heap buffer)
|
# Specify the memory partition where all globals(including the WAMR global heap buffer)
|
||||||
# in the library should be placed. This partition will be defined in the app source code
|
# in the library should be placed. This partition will be defined in the app source code
|
||||||
# and added to the use-mode thread that uses the WAMR library.
|
# and added to the use-mode thread that uses the WAMR library.
|
||||||
|
# When WAMR_USE_PREBUILT_LIB is set, the parent CMakeLists.txt handles partition
|
||||||
|
# registration via set_property() instead, demonstrating the pre-built library approach.
|
||||||
|
if (NOT WAMR_USE_PREBUILT_LIB)
|
||||||
zephyr_library_app_memory (wamr_partition)
|
zephyr_library_app_memory (wamr_partition)
|
||||||
|
endif ()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user