XiNGRZ's BLOG

一些唠叨

玩了一把 wasm

最近发现了 wasm-micro-runtime 这么个小玩意,一个超小的 wasm 运行时。随手记录下。

0. 先看全貌

在 wasm-micro-runtime (简称 wamr) 里要把一个程序从源文件一直到跑起来,会经历以下步骤:

1
test.c --[wasi-sdk]-> test.wasm --[wamrc]-> test.aot --[iwasm]-> 跑起来

如你所见,现在我需要 wasi-sdk wasmrc iwasm 这仨玩意儿。

1.环境准备

1.1. 取得 wasi-sdk

现成的。在 https://github.com/WebAssembly/wasi-sdk/releases 找到对应你系统的版本下载解压即可。这里假设你把它解压到了 /opt/wasi-sdk。实际上放哪无所谓。

1.2. 编译 iwasm:wamr 运行时

wamr 官方已经提供了几个不同平台的运行时。我用 macOS,直接有现成的:

1
2
cd product-mini/platforms/darwin
cmake -G Ninja -B build && cmake --build build

你可能发现我的编译命令和官方的不一样…没错,cmake 本身就有 -B--build,大可不必手动 mkdir build && cd make,多麻烦。而且 Ninja 香啊~

跑完,build/iwasm 就是当前平台的运行时。

1.3. 编译 wamrc:AOT 编译器

先编译一遍 LLVM 的一些库,需要的时间比较久。不得不说,原版脚本用的是 GNU Makefiles 是真的慢…所以我又夹带了点私货

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
diff --git a/build-scripts/build_llvm.py b/build-scripts/build_llvm.py
index bc0daf1f..9cd23d51 100755
--- a/build-scripts/build_llvm.py
+++ b/build-scripts/build_llvm.py
@@ -114,11 +114,7 @@ def build_llvm(llvm_dir, platform, backends, projects):
)

CONFIG_CMD = f"cmake {compile_options} ../llvm"
- if "windows" == platform:
- if "mingw" in sysconfig.get_platform().lower():
- CONFIG_CMD += " -G'Unix Makefiles'"
- else:
- CONFIG_CMD += " -A x64"
+ CONFIG_CMD += " -G Ninja"
print(f"{CONFIG_CMD}")
subprocess.check_call(shlex.split(CONFIG_CMD), cwd=build_dir)

跑它:

1
python build-scripts/build_llvm.py --platform darwin --arch ARM X86

然后编译 wamrc。这里我同样用 Ninja,比官方的命令快多了。

1
2
cd wamr-compiler
cmake -G Ninja -B build && cmake --build build

跑完,同样得到了 build/wamrc

2. 编译应用

先来个简单的程序,我假设它叫 test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
char *buf;

printf("Hello world!\n");

buf = malloc(1024);
if (!buf) {
printf("malloc buf failed\n");
return -1;
}

printf("buf ptr: %p\n", buf);

sprintf(buf, "%s", "1234\n");
printf("buf: %s", buf);

free(buf);
return 0;
}

编译它

1
$ /opt/wasi-sdk/bin/clang -O3 -o test.wasm test.c

现在,你得到了一个 test.wasm 文件了。理论上,你可以直接用 iwasm 去执行它。但我想玩玩 AOT。所以继续。

1
2
3
4
5
6
7
8
9
$ ./wamrc -o test.aot test.wasm
Create AoT compiler with:
target: x86_64
target cpu: westmere
cpu features:
opt level: 3
size level: 1
output format: AoT file
Compile success, file test.aot was generated.

现在你得到了一个 test.aot,执行它:

1
2
3
4
$ ./iwasm test.aot
Hello world!
buf ptr: 0x114e0
buf: 1234

完成!

3. 顺带一提

编译 wamrc AOT 编译器之前,使用 build_llvm.py 编译 LLVM 运行库时所传入的参数,--platform 表示当前 (也就是运行 wamrc 的构建机) 平台,--arch 表示需要 wamrc 支持生成的目标架构。具体可选值可执行 build-scripts/build_llvm.py --help 查看。

如果你需要生成 Xtensa 目标,直接传入 --arch Xtensa 会遇到两个问题,需要额外处理一下。

一是由于 LLVM 的 Xtensa 支持目前还是试验阶段,需要一个宏打开:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
diff --git a/build-scripts/build_llvm.py b/build-scripts/build_llvm.py
index bc0daf1f..db8dd1f7 100755
--- a/build-scripts/build_llvm.py
+++ b/build-scripts/build_llvm.py
@@ -66,7 +66,9 @@ def build_llvm(llvm_dir, platform, backends, projects):
"windows": [
"-DCMAKE_INSTALL_PREFIX=LLVM-install",
],
- "default": [],
+ "default": [
+ '-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="Xtensa"',
+ ],
}

LLVM_TARGETS_TO_BUILD = [

二是由于官方 llvm/llvm-project 不支持 Xtensa 目标,需要换成乐鑫的 espressif/llvm-project

1
2
3
4
5
cd core/deps/llvm
git remote set-url origin https://github.com/espressif/llvm-project.git
git fetch origin xtensa_release_13.0.0:xtensa_release_13.0.0 --depth 1
git checkout xtensa_release_13.0.0
cd ../../..

删掉 build 重新编译一下。

1
2
rm -rf core/deps/llvm/build
python build-scripts/build_llvm.py --platform darwin --arch Xtensa

4. 参考资料

Proudly powered by Hexo and Theme by Hacker
© 2022 XiNGRZ