在 OpenHarmony 开发板上运行 WasmEdge 原创 精华

CChristal
发布于 2022-1-5 12:42
浏览
11收藏

@toc
作者:翁纯仪

在 OpenHarmony OS 上运行 WasmEdge,能够改善开发者的开体验。

Why

移动与 IoT 设备的特点是资源受限,软硬件不统一,用户体验却要求很高。设备要能安全,跨平台地运行第三方开发者提供的软件应用(例如,应用商店),因而直接原生编译的软件应用(Native Client, or NaCl)并不主流。鸿蒙与安卓这样的主流操作系统一般提供基于 Java 或者 JavaScript 的软件执行沙盒,来支持第三方应用。但是这样的软件执行沙盒有几个大问题:

  • 支持的编程语言很有限
  • 支持的语言有 IP 与法律风险
  • 性能一般
  • 资源开销大
  • 无法支持实时系统
  • 安全性一般(所以应用商店需要审查制)

而 WebAssembly 作为一个多语言,跨平台,高性能,轻量级,安全的软件执行环境,能让开发者兼得性能,可移植性,与安全性。WebAssembly 是移动与 IoT 设备上系统中间件的最佳选择。
 
WasmEdge 是由 CNCF 托管的轻量级、高性能和可扩展的 WebAssembly runtime,适用于云原生、边缘和去中心化应用程序。WasmEdge 可以运行 C/C++、Rust、Swift、AssemblyScript 或 Kotlin 等语言编译的标准 WebAssembly 字节码程序。
 
OpenHarmony 是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。
 
WasmEdge 为 OpenHarmony 提供了一个与 JVM 与 JS engine 同级的 runtime,但是比 JVM、JS engine 更安全、更快、更小、更易于管理。通过 WasmEdge,可以在设备上安全地运行第三方开发者用 C、C++、Rust 等语言编写的 Wasm 程序,扩大 OpenHarmony 的开发者群体。 WasmEdge 相当于 OpenHarmony 的一个完全开源的开发执行环境。社区开发者可以方便地运行编译好的 WebAssembly 程序,降低门槛。
 
WasmEdge 目前已经支持了 Linux、macOS、Windows 与 实时操作系统 seL4。添加 OpenHarmony 的支持,将丰富 WasmEdge 的生态。
 
介绍完毕 ,下面进入编程时间。请参考下面的教程从源码在 OpenHarmony 开发板中构建和测试 WasmEdge。
 
1. 全量编译 OpenHarmony OS
2. 获取 WasmEdge 源码
3. 修改 OpenHarmony 标准系统配置文件
4. 构建 WasmEdge 与 OpenHarmony
5. 烧录到开发板
6. 运行 WasmEdge 提供的测试用例

 
配合视频观看,效果更佳。


环境准备

OpenHarmony 标准系统

OpenHarmony 标准系统为开发者提供的 Docker 环境封装了对应的编译工具链,本文档主要介绍在 Docker 环境下构建 WasmEdge 的步骤.
 
OpenHarmony 源码的获取与编译可以参考 Open Harmony 提供的文档 搭建Ubuntu环境-Docker方式
 
请注意,在构建 WasmEdge 前需要将 Openharmony 进行一次全量编译以便后续 WasmEdge 的交叉编译过程.

# 获取到 docker 镜像后
$ docker run -it -v $(pwd):/home/openharmony openharmony-docker-standard:0.0.5
$ ./build.sh --product-name Hi3516DV300

获取 WasmEdge 源码

OpenHarmony 将第三方库项目放在了 third_party 文件夹下,因此我们需要在 third_party 文件夹下获取 WasmEdge 源码。

这之后,用户可以根据需要更改路径并修改相关配置文件中的路径。

$ docker run -it -v $(pwd):/home/openharmony openharmony-docker-standard:0.0.5
$ cd third_party
$ git clone https://github.com/WasmEdge/WasmEdge.git
$ cd WasmEdge

修改 OpenHarmony 标准系统配置文件

添加 WasmEdge 子系统配置

修改 OpenHarmony 的 build 目录下的 subsystem_config.json 文件,如下添加 wasmedge 子系统。

{
  ...
  
  "wasmedge": {
    "path": "third_party/WasmEdge",
    "name": "wasmedge"
  },
  
  ...
}

将组件添加到产品配置中

修改 OpenHarmony 产品配置文件,标准系统对应的配置文件为:productdefine/common/products/Hi3516DV300.json
在该配置文件中添加 "wasmedge:wasmedge":{},表示该产品会编译并打包 wasmedge 子系统下的 wasmedge 模块到版本中。

{
  ...
  "parts":{
    ...
    "wasmedge:wasmedge":{}
  }
}

构建 WasmEdge 与 OpenHarmony

说明

在 OpenHarmony 中构建的 WasmEdge 目前仅支持 wasmedge,即 wasm 的通用运行时。

  • wasmedge 可以在解释器模式下执行一个 WASM 文件, 也可以执行从 WASM 文件 AOT 预编译产生的机器码二进制格式文件。但目前还不支持在 OpenHarmony 中对 WASM 文件进行 AOT 预编译 。

执行构建脚本

执行 WasmEdge 源码下的 utils/build_for_ohos.sh 命令行脚本,将自动执行以下工作:

  1. .gn 等 OpenHarmony 需要的构建配置文件移动到 WasmEdge 项目根目录;
  2. 使用 OpenHarmony 的编译工具链进行交叉编译构建 WasmEdge;
  3. 运行 OpenHarmony 的构建脚本 build.sh 进行全量编译,该步骤将 wasmedge 添加进 OpenHarmony OS;
$ docker run -it -v $(pwd):/home/openharmony openharmony-docker-standard:0.0.5
$ cd third_party/WasmEdge/utils/ohos
$ ./build_for_ohos.sh /home/openharmony

当 terminal 显示以下信息时,表明编译完成.

...

post_process
=====build Hi3516DV300 successful.
2021-12-15 03:18:50
++++++++++++++++++++++++++++++++++++++++

检查 wasmedge 是否编译打包进 OpenHarmony OS。

$ cd /home/openharmony/out/ohos-arm-release/packages/phone/system/bin
$ ls 

当输出的文件名中存在 wasmedge 时,就表明 WasmEdge 已经成功导入到 OpenHarmony OS。


测试

烧录镜像

将重新编译后的 OpenHarmony 标准系统镜像烧录进开发板,具体见 OpenHarmony 提供的文档 Hi3516DV300 开发板烧录

运行应用

WasmEdge 在 tools/wasmedge/examples/ 文件夹提供了测试样例。在 OpenHarmony 标准系统中,这些样例写入了 system 镜像中,依然可以进行测试。通过串口工具连接上开发板并启动OpenHarmony 标准系统后,我们就可以进行以下的测试。

# cd /system/usr/wasmedge_example
# wasmedge hello.wasm 1 2 3
hello
1
2
3
# wasmedge --reactor add.wasm add 2 2
4
# wasmedge --reactor fibonacci.wasm fib 8
34
# wasmedge --reactor factorial.wasm fac 12
479001600
#
# cd js
# wasmedge --dir .:. qjs.wasm hello.js 1 2 3
Hello 1 2 3

下一步

接下来,你可以参考 WasmEdge Book 在 OpenHarmony 标准系统中使用 WasmEdge Runtime 来运行你自己的 WebAssembly 应用。


移植过程踩过的坑

最后和大家分享一下,在移植 WasmEdge 到 OpenHarmony OS 过程出现的一些问题与值得注意的地方。

交叉编译

cmake 项目进行交叉编译需要配置工具链,官方的交叉编译配置给出了参考,但需要在此基础上细化,如指明 Clang 及 Clang++ 的位置。此外,标准版 sysroot 的路径也有所不同,具体可以参考 WasmEdge 中的配置:

  set(TOOLSCHAIN_PATH "${OHOS_DIR_PATH}/prebuilts/clang/ohos/linux-x86_64/llvm")
  set(TOOLCHAIN_HOST "${TOOLSCHAIN_PATH}/bin")
  set(OHOS_SYSROOT_PATH "${OHOS_DIR_PATH}/out/ohos-arm-release/obj/third_party/musl")
  set(CMAKE_SYSROOT ${OHOS_SYSROOT_PATH})
  set(CMAKE_CROSSCOMPILING TRUE)
  set(CMAKE_SYSTEM_NAME "Generic")
  set(CMAKE_CXX_COMPILER_ID Clang)
  set(CMAKE_TOOLCHAIN_PREFIX llvm-)
  set(LLVM_PATH "${OHOS_DIR_PATH}/prebuilts/clang/ohos/linux-x86_64/llvm")
  include_directories(${LLVM_PATH}/include/c++/v1)
  include_directories(${OHOS_SYSROOT_PATH}/usr/include/arm-linux-ohosmusl)
  link_directories(${OHOS_SYSROOT_PATH}/usr/lib/arm-linux-ohosmusl)
  set(TOOLCHAIN_CC "${TOOLCHAIN_HOST}/clang")
  set(TOOLCHAIN_CXX "${TOOLCHAIN_HOST}/clang++")
  set(CMAKE_C_COMPILER ${TOOLCHAIN_CC})
  set(CMAKE_C_FLAGS "--target=arm-linux-ohosmusl -D__clang__ -march=armv7-a -mfloat-abi=softfp -mtune=generic-armv7-a -mfpu=neon -mthumb -w --sysroot=${OHOS_SYSROOT_PATH}")
  set(CMAKE_CXX_COMPILER ${TOOLCHAIN_CXX})
  set(CMAKE_CXX_FLAGS "--target=arm-linux-ohosmusl -D__clang__ -march=armv7-a -mfloat-abi=softfp -mtune=generic-armv7-a -mfpu=neon -mthumb -w --sysroot=${OHOS_SYSROOT_PATH}")
  set(MY_LINK_FLAGS "--target=arm-linux-ohosmusl --sysroot=${OHOS_SYSROOT_PATH}")
  set(CMAKE_LINKER clang)
  set(CMAKE_CXX_LINKER clang++)
  set(CMAKE_C_LINKER clang)
  set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINKER} ${MY_LINK_FLAGS} <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
  set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINKER} ${MY_LINK_FLAGS} <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")

编译工具链

OpenHarmony OS 使用 gn+ninja 进行编译。对于 cmake 组织编译的项目来说,官方提供的 cmake 项目移植文档给出的案例是基于轻量级系统的,并不完全适用于标准版系统上的移植。要想将项目写入 OpenHarmony OS 编译生成的镜像烧录到开发板上,需要编写 gn 脚本参与进 OpenHarmony OS 的编译过程。
 
在 WasmEdge 编译过程中,需要使用到 spqlog 项目,构建过程中存在 spdlog 项目拉取及编译生成 sqdlog 静态库的动作,这意味着只将 WasmEdge 相关库的编译过程改写为 gn 脚本是不够的,还需要对 spdlog 的编译过程进行改写,使得工作量急剧增加。
 
那么对于项目所依赖但并不属于 OpenHarmony OS 中的静态库模块,编译过程中要如何将这一模块引入 OpenHarmony OS 呢?
 
OpenHarmony OS 提供的 gn 编写模板中有 ohos_copy ,它可以将生成的静态库移至生成的目标文件夹。这样在真正编译需要链接时,就能将这一静态库视为 OpenHarmony OS 的原生模块而不是查无此库。在 WasmEdge 的移植过程中,所执行的编译脚本便是事先进行一遍交叉编译,生成需要 copy 的 spdlog 静态库,然后再执行 OpenHarmony OS 的编译脚本,从而按照项目目录下的 BUILD.gn 内的定义组织编译。
 
在 WasmEdge 的 BUILD.gn 中,关于 spdlog 静态库的描述如下:

ohos_copy("spdlog"){
    sources = [
        "$WASMEDGE_ROOT_DIR/build/_deps/spdlog-build/libspdlog.a",
    ]
    outputs = [
        target_out_dir + "/lib/libspdlog.a"
    ]
    module_install_name = ""
}

标准 C 库

平时我们常用的标准 C 库是 GNU 发布的 libc 库,而 OpenHarmony 中使用的是 Musl-libc,因此如果需要移植的项目代码中使用了 glibc 的宏变量的代码,那么需要进行修改或者在开头重新定义为 Musl-libc 中的宏变量。

链接项

../../third_party/WasmEdge/lib/system/allocator.cpp:64:40: error: unused variable 'k4G' [-Werror,-Wunused-const-variable]
static inline constexpr const uint64_t k4G = UINT64_C(0x100000000);
                                       ^
../../third_party/WasmEdge/lib/system/allocator.cpp:65:40: error: unused variable 'k12G' [-Werror,-Wunused-const-variable]
static inline constexpr const uint64_t k12G = UINT64_C(0x300000000);
                                       ^
1 warning and 2 errors generated.

诸如这类报错,在 BUILD.gn 中使用到该源码的模块中添加 cflags.例如,对上面的报错,可以添加如下的 cflags

cflags = [
  ...
  "-Wno-unused-const-variable",
  ...
]

如果出现下面的 C++ 的链接编译报错,

../../third_party/WasmEdge/lib/host/wasi/inode-linux.cpp:745:3: error: cannot use 'try' with exceptions disabled
  try {
  ^

则添加 cflags_cc:

# BUILD.gn 使用到该源码的相应模块
{
  ...
  cflags_cc = [ 
    ...
    "-fexceptions",
    ...
  ]
}

移植过程中还有许多诸如此类的编译报错,在此不进行一一列举,有兴趣的朋友欢迎在下面留言,一起讨论。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-1-5 13:14:55修改
13
收藏 11
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

厉害呀,围观一波

回复
2022-1-5 13:44:56
物联风景
物联风景

这个好  先收藏了

回复
2022-1-6 10:25:12
回复
    相关推荐