hello, c++ + javascript world! - boost.勉強会 #11 東京
DESCRIPTION
Boost.勉強会 #11 東京(http://partake.in/events/e75cde86-75c8-47ce-b647-2dbd0495b053)で発表した資料です。補足資料はこちら: http://d.hatena.ne.jp/hecomi/20130604/1370356501TRANSCRIPT
++ + C++ と JavaScript で広がる世界
@hecomi
Boost.勉強会 #11 東京
Introduction • C++ と JavaScript が関連するお話について、 広く浅く簡単に世界観を紹介したいと思います
Introduction • 対象者
– C++, JavaScript 知ってる人・興味がある人
• 内容
– C++ と JS が関連した技術群それぞれについて、
Hello world に毛が生えたくらいの内容を紹介します
– ちなみに Boost 成分 1 ㍉ もありません…
自己紹介 • Name : @hecomi
• Blog : http://d.hatena.ne.jp/hecomi/
自己紹介 – 未来っぽいお部屋
Node.js 上で動作する自作 C++ モジュールと組み合わせて作った未来っぽいお部屋
目次 • C++ + JS の世界感
• V8
• Node.js
• Qt Quick
• Native Client
• Emscripten
C++ + JS の世界感
Browser Browser
JavaScript と言えばブラウザ…
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
C++ で書かれている!
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
ブラウザ以外でも…
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
他にも有名ドコロで…
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
アプリケーション開発
フレームワーク
他にも有名ドコロで…
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
アプリケーション開発
フレームワーク
NativeClient
ネイティブアプリをブラウザ上で動かす
ブラウザの話に戻ると…
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
アプリケーション開発
フレームワーク
NativeClient
ネイティブアプリをブラウザ上で動かす
Emscripten
C++ を JS に変換
ブラウザの話に戻ると…
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
mobile
JavaScript
Java
C++
JNI
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
アプリケーション開発
フレームワーク
NativeClient
ネイティブアプリをブラウザ上で動かす
Emscripten
C++ を JS に変換
モバイル周りは更に色々ありますが省略
ex.) Android
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
アプリケーション開発
フレームワーク
NativeClient
ネイティブアプリをブラウザ上で動かす
Emscripten
C++ を JS に変換 mobile
JavaScript
Java
C++
JNI
ex.) Android
C++ + JS の世界感
Browser Browser
JavaScript
エンジン
ゲーム用途
例: SimCity (WebKit + v8 で UI
を記述)
サーバサイド
JavaScript
アプリケーション開発
フレームワーク
NativeClient
ネイティブアプリをブラウザ上で動かす
Emscripten
C++ を JS に変換 mobile
JavaScript
Java
C++
JNI
ex.) Android
V8 Chrome でおなじみの JavaScript エンジン
内容 • Introduction
• V8 を使った JS の実行
• C++ の関数 à JavaScript の関数
• C++ のクラス à JavaScript のクラス
Introduction • V8 は、Chrome にも搭載されている C++ で書かれた JavaScript エンジン
その他のオープンなエンジンには SpiderMonkey (C),
Rhino (Java), JavaScriptCore (C++) 等があります
Introduction - インストール
h#ps://github.com/v8/v8
or
% brew install v8
% sudo ap;tude install libv8-‐dev
動かしてみる
V8 を使った JS の実行
※ 最近は Context.Dispose で‘ Isolate を引数に指定しない場合は Warning が出るようになったようです
Sample Code
この辺りは何となく 分かるけど…
V8 を使った JS の実行
Context??
• 独立した JS をある V8 インスタンスの中で実行する環境
• JS は built-in 変数/関数も書換可能なのでグローバル空間を分離
• 2 つ目以降の Context の生成はローコストで可能
• iframe とかイメージすると分かりやすいです
Context
Context A
Built-in func / obj
Custom func / obj
Context B
Built-in func / obj
Custom func / obj
V8 を使った JS の実行
Handle??
Handle • ヒープ内の JS オブジェクトの位置の参照
– GC する度に JS オブジェクトの実体のヒープ位置は変わってしまうので
– JS の世界の変数とのやり取りはこの Handle を通じて行う
• Local Handle と Persistent Handle の 2 種類がある – Local の寿命は Handle Scope で決定
– Persistent は明示的に Dispose するまで破棄されない
Heap
“hogehoge” 100
Function Handle Scope
Local<String>
Local<Number>
Persistent<Function>
V8 を使った JS の実行
Persistent ハンドルを返す
Local ハンドルを返す
関数を追加したい!
こんな風にやります
こんな風にやります
この戻り値、引数で関数をつくります
こんな風にやります
Value は JS の基本型(Number, Array, Object…) の基底クラスで、IsNumber() 等で型を確かめ、ToNumber() 等でアップキャスト出来ます。
Arguments は各引数(Value 型)に [ ] 演算子でアクセスでき、This や Callee などを参照できます。
こんな風にやります
Context 生成時に global オブジェクト を指定することができます。
こんな風にやります
“print” という関数を JS で呼ぶと、 ↑の print が実行されるように global オブジェクトにセットします
こんな風にやります
$ clang++ print_test.cpp –o print_test$ ./print_test100 + 200 = 300
実行 :
lambda 版
クラスを追加したい!
クラスの追加 概要
myClass の internal field に void* で保存 が呼ばれ、
C++ 側であらかじめ登録しておいた関数内で、
プロパティの読み書きやメソッド呼び出しのタイミングで、
事前に登録しておいた C++ の関数が呼ばれる。その内部では、 void* から my_class* へキャストして、メンバ変数 hoge の 読み書きや、メンバ関数 piyo() の呼び出しをする。
例えばこんなクラスを…
例えばこんなクラスを…
メンバ変数
setter / getter
例えばこんなクラスを…
なんか凄いことするメンバ関数
こんな風にします
こんな風にします
クラス内部の static 関数経由でのみ 呼ばれるようになるので private 化
setter / getter を JS 側から 呼ばれる形に変換
こんな風にします
JS の世界へ送り出す処理を記述
JS 側で new された時と GC された時の処理
piyo を JS 側から 呼べるようにする
JS の世界とつなぐ処理
my_class::ctor を元にした関数を作成
JS の世界とつなぐ処理
JS のインスタンス変数、プロトタイプ変数 に相当する変数を取得
JS の世界とつなぐ処理
そこへプロパティや そのアクセサをセットしたり
メソッドをセット したりします
JS の世界とつなぐ処理
この関数をグローバル空間に追加します
JS の世界とつなぐ処理
さっきは飛ばしましたが、ここでは 内部に JS からは見えない フィールドを 1 個作成しています
new 時に呼ばれるコンストラクタを見てみます
JS の世界とつなぐ処理
こんな風 this オブジェクトに インスタンスを埋め込みます
( 0 はインデックス )
JS の世界とつなぐ処理
参照されなくなったら削除する処理を書きます
JS の世界とつなぐ処理
getter / setter では内部に保存した インスタンスを取り出して使います
JS の世界とつなぐ処理
getter / setter では内部に保存した インスタンスを取り出して使います
JS の世界とつなぐ処理
メソッドでも同じです
JS の世界とつなぐ処理
$ ./hellohogehoge から fuga に書き換えられました fugapiyopiyo
実行 :
参考文献 • Chrome V8 Embedder’s Guide
– https://developers.google.com/v8/embed?hl=ja
NODE.JS サーバサイド JavaScript 環境
内容 • Introduction
• Node.js の世界観
• C++ モジュールの作成
Introduction • V8 をエンジンとして利用したサーバサイドの
JavaScript プラットフォーム
• ブラウザの JavaScript では出来なそうなことが色々簡単に出来る環境です
Introduction • ファイルを読み込んだり…
Introduction • HTTP サーバを立てたり…
Introduction • HTTP サーバを立てたり…
h#p://nodejs.jp/nodejs.org_ja/
Introduction - インストール
h#ps://github.com/hokaccha/nodebrew
or
バージョン指定出来るのでこっちがオススメ
Node.js の世界観
JS でつくりたいもの
Node.js の世界観
JS でつくりたいもの
コアモジュール
fs, h#p などの組み込みモジュール
Node.js の世界観
JS でつくりたいもの
コアモジュール
npm モジュール
$ npm install hoge で追加できるモジュール
fs, h#p などの組み込みモジュール
※ Node Packaged Modules
31,184 個 (2013/05/31 時点) も
登録されている。
WebSocket を使ったり、DB とつないだり、各サービスにアクセスしたり…
Node.js の世界観
JS でつくりたいもの
コアモジュール
npm モジュール 自作モジュール
$ npm install hoge で追加できるモジュール
fs, h#p などの組み込みモジュール
Node.js の世界観
未来っぽいお部屋
コアモジュール
npm モジュール 自作モジュール
twi#er, socket.io, express, serialport, …
fs, h#p などの組み込みモジュール
音声認識、発話、各種ガジェット操作、…
例えば冒頭紹介した
Node.js の世界観
未来っぽいお部屋
コアモジュール
npm モジュール 自作モジュール
twi#er, socket.io, express, serialport, …
fs, h#p などの組み込みモジュール
C++ と組み合わせれば 出来ることの幅が拡がる!
音声認識、発話、各種ガジェット操作、…
例えば冒頭紹介した
どうやって作るの?
C++ モジュールの作成
C++ モジュールの作成
JS の世界へ送り出す関数
Node.js の世界へ C++ の 関数を送り出す処理
C++ モジュールの作成
v8 で global に関数をセットした時と 同じ形に展開
C++ モジュールの作成
hello という名前のモジュールを作成 & JS 側へ変数/関数をセットする関数を指定(init)
C++ モジュールの作成
hello という名前のモジュールを作成 & JS 側へ変数/関数をセットする関数を指定(init)
C++ モジュールの作成
$ npm install node-gyp -g$ node-gyp configure build
binding.gyp
コンパイル :
先ほどと同じモジュール名
gyp (generate your projects) 用の 設定を json 形式で記述
ビルドは node 用の gyp (node-gyp) を用いる
C++ モジュールの作成
$ node helloworld
hello.js
実行 :
C++ モジュールの作成
$ node helloworld
hello.js
実行 :
参考文献 • Node.js マニュアル & ドキュメンテーション
– http://nodejs.jp/nodejs.org_ja/api/addons.html
QT QUICK UI 記述言語 QML でクロスプラットフォームアプリを簡単に作成
内容 • Introduction
• QML の例
• C++ バインディング
Introduction • Qt
– C++ で書かれたクロスプラットフォーム対応のアプリケーション開発フレームワーク
• 実績: Skype / Google Earth / Photoshop Elements
• Qt Quick
– C++ でなく QML という JavaScriptをベースにした言語で
UI 周りを記述する環境
• Qt 4.x (Qt Quick 1) では WebKit の JavaScriptCore がエンジンだったが、Qt 5 (Qt Quick 2) からは V8 がエンジンになりました
Introduction • インストール
– 開発には C++ と JS の世界をまたがってコード補完してくれる Qt Creator が便利です
• http://qt-project.org/downloads
QML の例
ProgressBar.qml main.qml
QML の例
ProgressBar.qml main.qml
JS が使える!
QML の例
ProgressBar.qml main.qml
プロパティの値でも!
QML の例
ProgressBar.qml main.qml
プログレスバーつき WebView
QML の例
ProgressBar.qml main.qml
プログレスバーつき WebView 簡単!
C++ バインディング
• QML だけでは込み入ったことは出来ない
– 例えばローカルファイル IO とか
• そこで C++ バインディング!
C++ バインディング
• 色々な方法がある
– QML の要素を C++ で使う
– QML の関数を C++ から呼ぶ
– C++ のクラスを QML から使う
– C++ で QML で使える型を定義する
C++ バインディング
• 色々な方法がある
– QML の要素を C++ で使う
– QML の関数を C++ から呼ぶ
– C++ のクラスを QML から使う
– C++ で QML で使える型を定義する
その他の方法については以下を参照!:
http://d.hatena.ne.jp/hecomi/20130503/1367594609
JS に関係する所
QML の関数を C++ から呼ぶ
C++ QML
QML の関数を C++ から呼ぶ
arr と obj を受け取り output に出力する関数
C++ QML
QML の関数を C++ から呼ぶ
QMLを表示 C++ QML
QML の関数を C++ から呼ぶ
配列と オブジェクト を作成
C++ QML
QML の関数を C++ から呼ぶ
setText を呼ぶ!
C++ QML
QML の関数を C++ から呼ぶ
setText を呼ぶ!
C++ QML
QML の関数を C++ から呼ぶ
setText を呼ぶ!
簡単!
C++ QML
C++ のクラスを QML から使う
myclass.h
main.qml
main.cpp
C++ のクラスを QML から使う
myclass.h
main.qml
main.cpp
my という名前で MyClass をセット
C++ のクラスを QML から使う
myclass.h
main.qml
main.cpp
my という名前で MyClass をセット
そのまま使える!
C++ のクラスを QML から使う
myclass.h
main.qml
main.cpp
超簡単!
C++ のクラスを QML から使う
myclass.h
main.qml
main.cpp
超簡単!
このオマジナイは何?
moc
• Qt には Meta Object Compiler (moc) というツールがある
• qmake すると C++ から C++ を吐き出す
– Q_INVOKABLE や signal / slot などのキーワードをアノーテーションとして解釈してコードを生成 • キーワードは C++ に影響を与えないよう define されている
– Q_OBJECT はそこに必要な幾つかのメンバを展開する
• 例えば qt_static_metacall という静的なメンバ関数を展開、この中で Q_INVOKABLE のついたメンバ関数を呼ぶ
自動生成されたコード例
moc_myclass.cpp
myclass.h 内の Q_OBJECT で qt_static_metacall の宣言が生成され、
定義は別途生成された moc_myclass.cpp にて行われる。
ここで呼ばれる
参考文献
• Using QML Bindings in C++ Applications
– http://harmattan-dev.nokia.com/docs/platform-api-
reference/xml/daily-docs/libqt4/qtbinding.html
• QtQuick での C++ × QML バインディングについてまとめてみた
– http://d.hatena.ne.jp/hecomi/20130503/1367594609
NATIVE CLIENT ブラウザ上でネイティブアプリを動かす
内容 • Introduction
• Hello World を動かしてみる
Introduction • Native Client (NaCl: 塩) はブラウザ上で安全にネイティブコードを実行
– サンプル: https://developers.google.com/showcase/
• JS とやり取りも出来る!
Chrome extension としても利用可能
(↑ SSH Client が動く Secure Shell)
Install • 参照
– Native Client の導入と Hello World までのまとめ
• http://d.hatena.ne.jp/hecomi/20130128/1359372772
Native Client の世界観 ①
HTML
nmf
C++
nexe
make
アーキの振り分け
embed タグを起点としてロード
Native Client の世界観 ②
NaCl Pepper API JavaScript
ローカルファイル IO
2D/3D グラフィックス (OpenGL ES 2.0)
オーディオ
マウス/キーボード/
ゲームパッド
等々…
Pepper Plugin API (PPAPI) を経由して
ブラウザを超えた機能にアクセスする
Native Client の世界観 ②
NaCl Pepper API
NaCl (塩) に対し Pepper (胡椒)
JavaScript
ローカルファイル IO
2D/3D グラフィックス (OpenGL ES 2.0)
オーディオ
マウス/キーボード/
ゲームパッド
等々…
Pepper Plugin API (PPAPI) を経由して
ブラウザを超えた機能にアクセスする
Native Client の世界観 ③
JavaScript C++
PostMessage()
postMessage()
HandleMessage
‘message’ Event Listener
Hello World を動かしてみる
Hello World を動かしてみる
まず embed タグ生成時に pp::CreateModule が呼ばれる
pp::Module* を返すので継承したクラスを作成
Hello World を動かしてみる
pp::Module::CreateInstance が呼ばれる
Hello World を動かしてみる
pp::Instance* を返すので 継承したクラスを作成する
Hello World を動かしてみる
Hello World を動かしてみる
JavaScript からのメッセージを受け取る
Hello World を動かしてみる
渡されたメッセージの処理
Hello World を動かしてみる
JS からのメッセージを受け取ったので 今度は JS 側へメッセージを送ってみる
Hello World を動かしてみる
Hello World を動かしてみる
読み込まれたら ‘hello’ を C++ 側へ送る (HandleMessage が呼ばれる)
Hello World を動かしてみる
C++ 側からのメッセージを受け取る (HandleMessage 内の PostMessage)
Hello World を動かしてみる
C++ 側からのメッセージを受け取る (HandleMessage 内の PostMessage)
参考文献 • Native Client の導入と Hello World までのまとめ
– http://d.hatena.ne.jp/hecomi/20130128/1359372772
• Native Client — Google Developers
– https://developers.google.com/native-client/
EMSCRIPTEN C++ のコードを JavaScript へ変換
内容 • Introduction
• 変換して動かしてみる
Introduction • LLVM-IR を JavaScript に変換!
– LLVM … Clang のバックエンドにもなっているコンパイラ基盤
– LLVM-IR … LLVM の中間表現
LLVM のロゴかこいい
Introduction
C++ LLVM-IR JavaScript Clang Emscripten
Introduction • 色々なものが変換されています
– https://github.com/kripken/emscripten/wiki
Introduction • 色々なものが変換されています
– https://github.com/kripken/emscripten/wiki
mruby
Introduction • 色々なものが変換されています
– https://github.com/kripken/emscripten/wiki
mruby
gnuplot
Introduction • 色々なものが変換されています
– https://github.com/kripken/emscripten/wiki
mruby
gnuplot
unreal engine
Introduction • 色々なものが変換されています
– https://github.com/kripken/emscripten/wiki
mruby
gnuplot
unreal engine
Qt
インストール • 参照
– Emscripten で C++ の Hello World を JavaScript に変換してみた
• http://d.hatena.ne.jp/hecomi/20130416/1366124901
Hello world を変換してみる
hello.cpp
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
hello.cpp
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
$ em++ hello.cpp –o hello.html$ open hello.html
hello.cpp
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
$ em++ hello.cpp –o hello.html$ open hello.html
hello.cpp
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
$ em++ hello.cpp –o hello.html$ open hello.html
hello.cpp
( ^ω^)
⊃ cpp ⊂ ここに cpp があるじゃろ?
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
$ em++ hello.cpp –o hello.html$ open hello.html
hello.cpp
( ^ω^)
≡⊃⊂≡ これを em++ すると…
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
$ em++ hello.cpp –o hello.html$ open hello.html
main 関数
hello.cpp hello.js
( ^ω^)
⊃ ⊂ こうじゃ
Hello world を変換してみる
$ em++ hello.cpp –o hello.js$ node hello.jsHello, world!
$ em++ hello.cpp –o hello.html$ open hello.html
main 関数
123536 行!
hello.js hello.cpp
( ^ω^)
⊃ ⊂ こうじゃ
速度どうなの? • 普通に JS 書くよりは数倍程度遅い…、が、
速度どうなの? • Emscripten は asm.js 形式の js を吐き出す
– asm.js は JavaScript を拡張せずに型付をして高速化をはかる JavaScript のサブセット
– ex.
(x + y) | 0 // int32
• asm.js 実装した JS エンジン OdinMonkey を積む Firefox (nightly) でデモ動かすとヌルヌル
– http://www.unrealengine.com/html5/
速度どうなの?
参考文献 • “実戦”Emscripten
– http://www.mozilla.jp/static/docs/events/vision/2012/06-ushiroad.pdf
• asm.js spec
– http://asmjs.org/spec/latest/
• BIG WEB APP? COMPILE IT!
– http://kripken.github.io/mloc_emscripten_talk/
まとめ • C++ と JavaScript が関連する世界を幾つか紹介
– V8
– Node.js
– Qt Quick
– NaCl
– Emscripten
• コレ以外にも色々あると思いますのでご存知でしたら教えて下さい m(_ _)m
++ + C++ と JavaScript で広がる世界
@hecomi
Boost.勉強会 #11 東京