For a quick and simple 'hello world' experience, you can use docker with
$ make docker
which will create two images:
unit:wasm
(based on the Docker Official image, with Wasm Module)unit:demo-wasm
(based on the Wasm image, with demo application)
Manual build instructions below.
You will need:
- Modern Linux platform (might work on others, not yet tested).
- Ability to build Unit from source. If you haven't done this before, please first run through the Building From Source how-to guide.
- Additional build tools (required for the demo Wasm Module)
- clang
- llvm
- lld
-
Do a test build of Unit from source (see docs) with this PR/patch applied. The following steps assume you're starting in the
unit
directory and used./configure --prefix=$PWD/build
. -
Download and extract the Wasmtime C API (newer versions may or may not work). Notice that we use
$(arch)
to substitute-in the appropriate CPU architecture. This works for x86_64 and aarch64 (ARM) platforms.
wget -O- https://github.com/bytecodealliance/wasmtime/releases/download/v11.0.0/wasmtime-v11.0.0-$(arch)-linux-c-api.tar.xz | tar Jxfv -
- Configure the Wasm Language Module for Unit
./configure wasm --include-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/include \
--lib-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/lib --rpath
- Build the Wasm Language Module
make
- Test that unitd Can Load the Language Module
Run unitd
in the foreground (attached to the console) to check that Unit
can discover and load the wasm
Language Module at startup. You should see
console output similar to this:
$ $PWD/build/sbin/unitd --no-daemon --log /dev/stderr
2023/06/15 11:29:31 [info] 1#1 unit 1.31.0 started
2023/06/15 11:29:31 [info] 43#43 discovery started
2023/06/15 11:29:31 [notice] 43#43 module: wasm 0.1 "/path/to/modules/wasm.unit.so"
From a suitable directory...
Clone the unit-wasm repository
$ git clone https://github.com/nginx/unit-wasm.git
Download and extract the wasi-sysroot from the WASI SDK
wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar zxfv -
Next Compile the C demo Wasm Modules to .wasm
files. This requires at least
the following; make and clang, llvm, compiler-rt, and lld from LLVM 9.0+
$ cd unit-wasm
$ make WASI_SYSROOT=../wasi-sysroot examples
If the above fails like
wasm-ld: error: cannot open /usr/lib/llvm-11/lib/clang/11.0.1/lib/wasi/libclang_rt.builtins-wasm32.a: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Then you need to download the wasm32 clang runtime and copy it into the location mentioned in the error message.
E.g
In the above case we would untar libclang_rt.builtins-wasm32-wasi-20.0.tar.gz into /usr/lib/llvm-11/lib/clang/11.0.1/
On Fedora this would be more like /usr/lib64/clang/16/
Adjust the tar '-C ...' option accordingly below...
wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | sudo tar -xvzf - -C /usr/lib/llvm-11/lib/clang/11.0.1
With recent enough versions of Clang (that support the -print-runtime-dir option) you can use the following command (as root)
wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
Then try again...
If everything built OK then you should have the following two WASM modules
examples/c/luw-echo-request.wasm
examples/c/luw-upload-reflector.wasm
{
"listeners": {
"[::1]:8080": {
"pass": "routes"
}
},
"settings": {
"http": {
"max_body_size": 1073741824
}
},
"routes": [
{
"match": {
"uri": "/echo*"
},
"action": {
"pass": "applications/luw-echo-request"
}
},
{
"match": {
"uri": "/upload*"
},
"action": {
"pass": "applications/luw-upload-reflector"
}
}
],
"applications": {
"luw-echo-request": {
"type": "wasm",
"module": "/path/to/unit-wasm/examples/c/luw-echo-request.wasm",
"request_handler": "luw_request_handler",
"malloc_handler": "luw_malloc_handler",
"free_handler": "luw_free_handler",
"module_init_handler": "luw_module_init_handler",
"module_end_handler": "luw_module_end_handler",
"access": {
"filesystem": [
"/tmp",
"/foo/bar"
]
}
},
"luw-upload-reflector": {
"type": "wasm",
"module": "/path/to/unit-wasm/examples/c/luw-upload-reflector.wasm",
"request_handler": "luw_request_handler",
"malloc_handler": "luw_malloc_handler",
"free_handler": "luw_free_handler",
"request_end_handler": "luw_request_end_handler",
"response_end_handler": "luw_response_end_handler"
}
}
}
Apply the above configuration to the /config URI of Unit's Control API. With the JSON in a file, you can use the CLI to apply it.
cat conf.json | tools/unitc /config
The following messages should then appear in the Unit log file (or console if
running with --no-daemon
).
2023/07/26 13:28:14 [info] 182585#182585 "luw-echo-request" prototype started
2023/07/26 13:28:14 [info] 182590#182590 "luw-echo-request" application started
2023/07/26 13:28:14 [info] 182591#182591 "luw-upload-reflector" prototype started
2023/07/26 13:28:14 [info] 182596#182596 "luw-upload-reflector" application started
Now make a request to the demo application.
curl http://localhost:8080/echo