WASM发展状况更新,以及LLVM-wasm编译环境搭建过程

简介: 之前介绍了[WASM在生产环境中的部署方案](https://www.atatech.org/articles/109271),编译的过程留了个坑,由于后来LLVM和Emscripten都有了很多更新,这里讲一下最新的发展状况,以及手把手环境搭建指南。 ## 标准发展 多数proposal仍然在开发中...... 这篇文章有详细介绍 [《WebAssembly’s post-MVP f

之前介绍了WASM在生产环境中的部署方案,编译的过程留了个坑,由于后来LLVM和Emscripten都有了很多更新,这里讲一下最新的发展状况,以及手把手环境搭建指南。

标准发展

多数proposal仍然在开发中...... 这篇文章有详细介绍 《WebAssembly’s post-MVP future: A cartoon skill tree》

总的来说,post-mvp时代还没有到来。

不过有一项post-mvp功能已经可以提前体验了,chrome70之后的版本已经默认开启了SharedArrayBuffer的支持(之前由于meltdown漏洞被默认关闭),并提供了 WebAssembly threads support 的实验性功能,相关工具并没有跟进,比可能需要自己动手体验这个接口 :)

工具栈发展

Emscripten

将完整的c/cpp桌面端项目编译成Web版本,并提供wasm版本的支持。

WASM社区目前最活跃的项目,虽然不是为WASM而设计的,也不是为模块化设计的,但是提供了目前最完整的toolchain,收到广泛支持。今年的更新中,着重优化了编译结果中胶水代码体积(之前饱受诟病的一点),可用性进一步提升。如果该项目今后能够更多的考虑到函数级以及模块级编译的需求,将大大提升WASM的易用性和普及速度。

AssemblyScript

快速发展的新兴项目,从之前的Binaryen/TypeScript编译器中发展出来。在TypeScript基础上进一步规范类型得到的一个语言子集。相关的工具栈已经非常成熟(相对于C/CPP工具栈),有可能成为接下来WASM的发展动力。

熟悉TypeScript的同学不妨尝试一下。在MVP阶段,C/CPP的很多底层性能优化特性起始用不上力,所以AssemblyScript的性能不见得比C差,而且不需要考虑标准库等麻烦的问题,与打包系统配合起来也很方便。

RUST

出于某种不明原因,RUST对WASM的支持可能是所有高级语言中最完整的(Mozilla血缘关系?)。toolchain完整,webpack支持良好,标准库也有成熟方案。观望。

LLVM/Clang

决定你能否在浏览器中跑C++的关键所在。

对WASM的支持在稳定发展,一部分功能已经加入正式版,新版本中安装和使用过程已经非常流畅,目前的遗留问题是标准库。如果你不介意不使用标准库或者跟着社区一起折腾标准库替代方案,该工具链目前已经可用。接下来会介绍如何搭建环境。

本地构建LLVM-WASM编译环境

由于LLVM对WASM的支持已经逐步稳定,社区中介绍的很多hack方案已经过时,例如:

  • "wasm32-unknown-unknown-wasm"这个triple已经不再需要,直接target=wasm即可
  • lld这个工具不再适用于wasm,应该使用专用的wasm-ld
  • llc不再需要,因为clang已经支持了wasm

现在的编译过程已经非常简化:

  • 按照官网标准过程编译LLVM,但要加入lld并开启其WASM实验性功能
  • 用clang编译成.o
  • 用wasm-ld连接成.wasm

你可以直接跑这个脚本来安装编译环境。

注意:

  • 测试环境osx,编译过程需要至少25G硬盘
  • 下载源码可能需要较长时间(10min),如果svn下载失败可以从git上的llvm-mirror下载
  • make过程可能需要较长时间(10-30min),具体要看你的电脑性能以及核心数,注意修改make -j8这一行,使用你的核心数来并行编译,不然要等几个小时
# 建个项目目录
mkdir llvm-wasm
cd llvm-wasm

# src dir
# llvm 必选
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm

# clang 必选
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
cd ../..

# extra 必选
cd llvm/tools/clang/tools
svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
cd ../../../..

# RT 必选
cd llvm/projects
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
cd ../..

# libcxx ?必选?
cd llvm/projects
# 似乎会搞挂官网然后网络失败,反正这部分标准库连接不进去......
svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
cd ../..

# lld 必选,编译wasm-ld
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/lld/trunk lld
cd ../..

# build dir
mkdir build
cd build

# cmake
cmake -G "Unix Makefiles" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly  ../llvm

# make 线程数写逻辑核数(如:4核8线程 -j8)
make -j8

使用

加入稳定支持后,使用方案就很简单了。

# 加入PATH
export PATH=当前目录/llvm/build/bin:$PATH

# 编译
clang -c -O3 --target=wasm32 test.cpp

# 连接
wasm-ld --no-entry --strip-all --allow-undefined --export-all test.o -o test.wasm

输入:

float max(float a, float b) {
  return a > b ? a : b;
}

输出(wasm转换成可读的wat):

(module
  (type $t0 (func))
  (type $t1 (func (param f32 f32) (result f32)))
  (func $__wasm_call_ctors (type $t0))
  (func $_Z3maxff (type $t1) (param $p0 f32) (param $p1 f32) (result f32)
    get_local $p0
    get_local $p1
    get_local $p0
    get_local $p1
    f32.gt
    select)
  (table $T0 1 1 anyfunc)
  (memory $memory 2)
  (global $g0 (mut i32) (i32.const 66560))
  (global $__heap_base i32 (i32.const 66560))
  (global $__data_end i32 (i32.const 1024))
  (global $__dso_handle i32 (i32.const 1024))
  (export "memory" (memory 0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "__heap_base" (global 1))
  (export "__data_end" (global 2))
  (export "__dso_handle" (global 3))
  (export "_Z3maxff" (func $_Z3maxff)))

注意由于使用了-O3优化,最后暴露出的函数名被加上了前后缀,代表其传入传出参数类型,调用的时候要注意加上。

目录
相关文章
|
5月前
|
人工智能 Rust 安全
WebAssembly运行时库(WASM runtime:wasmer 或 wasmtime)\将rust官方demo猜数字编译为WASI目标并使用Wasmer运行
WebAssembly运行时库(WASM runtime:wasmer 或 wasmtime)\将rust官方demo猜数字编译为WASI目标并使用Wasmer运行
77 2
|
6月前
|
编译器 Linux C语言
Valgrind兼容性解析:从核心依赖到错误诊断
Valgrind兼容性解析:从核心依赖到错误诊断
245 0
|
6月前
|
缓存 监控 Java
即时编译(JIT):从源代码到高效执行的神奇之旅(上)
即时编译(JIT):从源代码到高效执行的神奇之旅(上)
|
6月前
|
缓存 监控 编译器
即时编译(JIT):从源代码到高效执行的神奇之旅(下)
即时编译(JIT):从源代码到高效执行的神奇之旅(下)
|
6月前
|
缓存 编译器 Go
Build实战指南:优雅编译,高效开发
Build实战指南:优雅编译,高效开发
110 0
|
缓存 JavaScript 前端开发
Umi 4 特性 04:build 阶段的构建提速
Umi 4 特性 04:build 阶段的构建提速
1074 0
|
Java Linux 开发工具
RK3399平台开发系列讲解(系统编译篇)8.6、安卓开发环境的搭建及编译
RK3399平台开发系列讲解(系统编译篇)8.6、安卓开发环境的搭建及编译
218 0
|
Rust
【Rust指南】配置加速Cargo下载、更新依赖库|利用随机数编写Rust猜数游戏
【Rust指南】配置加速Cargo下载、更新依赖库|利用随机数编写Rust猜数游戏
531 0
【Rust指南】配置加速Cargo下载、更新依赖库|利用随机数编写Rust猜数游戏