From 9eb3ed6b15ad7450a249b4b59696db2568080cfa Mon Sep 17 00:00:00 2001 From: "liang.he" Date: Thu, 13 Jan 2022 16:43:05 +0800 Subject: [PATCH] Update documents about building wasm app with wasi-sdk (#955) Checked with grammarly --- doc/build_wasm_app.md | 87 ++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index eee1711f..cff4afd2 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -2,18 +2,38 @@ # Prepare WASM building environments -For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). +For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also, we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). To install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. -The offical *wasi-sdk release* doesn't fully support *latest 128-bit SIMD spec* yet. WARM provides a script in [build-wasi-sdk](../test-tools/build-wasi-sdk/) to generate -another wasi-sdk with *llvm-13* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the offical release. +The official *wasi-sdk release* doesn't fully support *latest 128-bit SIMD spec* yet. WARM provides a script in [build-wasi-sdk](../test-tools/build-wasi-sdk/) to generate +another wasi-sdk with *llvm-13* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the official release. And [sample workloads](../samples/workload) are using the self-compiled wasi-sdk. For [AssemblyScript](https://github.com/AssemblyScript/assemblyscript), please refer to [AssemblyScript quick start](https://www.assemblyscript.org/quick-start.html) and [AssemblyScript compiler](https://www.assemblyscript.org/compiler.html#command-line-options) for how to install `asc` compiler and build WASM applications. -For Rust, please firstly ref to [Install Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) to install cargo, rustc and rustup, by default they are installed under ~/.cargo/bin, and then run `rustup target add wasm32-wasi` to install wasm32-wasi target for Rust toolchain. To build WASM applications, we can run `cargo build --target wasm32-wasi`, the output files are under `target/wasm32-wasi`. +For Rust, please refer to [Install Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) to install *cargo*, *rustc* and *rustup*. By default they are under ~/.cargo/bin. + +And then run such a command to install `wasm32-wasi` target. + +``` bash +$ rustup target add wasm32-wasi +``` + +To build WASM applications, run + +``` bash +$ cargo build --target wasm32-wasi +``` + +The output files are under `target/wasm32-wasi`. + +To build a release version + +``` bash +$ cargo build --release --target wasm32-wasi +``` Build WASM applications with wasi-sdk @@ -55,9 +75,9 @@ To build the source file to WASM bytecode, we can input the following command: ## 1. wasi-sdk options -There are some useful options which can be specified to build the source code (for more link options, please run `/opt/wasi-sdk/bin/wasm-ld --help`): +There are some useful options that are used to compile C/C++ to Wasm (for a full introduction, please refer to [clang command line argument reference](https://clang.llvm.org/docs/ClangCommandLineReference.html) and [wasm-ld command line argument manual](https://lld.llvm.org/WebAssembly.html)): -- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for cmake to build WAMR with libc-builtin support or libc-wasi support. +- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for CMake to build WAMR with libc-builtin support or libc-wasi support. - **-Wl,--no-entry** Do not output any entry point @@ -69,7 +89,7 @@ There are some useful options which can be specified to build the source code (f - **-Wl,--max-memory=\** Maximum size of the linear memory, which must be a multiple of 65536 -- **-z stack-size=\** The auxiliary stack size, which is an area of linear memory, and must be smaller than initial memory size. +- **-z stack-size=\** The auxiliary stack size, which is an area of linear memory, must be smaller than the initial memory size. - **-Wl,--strip-all** Strip all symbols @@ -81,7 +101,7 @@ There are some useful options which can be specified to build the source code (f - **-pthread** Support POSIX threads in generated code -For example, we can build the wasm app with command: +For example, we can build the wasm app with the command: ``` Bash /opt/wasi-sdk/bin/clang -O3 -nostdlib \ @@ -91,9 +111,9 @@ For example, we can build the wasm app with command: -Wl,--export=__heap_base -Wl,--export=__data_end \ -Wl,--no-entry -Wl,--strip-all -Wl,--allow-undefined ``` -to generate a wasm binary with nostdlib mode, auxiliary stack size is 8192 bytes, initial memory size is 64 KB, main function, heap base global and data end global are exported, no entry function is generated (no _start function is exported), and all symbols are stripped. Note that it is nostdlib mode, so libc-builtin should be enabled by runtime embedder or iwasm (with cmake -DWAMR_BUILD_LIBC_BUILT=1, enabled by iwasm in Linux by default). +to generate a wasm binary with nostdlib mode, the auxiliary stack size is 8192 bytes, initial memory size is 64 KB, main function, heap base global and data end global are exported, no entry function is generated (no _start function is exported), and all symbols are stripped. Note that it is nostdlib mode, so libc-builtin should be enabled by runtime embedder or iwasm (with `cmake -DWAMR_BUILD_LIBC_BUILT=1`, enabled by iwasm in Linux by default). -If we want to build the wasm app with wasi mode, we may build the wasm app with command: +If we want to build the wasm app with wasi mode, we may build the wasm app with the command: ```bash /opt/wasi-sdk/bin/clang -O3 \ @@ -103,7 +123,7 @@ If we want to build the wasm app with wasi mode, we may build the wasm app with -Wl,--strip-all ``` -to generate a wasm binary with wasi mode, auxiliary stack size is 8192 bytes, initial memory size is 64 KB, heap base global and data end global are exported, wasi entry function exported (_start function), and all symbols are stripped. Note that it is wasi mode, so libc-wasi should be enabled by runtime embedder or iwasm (with cmake -DWAMR_BUILD_LIBC_WASI=1, enabled by iwasm in Linux by default), and normally no need to export main function, by default _start function is executed by iwasm. +to generate a wasm binary with wasi mode, the auxiliary stack size is 8192 bytes, initial memory size is 64 KB, heap base global and data end global are exported, wasi entry function exported (_start function), and all symbols are stripped. Note that it is wasi mode, so libc-wasi should be enabled by runtime embedder or iwasm (with `cmake -DWAMR_BUILD_LIBC_WASI=1`, enabled by iwasm in Linux by default), and normally no need to export main function, by default _start function is executed by iwasm. ## 2. How to reduce the footprint? @@ -119,7 +139,7 @@ Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are - reduce auxiliary stack size - The auxiliary stack is an area of linear memory, normally the size is 64 KB by default which might be a little large for embedded devices and actually partly used, we can use `-z stack-size=n` to set its size. + The auxiliary stack is an area of linear memory, normally the size is 64 KB by default which might be a little large for embedded devices and partly used, we can use `-z stack-size=n` to set its size. - use -O3 and -Wl,--strip-all @@ -133,7 +153,7 @@ Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are - decrease block_addr_cache size for classic interpreter - The block_addr_cache is an hash cache to store the else/end addresses for WebAssembly blocks (BLOCK/IF/LOOP) to speed up address lookup. This is only available in classic interpreter. We can set it by define macro `-DBLOCK_ADDR_CACHE_SIZE=n`, e.g. add `add_defintion (-DBLOCK_ADDR_CACHE_SIZE=n)` in CMakeLists.txt, by default it is 64, and total block_addr_cache size is 3072 bytes in 64-bit platform and 1536 bytes in 32-bit platform. + The block_addr_cache is a hash cache to store the else/end addresses for WebAssembly blocks (BLOCK/IF/LOOP) to speed up address lookup. This is only available in the classic interpreter. We can set it by defineing macro `-DBLOCK_ADDR_CACHE_SIZE=n`, e.g. add `add_defintion (-DBLOCK_ADDR_CACHE_SIZE=n)` in CMakeLists.txt, by default it is 64, and the total block_addr_cache size is 3072 bytes in 64-bit platform and 1536 bytes in 32-bit platform. ### (2) Methods to reduce the libc-wasi (without -nostdlib) mode footprint @@ -178,7 +198,7 @@ EMCC_ONLY_FORCED_STDLIBS=1 emcc -O3 -s STANDALONE_WASM=1 \ There are some useful options: -- **EMCC_ONLY_FORCED_STDLIBS=1** whether to link libc library into the output binary or not, similar to `-nostdlib` option of wasi-sdk clang. If specified, then no libc library is linked and the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for cmake to build WAMR with libc-builtin support or libc-wasi support. +- **EMCC_ONLY_FORCED_STDLIBS=1** whether to link libc library into the output binary or not, similar to `-nostdlib` option of wasi-sdk clang. If specified, then no libc library is linked and the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for CMake to build WAMR with libc-builtin support or libc-wasi support. The emsdk's wasi implementation is incomplete, e.g. open a file might just return fail, so it is strongly not recommended to use this mode, especially when there are file io operations in wasm app, please use wasi-sdk instead. @@ -200,32 +220,49 @@ For more options, please ref to /upstream/emscripten/src/settings.js, # Build a project with cmake -If you have complex WASM application project which contains dozens of source files, you can consider using cmake for project building. +If you have a complex WASM application project which contains dozens of source files, you can consider using cmake for project building. You can cross compile your project by using the toolchain provided by WAMR. -We can generate a `CMakeLists.txt` file for `test.c`: +Assume the original `CMakeLists.txt` for `test.c` likes below: ``` cmake cmake_minimum_required (VERSION 3.5) project(hello_world) - -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS},--export=main") add_executable(hello_world test.c) ``` -It is simple to build this project by cmake: +It is easy to use *wasi-sdk* in CMake by setting *CMAKE_TOOLCHAIN_FILE* without any modification on the original *CMakeLists.txt*. -``` Bash -mkdir build && cd build -cmake .. -DCMAKE_TOOLCHAIN_FILE=$WAMR_ROOT/wamr-sdk/app/wamr_toolchain.cmake -make +``` +$ cmake -DWASI_SDK_PREFIX=${WASI_SDK_INSTALLTION_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_INSTALLTION_DIR}/share/cmake/wasi-sdk.cmake + -DCMAKE_SYSROOT= + .. +``` + +`WASI_SDK_INSTALLTION_DIR` is the directory in where you install the *wasi-sdk*. like */opt/wasi-sdk* + +If you prefer WASI, set *CMAKE_SYSROOT* to *wasi-sysroot* + +``` +$ cmake + -DCMAKE_SYSROOT=${WASI_SDK_INSTALLTION_DIR}/share/wasi-sysroot + .. +``` + +If you prefer *WAMR builtin libc*, set *CMAKE_SYSROOT* to *libc-builtin-sysroot* + +> Note: If you have already built a SDK profile + +``` +$ cmake + -DCMAKE_SYSROOT=${WAMR_SOURCE_ROOT}/wamr-sdk/app/libc-builtin-sysroot + .. ``` You will get ```hello_world``` which is the WASM app binary. -> Note: If you have already built a SDK profile, then the **DCMAKE_TOOLCHAIN_FILE** should be changed into `$WAMR_ROOT/wamr-sdk/out/${PROFILE}/app-sdk/wamr_toolchain.cmake` - # Compile WASM to AoT module