1 of 41

WebAssemblyに足りないもの

東京Node学園祭2016

2016/11/13�Yoshiki Shibukawa (@shibu_jp)

2 of 41

お前誰よ

  • <MARQUEE>誕生日は明日(11/14)です!!</MARQUEE>
  • 3人目の子供が生まれました
  • 社内SE的な仕事
  • よく使う言語はGo、C++、Python、JavaScript
  • たまに物を書いたりします
  • 最近のお気に入りのガジェットは�SOLOWHEELです

3 of 41

君たちに最新情報を公開しよう

  • 昨年Mithrilのebookを世界最速で出しました
    • というか世界唯一?
    • 0.2ベースでした
  • Mithrilは現在1.0rc3です�https://github.com/lhorie/mithril.js/tree/rewrite
    • コードサイズがさらに減って高速になるとか
    • API数はほぼ変わらず(m.component等、一部減る)
    • ストイックな人におすすめ!
  • 書籍は1.0化したい
    • コンテンツもちょっと足したい!

4 of 41

WebAssemblyに足りないもの

5 of 41

背景

  • JavaScriptにasm.jsがきた
    • C/C++からコンパイルしてブラウザで動かせる(emscripten)
    • 高速化(ネイティブより10倍遅いJSが2倍遅い程度になる)
    • JSよりも機能は低く、文字列すらない。DOMもアクセスできない。
  • WebAssemblyがきた
    • バイナリフォーマットでロードが早くなる
    • 実行速度が早くはならない (それはasm.js対応側の機能)

6 of 41

WebAssemblyを書くには?

  • C/C++(emscripten)
  • LLVM系の言語
    • 今のところ積極的なのはRustぐらい?
  • オールインワンのゲームエンジン
    • Unreal Engine 4
    • Unity 3D 5.x

7 of 41

C/C++

8 of 41

WELCOME TO HELL!!!!

9 of 41

C/C++

  • C++11、14、17と、言語そのものはとても良くなっています
    • lambdaと型推論(auto)、rangeアクセスあたりだけでも大分すっきり
  • もう(昔ほど)怖い言語じゃないよ
    • むかし膝にC++を受けた(IUnknownとかで)人もぜひもう一度再入門を!
  • 問題は言語よりも下のレイヤー

10 of 41

WebAssemblyには関係ないツライところ (1)

  • コンパイル(ランタイムライブラリ)のモードとか実行モードとか
    • /MD, /MT, /ML, /MDd, /MTd, /MLd, /LD, /LDd
    • -mmacosx-version-min=10.8
  • .dll, .so, .a, .lib, .dylib
    • __declspec(dllimport)とか
    • 静的リンクライブラリと動的リンクライブラリで書き方が変わるとか
    • WebAssemblyも動的リンクとか言ってるので無関係でもない?
    • 動的リンクの方式が規格にない→JavaScriptと同じだ!
  • 名前マングリング(含むABI)が規格にない
    • クロスコンパイルできてもVC++用ライブラリは他のOSから使えない
    • Haiku OSとか、未だにGCC 2系を引きずっている・・・

11 of 41

WebAssemblyには関係ないツライところ (2)

  • 共有ライブラリもヘッダーがないとダメ
    • macOS添付のlibssl.dylibのヘッダーがないから再利用できない問題
    • pyOpenSSL とか cryptgraphy みたいなモジュールが OpenSSL にリンクするんだけど、そいつらを別の OpenSSL でビルドしたときに問題が起こる (@moriyoshit情報)
  • SxSとかなんですかそれ
  • クロスコンパイラ用意するのがめんどう・・・

12 of 41

WebAssemblyも関係するところ (1)

  • 環境から独立の枯れたパッケージマネージャがない
    • OS提供のツールに相乗りしてるのが多い
      • yum/apt/port/homebrew…
      • ビルド済みツールの利用者でしかなければ問題はないが・・・
    • 開発版とOSで使いたいバージョンが違う場合どうするの?
      • Qt4を要求する開発補助ツールを使いつつ開発はQt5を使いたい場合
      • MacPortsだとQt4/Qt5はコンフリクトする
    • そもそも開発環境とターゲット(web)が違う場合に使えない
      • ターゲットがLinuxならコンテナでいいのかもしれないが・・・

13 of 41

C/C++のパッケージマネージャ

  • biicode.com
    • 死んだ
    • github pagesだけ残ってて切ない
  • clib
    • C言語用
  • CMakeベース
    • CPM、Hunterとかいろいろ
  • conan.io
    • 今年リリース
    • まだ詳しくは触ってないけど・・・まあ悪くない?
  • QTPM
    • わしがつくった

14 of 41

定番がない

  • クロスコンパイルとか可能なのか?
    • そもそも静的ライブラリが作れないやつはどうするのか?
  • 欲しいライブラリはあるのか?
  • セキュリティアップデートはあるのか?

15 of 41

WebAssemblyにも関係するところ (2)

  • ビルドに必要なツールの選択肢がたくさん
    • 上位レイヤー
      • autotools (configure)
      • CMake / qmake
    • 下位レイヤーのみ?
      • ninja/make
    • 下位レイヤーまでやる系
      • waf/SCons/Visual Studio/XCode
  • OSによって使い分け・複数サポートが必要だったり
    • 同じWindowsでも、VC++、mingw、cygwinでは違う手法やオプションが必要だったり
  • gulpとgruntとnpm scriptsで悩むぐらいどうってことないですよね!

16 of 41

CMake

  • 現時点でのレジェンド・オブ・ビルドツール(デファクトスタンダード)になりつつある
    • Qt5は自前のビルドツールにプラスしてCMakeもサポートした
    • JetBrains社のC++ IDEはプロジェクトファイル形式としてCMakeのみをサポート
  • 中に各環境のコンパイラ情報とかライブラリの情報とかすべて持っている
    • C++の闇はすべてCMakeの腹の中に・・・
  • qmakeやMakeなどが宣言的(grunt的)なのに対して、手続き型構造化言語になっている

17 of 41

CMakeの欠点

  • 設定ファイルがとにかく長くなる
  • デバッガとかが欲しくなる
  • 環境の違いを吸収するのは簡単ではない
  • なんでもできてしまうがゆえに、他の人が書いたファイルが読みづらい・・・

18 of 41

CMakeでfizzbuzz

foreach(i RANGE 1 100)� math(EXPR notFizz "${i} % 3")� math(EXPR notBuzz "${i} % 5")� if(NOT notFizz AND notBuzz) � message("fizz")� elseif(notFizz AND NOT notBuzz)� message("buzz")� elseif(NOT notFizz AND NOT notBuzz)� message("fizzbuzz")� else()� message("${i}")� endif()�endforeach()

19 of 41

CMakeでズンドコキ・ヨ・シ!

set(kiyoshied false)�set(zun 0)�while(NOT kiyoshied)� string(RANDOM LENGTH 1 ALPHABET 01 number)� if(${number})� message("ズン")� math(EXPR zun "${zun}+1")� else()� message("ドコ")� if(${zun} EQUAL 4)� message("キ・ヨ・シ!")� set(kiyoshied true)� endif()� set(zun 0)� endif()�endwhile()

20 of 41

cmake_minimum_required(VERSION 3.1.0)��# project global setting��project(workbench7)��set(WORKBENCH7_MAJOR_VERSION 0)�set(WORKBENCH7_MINOR_VERSION 1)�set(WORKBENCH7_PATCH_VERSION 0)�set(WORKBENCH7_VERSION 0.1.0)��# qtpm setting��set(VENDOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/vendor)��# compiler setting��set(CMAKE_CXX_STANDARD 11)�if(MSVC)� set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")�else()� set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")�endif()��# enable Qt��set(CMAKE_AUTOMOC ON)�set(CMAKE_AUTOUIC ON)�set(CMAKE_AUTORCC ON)�set(CMAKE_INCLUDE_CURRENT_DIR ON)�include_directories(${CMAKE_CURRENT_BINARY_DIR})�if(DEFINED ENV{QTDIR})� set(CMAKE_PREFIX_PATH "$ENV{QTDIR}")�endif()��find_package(Qt5Core REQUIRED)�find_package(Qt5Gui REQUIRED)�find_package(Qt5Widgets REQUIRED)�# include extra settings��include("${CMAKE_CURRENT_SOURCE_DIR}/CMakeExtra.txt" OPTIONAL)

21 of 41

# dependencies��set(QTPM_IS_ROOT_PROJECT FALSE)�add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package1 ${CMAKE_CURRENT_BINARY_DIR}/package1)�include("${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package1/CMakeExtra.txt" OPTIONAL)�include_directories(${VENDOR_PATH}/github.com___shibukawa___package1/src)�add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package2 ${CMAKE_CURRENT_BINARY_DIR}/package2)�include("${CMAKE_CURRENT_SOURCE_DIR}/vendor/github.com___shibukawa___package2/CMakeExtra.txt" OPTIONAL)�include_directories(${VENDOR_PATH}/github.com___shibukawa___package2/src)��# build setting��include_directories(src)��if(APPLE)� set(MACOSX_BUNDLE_BUNDLE_NAME Workbench7)� set(MACOSX_BUNDLE_GUI_IDENTIFIER "Workbench7")� set(MACOSX_BUNDLE_ICON_FILE MacOSXAppIcon.icns)� set_source_files_properties(Resources/MacOSXAppIcon.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")� set(MACOSX_BUNDLE_INFO_STRING "Workbench7-0.1.0, Copyright 2016 shibukawa.yoshiki")� set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${WORKBENCH7_MAJOR_VERSION}.${WORKBENCH7_MINOR_VERSION}" )� set(MACOSX_BUNDLE_LONG_VERSION_STRING "${WORKBENCH7_VERSION}")� set(MACOSX_BUNDLE_BUNDLE_VERSION "${WORKBENCH7_VERSION}")� set(MACOSX_BUNDLE_COPYRIGHT "(C) 2016 shibukawa.yoshiki")� add_executable(workbench7 MACOSX_BUNDLE src/main.cpp Resources/MacOSXAppIcon.icns)�

22 of 41

elseif(WIN32)� set(winres "${CMAKE_CURRENT_SOURCE_DIR}/windows.rc")� if(MINGW)� if(NOT CMAKE_RC_COMPILER)� set(CMAKE_RC_COMPILER windres.exe)� endif()� set(winresobj "${CMAKE_CURRENT_SOURCE_DIR}/windows.rc.obj")� add_custom_command(OUTPUT "${winresobj}"COMMAND ${CMAKE_RC_COMPILER}� -D GCC_WINDRES-I ${CMAKE_CURRENT_SOURCE_DIR}� -I ${CMAKE_CURRENT_BINARY_DIR}� -o ${winresobj}� -i ${winres})� set(${sources} "${winresobj}")� else()� set(${sources} ${winres})� endif()� add_executable(workbench7 WIN32 src/main.cpp ${sources})�else()� add_executable(workbench7 src/main.cpp)�endif()�qt5_use_modules(workbench7 Core Gui Widgets)�target_link_libraries(workbench7 package1 package2)

23 of 41

# installer setting��if(WIN32)� install(TARGETS workbench7 ${dlls} RUNTIME DESTINATION bin COMPONENT applications)� file(GLOB dlls ${CMAKE_CURRENT_BINARY_DIR}/*.dll)� install(PROGRAMS ${dlls} DESTINATION bin COMPONENT applications)� install(DIRECTORY� ${CMAKE_CURRENT_BINARY_DIR}/iconengines� ${CMAKE_CURRENT_BINARY_DIR}/imageformats� ${CMAKE_CURRENT_BINARY_DIR}/platforms� ${CMAKE_CURRENT_BINARY_DIR}/translations DESTINATION bin COMPONENT applications)� set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)� include(InstallRequiredSystemLibraries)� install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}� DESTINATION programsCOMPONENT applications)� set(CPACK_PACKAGE_NAME "Workbench7")� set(CPACK_PACKAGE_VENDOR "shibukawa.yoshiki")� set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Write your project description here")� set(CPACK_PACKAGE_VERSION_MAJOR "${WORKBENCH7_MAJOR_VERSION}")� set(CPACK_PACKAGE_VERSION_MINOR "${WORKBENCH7_MINOR_VERSION}")� set(CPACK_PACKAGE_VERSION_PATCH "${WORKBENCH7_PATCH_VERSION}")� set(CPACK_PACKAGE_VERSION "${WORKBENCH7_VERSION}")� set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.rst")� set(CPACK_PACKAGE_INSTALL_DIRECTORY "installer")� set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "applications (Workbench7)")� set(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_BINARY_DIR}/WindowsAppIcon.ico")� set(CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_BINARY_DIR}/WindowsAppIcon.ico")� set(CPACK_NSIS_MENU_LINKS "programs/workbench7" "Workbench7")� include(CPack)�endif()

24 of 41

  • C++11でWindowsとmacで、子供プロジェクトの設定ファイルを読み込みつつ、ライブラリを静的リンクして実行ファイルを作ってインストーラを作るCMakeLists.txtです。
  • 本当はWindowsのインストーラ作成はWiXにしたかったけど情報が見つからなくてNSISです。

25 of 41

WebAssemblyにも関係するところ (3)

  • 歴史あるライブラリがみんなでかい
    • 標準ライブラリが貧弱だった歴史的経緯
  • 自前主義
    • みんな自前で文字列クラスを実装しだす
      • CString、QString、TAnsiString、gchar*....
    • みんな自前でリストコンテナクラスを実装しだす
      • CList、QList、TList、GList…
    • みんな自前で動的型システムを実装しだす
      • COM、Qtのsignal/slot(moc)、GObjct…
    • AltJSはあるけど、トランスパイラがない世界線
      • アプリケーションを書く人は好きなの使えばいいけど、ライブラリの実装者が困る
  • 結局共通で問題なく使えるのは標準のC/C++だけではないか疑惑

26 of 41

まとめると

  • 良いパッケージマネージャがない
    • いろんなパッケージをすばやく組み合わせてアプリケーションを作成する環境がない
    • たとえ問題があってyarnpkgとか登場するようであっても、node.jsの方がマシ
    • pyenvがないとAnacondaが環境壊すんだよ!問題があっても、Pythonの方がマシ
  • 心を込めてセットアップする必要がある
    • 手で依存ライブラリのソースコードのパッケージを落としてきて
    • ビルド対象ごとにCMakeの設定ファイルを手で書いて
    • 環境を構築
  • 使えるライブラリが少ない
    • 完全にフレームワークに乗っかる
    • パッケージやライブラリではなく、生アルゴリズムを再利用する、ぐらいの気持ちで接する�

27 of 41

みなさん、ワクワクしますよね!

28 of 41

ちなみにqtpm

  • フォルダ構成やテストフレームワークを決め打ち
    • ヘッダー、ソースコード、テストフレームワーク&ランナー(QTest + CTest)
    • CMakeLists.txtを自動生成
  • ローカルフォルダ以外にファイルを置かない
    • node_modules的な
  • 作者自身があまり積極的ではない
    • パッケージをそろえたりメンテし続けたり・・・
    • 自分が必要なパッケージだけぼちぼち追加してる
  • すべてのライブラリは静的リンク
    • WebAssembly対応が楽になることを見越してる
      • emsdk isntall sdk-1.36.xで、バイナリインストールできるようになったら本気出す
      • 9ヶ月ぐらい寝てる

29 of 41

conan.io

  • 今年の1月ぐらいにでてきたパッケージマネージャ
  • マークしてなかったけど結構アクティブっぽい
  • こいつにWebAssembly対応してもらった方が良さそう
    • arch=webasmとか、compiler=emccとか?
    • Pull Requestを送るチャンス
  • とはいえ、CMakeなりを裏で実行するので、CMakeは多少読めないと厳しい雰囲気

30 of 41

WebAssemblyで何作る?

31 of 41

考えられるもの

  • ゲームを作る
  • 特殊なファイルフォーマットを扱ったり、高度な圧縮や計算をしたり
  • WebGL上にHTMLとは別のGUIの仕組みを作る

32 of 41

ゲームを作る

  • Unreal Engine 4か、Unity 3Dを使いましょう
  • 以上

33 of 41

補足すると

  • ゲームの場合はアセットのパイプライン�(3Dモデル、アニメーションなど)が一番大事
  • パッケージマネージャ問題とかを気にすることなく、必要なライブラリとかがすべて含まれた状態からスタートできる
  • 起動をなるべく高速化することにビジネス価値があるなら自作するのも価値がある

34 of 41

新ファイルフォーマットとかファイル圧縮

  • これが一番使われる用途な気がする
  • 画像とか音楽をdata-uriエンコーディングのネイティブフォーマットに変換
  • xlsxをブラウザで高速に読み書きとか
  • waifu2x的な計算、オフラインで音声/文字認識
  • みなさんも、検索エンジンをブラウザ上に実装したことがあると思いますが
    • 計算量重視のアルゴリズムは最後はビット演算の塊だったりする
    • 簡潔データ構造とかTRIEとかFM-Indexとか

35 of 41

単機能系のものが(現時点で)現実的と思う理由

  • コードとしては小さい
  • ライブラリを手で入れても大したことがないレベル

36 of 41

HTMLとは別のGUIの仕組み

  • みなさんも、OpenGL上でGUIのフレームワークとか作ったこと�ありますよね?
  • 仕組み上、HTML/CSSには勝ち目がない
    • どうがんばってもMB単位のファイルサイズになる
    • 日本語フォントは最低3MB。平均的には10MB以上。
      • SafariはOriginが違うとキャッシュを共有しない(Etagを使ったトラッキング防止?)
    • Qtが動くよ、というデモが昔あったけど、C++で静的リンクするとネイティブビルドでもランタイムサイズは50MB〜100MB以上。
  • GUIフレームワークを自分で作るにはやらなければならないことが多い

37 of 41

38 of 41

フォントレンダリング

  • みなさんもOpenTypeフォントのパーサを書いたことがありますよね?
    • TrueTypeフォントと、PostScriptフォント、PNGのキメラフォーマット
    • TrueTypeフォントは2次ベジェ曲線、PostScriptフォントは3次ベジェ曲線、絵文字はPNG
  • 普通はOSごとにキャッシュを持っている
    • 毎フレームカーブをライスタライズすると重いので、画像をキャッシュしておいて、必要なグリフの絵を再利用
    • アプリケーションにフォントレンダリングエンジンをもたせると、OSレベルのキャッシュは利用できない
  • ラスタライズしたら終わりじゃないよ
    • PangoとかHarfbuzzのコードを読んだら悶絶できます!
    • カーニング情報とか禁則情報を元にレイアウトをする

39 of 41

HTML/CSS

  • 昔ながらのGUIフレームワーク(Qt Widgetsとか)はウィジェットの親子構造で更新情報を計算する
    • コンボボックスなどのオーバーレイはOS的には別ウインドウ
  • CSSは親子構造を超えてレイアウトできる
    • position: relative, aboslute, fix
    • HTML/CSSは内部でRender Layer Treeとか、Composite Layerとか計算している
    • シンプルなCSSでプルダウンメニューとか、吹き出し、サイドバーが実現できる
    • 真似て作り込むのはつらい。力づくアプローチ(毎フレーム上書き)だとCPUが熱くなる
  • 大きなアプリケーションを作ろうとするとスタイルとコードを分けたい
    • CSSを再実装したくなってくる!
  • 頭のいい人がブラウザに作り込んでくれているんだからこれを使ったほうが

40 of 41

HTMLとは別のGUIの仕組みが欲しいケース

  • Cacooのようなビジュアルダイアグラムエディタとか、UIモック設計ツールとかならあり
  • ウィジェットほとんど出てこないようなケースならなんとか
    • 動く漫画的なコンテンツとか
    • 顧客ロイヤリティの高いブランドのゲームとか漫画とかならいけるかも
      • 低いとローディングでユーザが離脱する
      • 長期的なユーザの継続を考えても、待ち時間が長いものは敬遠されやすい
    • といっても、CDNも駆使してAMPで高速ロードをライバルとして見ると厳しい
  • できるだけHTML/CSSでUIを作って、コア部分だけWebAssembly(WebGL)という使い分けが無難では

41 of 41

まとめ

  • WebAssemblyめっちゃエキサイティングです!
    • パッケージマネージャを作るところから!
      • ライブラリを使うのはnpmほど簡単ではない
    • ビルドシステムも詳しくなろう!
      • CMakeでFizzBuzz、ズンドコキ・ヨ・シ!!
    • C++は11以降は良い子になりすぎて退屈です
    • 使いたいだけならRustとかにリソースを割いた方が現実的な気はする
  • WebAssembly(asm.js)はネイティブに比肩する性能が得られるといっても制約はある
    • フォント、レイアウト、スタイル、すべてでHTML/CSSを超えるのは厳しい
    • 単機能のヘルパー、あるいは対象をしぼったUIに特化したほうが良さげ