Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
emscriptenでC/C++プログラムを
webブラウザから使うまでの
難所攻略
伊藤 祐司
2015/6/20 Creators MeetUp #29
自己紹介
伊藤 祐司
バックエンドの設計 開発
フレームワークの作成 バイナリ・テキスト変換 クローラー
アルゴリズム 仮想マシン
下北沢OSSカフェでPROCESS WARPというシステムを作っています
http://www.processw...
背景・動機
PROCESS WARP
複数のマシンを接続し、プロセス転送(ライブマイ
グレーション)機能を持ったアプリ実行基盤
webブラウザ、Linux、Unix上で専用VMを実行
背景・動機
PROCESS WARPのコアプログラムをweb上でも動かして手
軽に使ってもらいたいけど開発に時間は掛けたくない
CORE
SOURCE
(C++)
C/C++
compiler
emscripten
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
http://emscripten.org/
C/C++からJavaScriptへのコンパイル(コンバート)を行
うアプリケーション
C/C++のコードをLLVM IR経由でJavaScriptへ変換
標準C/C++ライブラリ, POSIX, ...
LLVM
http://llvm.org/
コンパイラ基盤、コンパイラの共通機能(最適化など)をパッケージ
化したもの
clang C/C++/Objective-C/swiftコンパイラ
LLILC .netからの変換 by Microsof...
コンパイルの流れ
LLVM
Optimizer
Clang
dragon
egg
original
frontend
C/C++
Obj-C
Swift
Fortran
Ada
Go
original
language
-emit-llvm
x...
LLVMとemscripten
LLVM
Optimizer
Clang
C/C++
emscripten
JavaScript!
できないこと
マルチスレッド
ソケット通信
アセンブラ
他、JavaScriptでできないこと
主要モダンブラウザではだいたい動くけどそれぞれ制
限事項(特にIE)がある
http://kripken.github.io/emscripten-...
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
インストール方法
LinuxやOSXではPortable SDKを使うのが一番良い
renv, nodebrewのように複数バージョンを依存アプリ
(clang, node.js)込みでよしなに管理してくれる
https://kripken.g...
Hello world
// emscriptenのヘッダファイル
#include <emscripten.h>
int main(int argc, char* argv[]) {
printf("hello world.”);
retur...
こんにちわ
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
こんにちわ
見た目を変える
emsdk/emscripten/<バージョン>/src/
shell_minimal.html をもとにHTMLをカスタム
$ emcc hello.c --shell-file custom.html -o
hello.ht...
見た目を変える
#canvas
OpenGLを使わないなら消してし
まって構わない
#output
Module.printからテキストが出力
されている
他もJavaScript部分と整合性を取
りながら変更してOK
{{ SCRIPT }}...
HTMLの生成をやめる
デザイン変更のたびにコンパイルするのは面倒
<script async type="text/javascript"
src="hello.js">とModuleがあればHTMLは直接
編集したい
$ emcc hell...
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
ループを作る
main内で無限ループを回すとブラウザへ処理が戻らない
普通のJavaScriptであればsetTimeout
emscripten_set_main_loop(<関数>, <FPS>, true);を利用
#include <e...
emscriptenとネイティブ
でコードを切り替える
#include <emscripten.h>
void main_loop() {
// メイン処理をココに
}
int main(int argc, char* argv[]) {
/...
C/C++からJavaScriptを
呼び出す
インラインアセンブラはJavaScriptとして実行される
(固定機能)
void emscripten_run_script(<JavaScript>);で渡した
文字列をJavaScriptと...
JavaScriptから
C/C++関数を呼び出す
embind機能でJavaScriptから呼び出す関数を指定しておく
引数、戻り値は変換される(※構造体はNG)
https://kripken.github.io/emscripten-si...
JavaScriptから
C/C++関数を呼び出す
sample.jsが読み込まれた後から利用可能になるので、
onloadの中などでは利用できない
コンパイルオプションに-s EXPORT_ALL=1を指定すると
全ての関数がexportされ...
Makefileの利用
emcmake, emconfigure, emmakeを利用すると、普通のアプリ
ケーションをemscriptenでコンパイルできる
未対応のライブラリに依存していたりすると上手く動かない
CC, CXX, 他の環境変...
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
int value1 = 1192; // 0x04a8
short value2 = 758; // 0x02f6
char value3 = -1; // 0xff
char value4 = 99; // 0x63
メモリ空間
emscr...
ポインタ
ポインタ = 先頭からのインデックスと考えればOK
ポインタはembindで変換されないのでunsigned intにキャスト
int value1 = 1192; // 0x04a8
short value2 = 758; // 0...
for (int i = 0; i < 2; i ++) {
console.log(Module.HEAPU32[Module.getptr() / 4 + i]);
}
for (int i = 0; i < 4; i ++) {
cons...
もっと簡単にポインタ
Module.getValue(<ポインタ>, <型>);
Module.setValue(<ポインタ>, <値>, <型>);
JavaScript
var v = Module.getValue(Module.getp...
console.log(Pointer_stringify(Module.getptr()));
文字列
C/C++からJavaScriptで文字列を授受するときはポインタを使う場合が
多い
Pointer_stringify(<ポインタ>[,...
まとめ
基本的なC/C++とJavaScript連携はだいたいできる
OpenGLや、Moduleを使ったさらなる制御もできる
できることと、できないことが分かった?
ポインタはタダのインデックス
アルゴリズムやコアは共有できてもGUI部分は別...
以上
ありがとうございました
Upcoming SlideShare
Loading in …5
×

emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略

CMU #29の発表資料です。
emscriptenを利用して、C/C++アプリをHTML化する具体的な手法についてです。

  • Login to see the comments

emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略

  1. 1. emscriptenでC/C++プログラムを webブラウザから使うまでの 難所攻略 伊藤 祐司 2015/6/20 Creators MeetUp #29
  2. 2. 自己紹介 伊藤 祐司 バックエンドの設計 開発 フレームワークの作成 バイナリ・テキスト変換 クローラー アルゴリズム 仮想マシン 下北沢OSSカフェでPROCESS WARPというシステムを作っています http://www.processwarp.org/ GitHub llamerada-jp facebook ito.yuuji blog http://llamerad-jp.hatenablog.com/
  3. 3. 背景・動機 PROCESS WARP 複数のマシンを接続し、プロセス転送(ライブマイ グレーション)機能を持ったアプリ実行基盤 webブラウザ、Linux、Unix上で専用VMを実行
  4. 4. 背景・動機 PROCESS WARPのコアプログラムをweb上でも動かして手 軽に使ってもらいたいけど開発に時間は掛けたくない CORE SOURCE (C++) C/C++ compiler emscripten
  5. 5. 実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
  6. 6. http://emscripten.org/ C/C++からJavaScriptへのコンパイル(コンバート)を行 うアプリケーション C/C++のコードをLLVM IR経由でJavaScriptへ変換 標準C/C++ライブラリ, POSIX, SDL, OpenGLが使える C/C++でブラウザアプリケーションが作れる! Alon Zakai (kripken)
  7. 7. LLVM http://llvm.org/ コンパイラ基盤、コンパイラの共通機能(最適化など)をパッケージ 化したもの clang C/C++/Objective-C/swiftコンパイラ LLILC .netからの変換 by Microsoft https://github.com/dotnet/llilc その他、gnuコンパイラをフロントエンドとし多数の言語を処理可能 Fortran, Ada, Go http://dragonegg.llvm.org 開発が非常に活発 Chris Lattner
  8. 8. コンパイルの流れ LLVM Optimizer Clang dragon egg original frontend C/C++ Obj-C Swift Fortran Ada Go original language -emit-llvm x86 backend ARM backend iPhone Android Raspberry Pi PC objectfile for
  9. 9. LLVMとemscripten LLVM Optimizer Clang C/C++ emscripten JavaScript!
  10. 10. できないこと マルチスレッド ソケット通信 アセンブラ 他、JavaScriptでできないこと 主要モダンブラウザではだいたい動くけどそれぞれ制 限事項(特にIE)がある http://kripken.github.io/emscripten-site/docs/ porting/guidelines/browser_limitations.html
  11. 11. 実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
  12. 12. インストール方法 LinuxやOSXではPortable SDKを使うのが一番良い renv, nodebrewのように複数バージョンを依存アプリ (clang, node.js)込みでよしなに管理してくれる https://kripken.github.io/emscripten-site/docs/ getting_started/downloads.html $ tar vzxf emsdk-protable.tar.gz $ cd emsdk_portable $ ./emsdk install latest $ ./emsdk activate latest $ source emsdk_env.sh 実行前に環境変数を設定 デフォルトのコンパイラがemsdk のインストールしたclangになる console
  13. 13. Hello world // emscriptenのヘッダファイル #include <emscripten.h> int main(int argc, char* argv[]) { printf("hello world.”); return 0; } hello.c $ emcc hello.c -o hello.html console hello.html hello.js
  14. 14. こんにちわ
  15. 15. 実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
  16. 16. こんにちわ
  17. 17. 見た目を変える emsdk/emscripten/<バージョン>/src/ shell_minimal.html をもとにHTMLをカスタム $ emcc hello.c --shell-file custom.html -o hello.html console
  18. 18. 見た目を変える #canvas OpenGLを使わないなら消してし まって構わない #output Module.printからテキストが出力 されている 他もJavaScript部分と整合性を取 りながら変更してOK {{ SCRIPT }}がscriptタグに変換 される
  19. 19. HTMLの生成をやめる デザイン変更のたびにコンパイルするのは面倒 <script async type="text/javascript" src="hello.js">とModuleがあればHTMLは直接 編集したい $ emcc hello.c -o hello.js console hello.js
  20. 20. 実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
  21. 21. ループを作る main内で無限ループを回すとブラウザへ処理が戻らない 普通のJavaScriptであればsetTimeout emscripten_set_main_loop(<関数>, <FPS>, true);を利用 #include <emscripten.h> void main_loop() { // メイン処理をココに } int main(int argc, char* argv[]) { // 初期化処理とか // メインループを登録 emscripten_set_main_loop(main_loop, 0, true); return 0; } C/C++
  22. 22. emscriptenとネイティブ でコードを切り替える #include <emscripten.h> void main_loop() { // メイン処理をココに } int main(int argc, char* argv[]) { // 初期化処理とか #ifdef EMSCRIPTEN // メインループを登録 emscripten_set_main_loop(main_loop, 0, true); #else // メインループを呼び出し while(true) main_loop(); #endif return 0; } C/C++ emscriptenでコンパイルする場合、EMSCRIPTENが 定義される
  23. 23. C/C++からJavaScriptを 呼び出す インラインアセンブラはJavaScriptとして実行される (固定機能) void emscripten_run_script(<JavaScript>);で渡した 文字列をJavaScriptとして実行 JavaScriptのeval();のような動作 int emscripten_run_script_int(); std::string emscripten_run_script_string(); int r = emscripten_run_script_int("screen.width"); C/C++
  24. 24. JavaScriptから C/C++関数を呼び出す embind機能でJavaScriptから呼び出す関数を指定しておく 引数、戻り値は変換される(※構造体はNG) https://kripken.github.io/emscripten-site/docs/ porting/connecting_cpp_and_javascript/ embind.html#built-in-type-conversions #include <math.h> #include <emscripten.h> #include <emscripten/bind.h> // ヘッダ using namespace emscripten; // 名前空間 double _pow(double a, int b) { return pow(a, b); } EMSCRIPTEN_BINDINGS(mod) { function("c_pow", &_pow); // Module.c_pow(); } sample.cpp
  25. 25. JavaScriptから C/C++関数を呼び出す sample.jsが読み込まれた後から利用可能になるので、 onloadの中などでは利用できない コンパイルオプションに-s EXPORT_ALL=1を指定すると 全ての関数がexportされるがjsファイルが巨大になる $ em++ sample.cpp --bind -o sample.js console var p = Module.c_pow(3.14, 2); JavaScript
  26. 26. Makefileの利用 emcmake, emconfigure, emmakeを利用すると、普通のアプリ ケーションをemscriptenでコンパイルできる 未対応のライブラリに依存していたりすると上手く動かない CC, CXX, 他の環境変数などをemscripten用に書き換えている $ ememake cmake . $ emconfigure configure $ emmake make console
  27. 27. 実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
  28. 28. int value1 = 1192; // 0x04a8 short value2 = 758; // 0x02f6 char value3 = -1; // 0xff char value4 = 99; // 0x63 メモリ空間 emscriptenでは、C/C++の変数をArrayBufferで作った擬似 的なメモリ空間に保存している Module.HEAPU8などDataViewでアクセスできる ビッグエンディアン C/C++ 00 00 04 a8 02 f6 ff 63 Memory …… … …
  29. 29. ポインタ ポインタ = 先頭からのインデックスと考えればOK ポインタはembindで変換されないのでunsigned intにキャスト int value1 = 1192; // 0x04a8 short value2 = 758; // 0x02f6 char value3 = -1; // 0xff char value4 = 99; // 0x63 return (unsigned int)(&value1); // unsigned int getptr(); C/C++ a8 04 00 00 f6 02 ff 63 JavaScriptfor (int i = 0; i < 8; i ++) { console.log(Module.HEAPU8[Module.getptr() + i]); } …… … …
  30. 30. for (int i = 0; i < 2; i ++) { console.log(Module.HEAPU32[Module.getptr() / 4 + i]); } for (int i = 0; i < 4; i ++) { console.log(Module.HEAPU16[Module.getptr() / 2 + i]); } intやshortでアクセス 000004a8 63ff02f6 JavaScript … … 04a8 0000 02f6 63ff JavaScript … … a8 04 00 00 f6 02 ff 63…… … …
  31. 31. もっと簡単にポインタ Module.getValue(<ポインタ>, <型>); Module.setValue(<ポインタ>, <値>, <型>); JavaScript var v = Module.getValue(Module.getptr(), 'i32'); Module.setValue(Module.getptr(), v + 1, 'i32');
  32. 32. console.log(Pointer_stringify(Module.getptr())); 文字列 C/C++からJavaScriptで文字列を授受するときはポインタを使う場合が 多い Pointer_stringify(<ポインタ>[, <長さ>]);を使って文字列を取り出す JavaScriptからC/C++へ文字列を渡す場合、引数の型をstd::stringにし ておくとemscriptenで変換される unsigned int getptr() { char* str = "hello world!"; return (unsigned int)(&str); } C/C++ JavaScript
  33. 33. まとめ 基本的なC/C++とJavaScript連携はだいたいできる OpenGLや、Moduleを使ったさらなる制御もできる できることと、できないことが分かった? ポインタはタダのインデックス アルゴリズムやコアは共有できてもGUI部分は別々の実 装のほうが良いと思う C/C++からDOMを操作するライブラリとかあったらど うなんでしょうね? Moduleの中を覗いてみると凄い作りだったり…
  34. 34. 以上 ありがとうございました

×