Skip to content

Commit 82f9508

Browse files
Add sample usage: how to use pre-built WAMR library in user mode (#4908)
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.
1 parent 0b3001d commit 82f9508

File tree

4 files changed

+177
-5
lines changed

4 files changed

+177
-5
lines changed

.github/workflows/compilation_on_zephyr.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,17 @@ jobs:
127127
sleep 5
128128
pkill qemu-system-arc
129129
working-directory: modules/wasm-micro-runtime
130+
131+
- name: Build a sample application(user-mode, prebuilt library approach)
132+
shell: bash
133+
run: |
134+
pushd product-mini/platforms/zephyr/user-mode
135+
west build . -b qemu_arc/qemu_arc_hs -p always -- -DWAMR_BUILD_TARGET=ARC -DWAMR_USE_PREBUILT_LIB=1
136+
popd
137+
138+
.github/scripts/run_qemu_arc.sh \
139+
../../zephyr-sdk \
140+
product-mini/platforms/zephyr/user-mode/build/zephyr/zephyr.elf &
141+
sleep 5
142+
pkill qemu-system-arc
143+
working-directory: modules/wasm-micro-runtime

product-mini/platforms/zephyr/user-mode/CMakeLists.txt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,31 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
66

77
project(wamr_user_mode LANGUAGES C)
88

9-
# Add the wamr-lib directory
9+
# Option: use pre-built library integration path.
10+
# The library is still compiled from source under lib-wamr-zephyr/, but instead
11+
# of relying on zephyr_library_app_memory() to register the partition, the
12+
# resulting .a is imported as a pre-built library and the partition is registered
13+
# manually via set_property(). This demonstrates how to integrate a WAMR library
14+
# that was built externally (e.g. copied from another build).
15+
#
16+
# Usage: west build ... -- -DWAMR_USE_PREBUILT_LIB=1
17+
option(WAMR_USE_PREBUILT_LIB
18+
"Use pre-built library approach for app_smem partition registration" OFF)
19+
20+
# Always build the library from source, but conditionally skip
21+
# zephyr_library_app_memory() inside the subdirectory when using pre-built mode.
1022
add_subdirectory(lib-wamr-zephyr)
1123

24+
if(WAMR_USE_PREBUILT_LIB)
25+
# Manually replicate what zephyr_library_app_memory(wamr_partition) does:
26+
# tell gen_app_partitions.py to place this library's globals into wamr_partition.
27+
set_property(TARGET zephyr_property_target
28+
APPEND PROPERTY COMPILE_OPTIONS
29+
"-l" "libwamr_lib.a" "wamr_partition")
30+
31+
message(STATUS "WAMR: using pre-built library approach for partition registration")
32+
endif()
33+
1234
# Link the wamr library to the app target
1335
target_link_libraries(app PRIVATE wamr_lib)
1436

product-mini/platforms/zephyr/user-mode/README.md

Lines changed: 135 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,148 @@ When creating a Zephyr thread, set the thread option to `K_USER` and the timeout
4545
4646
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.
4747
48+
### Using a pre-built WAMR library in user mode
49+
50+
If the WAMR library is pre-built as a static archive (`.a` file) rather than
51+
compiled inline via `add_subdirectory`, the library's global variables still
52+
need to be placed into the `app_smem` section so they are accessible from the
53+
user-mode thread. This is useful when you want to treat the WAMR runtime as a
54+
binary dependency copied from an external build.
55+
56+
#### How `zephyr_library_app_memory` works internally
57+
58+
`zephyr_library_app_memory(partition)` is a thin wrapper that appends metadata
59+
to a CMake target property:
60+
61+
```cmake
62+
# zephyr/cmake/modules/extensions.cmake
63+
set_property(TARGET zephyr_property_target
64+
APPEND PROPERTY COMPILE_OPTIONS
65+
"-l" <library_filename> "<partition_name>")
66+
```
67+
68+
Zephyr's build system passes this metadata as `-l libname.a partition` arguments
69+
to `gen_app_partitions.py`, which generates a linker script fragment with
70+
wildcard patterns that collect the library's `.data` and `.bss` sections into
71+
the named partition:
72+
73+
```ld
74+
"*libwamr_lib.a:*"(.data .data.* .sdata .sdata.*)
75+
"*libwamr_lib.a:*"(.bss .bss.* .sbss .sbss.* COMMON COMMON.*)
76+
```
77+
78+
#### Using the built-in `WAMR_USE_PREBUILT_LIB` option
79+
80+
This sample's CMakeLists.txt supports a `WAMR_USE_PREBUILT_LIB` option. When
81+
enabled, the library is still compiled from source under `lib-wamr-zephyr/`,
82+
but partition registration bypasses `zephyr_library_app_memory()` and uses the
83+
manual `set_property()` approach instead. This demonstrates the same integration
84+
path you would use with an externally built `.a` file.
85+
86+
Build from source with `zephyr_library_app_memory` (default):
87+
88+
```shell
89+
west build -b qemu_x86 . -p always
90+
```
91+
92+
Build from source with pre-built library partition registration:
93+
94+
```shell
95+
west build -b qemu_x86 . -p always -- -DWAMR_USE_PREBUILT_LIB=1
96+
```
97+
98+
The application code (`main.c`) is unchanged in both cases — define the
99+
partition with `K_APPMEM_PARTITION_DEFINE(wamr_partition)`, set up the memory
100+
domain, and create a user-mode thread as usual.
101+
102+
#### Applying this to your own project
103+
104+
To use a pre-built WAMR library in a standalone Zephyr application, add the
105+
following to your CMakeLists.txt:
106+
107+
```cmake
108+
# Import the pre-built library
109+
add_library(wamr_lib STATIC IMPORTED GLOBAL)
110+
set_target_properties(wamr_lib PROPERTIES
111+
IMPORTED_LOCATION /path/to/libwamr_lib.a
112+
)
113+
114+
# Tell gen_app_partitions.py to place this library's globals into wamr_partition.
115+
# This replicates what zephyr_library_app_memory(wamr_partition) does for
116+
# libraries built through zephyr_library_named().
117+
set_property(TARGET zephyr_property_target
118+
APPEND PROPERTY COMPILE_OPTIONS
119+
"-l" "libwamr_lib.a" "wamr_partition")
120+
121+
# Link it to the app
122+
target_link_libraries(app PRIVATE wamr_lib)
123+
```
124+
125+
#### Notes
126+
127+
- The library filename in the `-l` argument must match the archive filename
128+
that the linker sees (e.g. `libwamr_lib.a`).
129+
- The pre-built library must be compiled with the same Zephyr toolchain and
130+
flags (architecture, sysroot, etc.) as the application.
131+
- For Zephyr 4.x, if building the library inline via `add_subdirectory`, add
132+
`add_dependencies(wamr_lib zephyr_generated_headers)` to avoid build race
133+
conditions with generated headers like `heap_constants.h`.
134+
48135
### Example Targets
49136

50-
x86_64 QEMU (x86_64) is a 64-bit x86 target for emulating the x86_64 platform.
137+
#### qemu_x86 (Zephyr 4.x with Zephyr SDK 1.0+)
138+
139+
Build for the `qemu_x86` board (32-bit x86, the default `WAMR_BUILD_TARGET`):
140+
141+
```shell
142+
west build -b qemu_x86 . -p always
143+
```
144+
145+
To use the pre-built library approach instead:
146+
147+
```shell
148+
west build -b qemu_x86 . -p always -- -DWAMR_USE_PREBUILT_LIB=1
149+
```
150+
151+
Run on QEMU using `west`:
152+
153+
```shell
154+
west build -t run
155+
```
156+
157+
> Press `CTRL+a, x` to exit QEMU.
158+
159+
Expected output:
160+
161+
```
162+
*** Booting Zephyr OS build v4.4.0-rc2 ***
163+
wamr_partition start addr: 1257472, size: 45056
164+
User mode thread: start
165+
Hello world!
166+
buf ptr: 0x1458
167+
buf: 1234
168+
User mode thread: elapsed 10
169+
```
170+
171+
> Note: The boot message order may vary. `wamr_partition` size should be around
172+
> 45056 bytes (40 KB global heap + other library globals).
173+
174+
#### qemu_x86_tiny (older Zephyr / manual QEMU)
175+
176+
Build for the `qemu_x86_tiny` board:
51177

52178
```shell
53179
west build -b qemu_x86_tiny . -p always -- -DWAMR_BUILD_TARGET=X86_32
54180
```
55181

56-
Use qemu to run the image.
182+
Run QEMU manually:
57183

58184
```shell
59-
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
185+
qemu-system-i386 -m 32 -cpu qemu32,+nx,+pae -machine pc \
186+
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
187+
-no-reboot -nographic -net none -pidfile qemu.pid \
188+
-chardev stdio,id=con,mux=on -serial chardev:con \
189+
-mon chardev=con,mode=readline \
190+
-icount shift=5,align=off,sleep=off -rtc clock=vm \
191+
-kernel ./build/zephyr/zephyr.elf
60192
```

product-mini/platforms/zephyr/user-mode/lib-wamr-zephyr/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,8 @@ endif()
6767
# Specify the memory partition where all globals(including the WAMR global heap buffer)
6868
# in the library should be placed. This partition will be defined in the app source code
6969
# and added to the use-mode thread that uses the WAMR library.
70-
zephyr_library_app_memory (wamr_partition)
70+
# When WAMR_USE_PREBUILT_LIB is set, the parent CMakeLists.txt handles partition
71+
# registration via set_property() instead, demonstrating the pre-built library approach.
72+
if (NOT WAMR_USE_PREBUILT_LIB)
73+
zephyr_library_app_memory (wamr_partition)
74+
endif ()

0 commit comments

Comments
 (0)