Closed21

PlantUMLをWASMに移植してブラウザ上で動かせないか

2022年 GitHubがmermaidによる作図に対応した。

https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/

PlantUML派としては悔しいです。

しかしmermaid-jsのいいところはJavaScriptベースなのでブラウザの中で完結する。
それ故にWikiとの統合がしやすかったのだろう。

対してPlantUMLはJavaベースなのがつらい。

  • JREがないと動かない
    • VSCodeで使うときもここはちょっと煩わしい
  • Appletの廃れた今、ブラウザ上でJavaコードを動かすのは無い
    • それ故にplantuml-serverを立てる必要がある
      • サーバーにするとトラフィック量によるスケール費用とか、DoS攻撃とか色々気になるから採用しづらくなる気持ちがわかる
  • おまけにGraphviz依存もある

PlantUMLがWASMになればブラウザ上で完結して幸せになれるんじゃね?

PlantUMLがどう実装されているか調べてみる

https://github.com/plantuml/plantuml

ビルドシステム複雑だな・・・

  • gradle -> kotlinだ
  • maven -> pom.xmlあるしそうだよね? pom.xml消えた
  • ant -> build.xmlがそれっぽい

3つも使ってんの??

結局どこでGraphvizと連携しているんや…
PlantUML記法→DOT記法からのGraphvizでSVG生成だと思ってたけど違うのだろうか?

ライセンス

GPLv3だとFAQに書いてある

他、LGPL, Apache, EPL, MITでも良いと。

PlantUML2

https://github.com/plantuml/plantuml2

Haxeで書き直してマルチプラットフォーム化を目指しているよう。HaxeからJavaScriptへもトランスパイルできるみたいなのでWeb上でPlantUMLが使いやすくなるのは期待できそうだが。

We will port to Haxe the Smetana project which means that PlantUML 2 will not need any Graphviz/dot executable to run.

ということでGraphviz依存はなくなる模様。

そもそもWASMどう動かすのよ?

https://developer.mozilla.org/ja/docs/WebAssembly/Rust_to_wasm

これはちょろっとやってみたけど、

  • 基本的にwasm-pack crateのチカラ
  • Rustコードをwasm形式にコンパイルしてくれる以外にも、
  • JavaScript -> wasm内のFunctionに対するバインディングを用意してくれる
  • Rust側からJavaScriptのFunctionを呼び出せるバインディングを用意してくれる

という感じで、直接wasmが動くわけでなく、JavaScriptがWASM内のFunctionを呼び出せるようにしているもの。つまりアプリケーションのBootstrap的なところはHTML+JavaScriptの世界で書く必要がある。

このことは上記MDNでも述べられている。

Rust と WebAssembly には、主に 2 つのユースケースがあります。

  • アプリケーション全体を構築する — ウェブアプリ全体を Rust ベースで構築します。
  • アプリケーションの一部を構築する — 既存の JavaScript フロントエンドの内部で Rust を使用します。 <--こっちにフォーカスされている

Webサイト上でPlantUMLを動かすという意味ではwasm-packのアプローチはマッチしている。
VSCodeの拡張として動かすケースでもマッチする。

WASIも試しておきたい

本筋とは少し異なるがコマンドラインツールの側面としてWASIも試しておきたい

https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-intro.md
  • WASIはBrowser, JS independet なWASM仕様 -> ランタイムのためのインターフェース?
  • BytecodeAllianceが中心となって策定している
  • WASI実装としては wasmtime, wasmer, lucetの3つがメジャーっぽい

wasmtime

https://github.com/bytecodealliance/wasmtime
  • BytecodeAllienceのリファレンス実装
  • 実用性でいうと起動速度、実行速度ともに物足りなくなっている様子

wasmer

https://wasmer.io/
  • 単純なWASI実装を超えてエコシステム目指してるっぽい
    • NPMライクなWAPMとか
  • 商業感ある

lucet

https://www.fastly.com/blog/how-lucet-wasmtime-make-stronger-compiler-together
  • CDNで有名なFastly主管
  • Fastlyはエッジコンピューティングの有力な手段としてwasm推し
  • BytecodeAllianceのwasmtimeと密な連携してそう
  • ...と思ったら開発終了してwasmtimeと合流してる
    • もともとwasmtimeの派生でその成果をwasmtimeに還元してプロジェクトを終了したっぽい

そのままの流れでWasmerも。コンテナ化はちゃんとしてない。

$ sudo apt update
$ sudo apt install libxkbcommon0
$ sudo apt install libtinfo5
$ curl https://get.wasmer.io -sSfL | bash

libxkbcommon0 問題は https://github.com/wasmerio/wasmer/issues/2822 で議論されてた。

同じwasmファイルが当然wasmerでも動く

$ wasmer ./target/wasm32-wasi/debug/hello.wasm 
Hello, world!

単純なHello Worldだからアレだけどwasmer早いな…

$ time wasmer ./target/wasm32-wasi/debug/hello.wasm 
Hello, world!

real    0m0.007s
user    0m0.007s
sys     0m0.000s

$ time wasmtime ./target/wasm32-wasi/debug/hello.wasm 
Hello, world!

real    0m0.014s
user    0m0.015s
sys     0m0.000s

$ time ./target/debug/hello
Hello, world!

real    0m0.001s
user    0m0.001s
sys     0m0.000s

File I/Oのチュートリアルやってみる

https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-tutorial.md#from-rust

なるほど、サンドボックスとして --dir, --mapdirでファイルアクセス範囲をホワイトリストで指定するようになっているのか。

The --dir= option instructs wasmtime to preopen a directory, and make it available to the program as a capability which can be used to open files inside that directory.

結局、WASI/WASMの関係性は何なのか?

  • 一般的にWASMと呼ばれているものはブラウザ向けのWebAssemblyのこと
  • 対してWASIはCoreにWASI APIをのっけたもの
    • 正確にはInterfaceなのでWASI API仕様だけで、実装としてwasmerやwasmtimeなどがある
      • こちらもOSネイティブなランタイムにEmbeddedされている

つまり、ブラウザ向けのWASMとWASI向けのWASMには差がある。積集合に当たる部分はCoreで共通するが使えるcapabilityが異なる。

ブラウザ向けにコンパイルされた(アセンブルされたというべき?)wasmはWASIでは動かないかもしれない=依存するAPIが使えないかもしれない

理解の役に立った文献

Graphvizをwasm用にどうにかする

Emscriptenでビルドしてwasm化している例があるので、これを真似ればRustコードからGraphvizを使える気がする。

https://github.com/hpcc-systems/hpcc-js-wasm

一方でpure Rustでdot記法をsvgにするプログラムを書いている人もいるがすべてのdot記法をカバーは指定なさそう。実験的なものかな?

https://github.com/nadavrot/layout

hpcc-js-wasmをビルドして何が起きているのかを解析してみる

npm run install-build-deps

https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/scripts/cpp-install-graphviz.sh
  1. Graphviz公式のGitLabからソースを取得
  2. cmakeを使って./src-graphviz/build の中にビルドする
    • 例) ./src-graphviz/build/lib/gvc/libgvc.so.6.0.0

npm run build

https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/scripts/cpp-build.sh

https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/cpp/CMakeLists.txt
  1. ツールチェインとしてemscripten使う
  2. あとはCMakeにヨロ

これじゃ何もわからんやんけ

cpp/graphviz/CMakeLists.txt を追う

https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/cpp/graphviz/CMakeLists.txt
  • src-graphviz/lib
  • src-graphviz/plugin
  • src-graphviz/build
  • cpp/graphviz/lib
  • cpp/graphviz/plugin
  • cpp/graphviz/graphvizlib

build.rsに書き直す

cmake crateの使い方はなんとなくわかった。

https://github.com/NewGyu/rust-wasm-with-graphviz/blob/master/clib-graphviz/build.rs

CMAKE_TOOLCHAIN_FILEにEmscripten.cmakeを指定するのは合っているのか??

hpcc-js-wasmのスクリプト実行結果

https://github.com/NewGyu/rust-wasm-with-graphviz/blob/master/memo/cpp-build.sh.md

当たり前だけど正常に完了する。

build/graphvizlib/
├── CMakeFiles
│   ├── graphvizlib.dir
│   │   └── main.cpp.o
├── graphvizlib.js
└── graphvizlib.wasm
Scanning dependencies of target graphvizlib
[ 99%] Building CXX object graphvizlib/CMakeFiles/graphvizlib.dir/main.cpp.o
[100%] Linking CXX executable graphvizlib.js
[100%] Built target graphvizlib

今回はjsとwasmファイルはいらないんだよな。

CMAKE_TOOLCHAIN_FILE無指定だとgcc使ってリンクがうまくいかない

https://github.com/NewGyu/rust-wasm-with-graphviz/blob/master/memo/gcc-compiled.md

Emscripten.cmakeを指定すると最後のgraphvizlib.js作るところでコケる

https://github.com/NewGyu/rust-wasm-with-graphviz/blob/master/memo/emcc-compile.md
failed (returned 1)
  make[2]: *** [graphvizlib/CMakeFiles/graphvizlib.dir/build.make:111: graphvizlib/graphvizlib.js] Error 1
  make[1]: *** [CMakeFiles/Makefile2:1608: graphvizlib/CMakeFiles/graphvizlib.dir/all] Error 2
  make: *** [Makefile:130: all] Error 2
このスクラップは23日前にクローズされました
作成者以外のコメントは許可されていません