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
乳牛乳牛

結局、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
このスクラップは2022/11/09にクローズされました