狠狠撸
Submit Search
别尘蝉肠谤颈辫迟别苍で颁/颁++プログラムを飞别产ブラウザから使うまでの难所攻略
?
28 likes
?
17,688 views
祐司 伊藤
Follow
CMU #29の発表資料です。 emscriptenを利用して、C/C++アプリをHTML化する具体的な手法についてです。
Read less
Read more
1 of 34
Download now
Download to read offline
More Related Content
别尘蝉肠谤颈辫迟别苍で颁/颁++プログラムを飞别产ブラウザから使うまでの难所攻略
1.
emscriptenでC/C++プログラムを webブラウザから使うまでの 難所攻略 伊藤 祐司 2015/6/20 Creators
MeetUp #29
2.
自己紹介 伊藤 祐司 バックエンドの設計 開発 フレームワークの作成
バイナリ?テキスト変換 クローラー アルゴリズム 仮想マシン 下北沢OSSカフェでPROCESS WARPというシステムを作っています http://www.processwarp.org/ GitHub llamerada-jp facebook ito.yuuji blog http://llamerad-jp.hatenablog.com/
3.
背景?動機 PROCESS WARP 複数のマシンを接続し、プロセス転送(ライブマイ グレーション)機能を持ったアプリ実行基盤 webブラウザ、Linux、Unix上で専用VMを実行
4.
背景?動機 PROCESS WARPのコアプログラムをweb上でも動かして手 軽に使ってもらいたいけど開発に時間は掛けたくない CORE SOURCE (C++) C/C++ compiler emscripten
5.
実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
6.
http://emscripten.org/ C/C++からJavaScriptへのコンパイル(コンバート)を行 うアプリケーション C/C++のコードをLLVM IR経由でJavaScriptへ変換 標準C/C++ライブラリ, POSIX,
SDL, OpenGLが使える C/C++でブラウザアプリケーションが作れる! Alon Zakai (kripken)
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.
コンパイルの流れ 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.
LLVMとemscripten LLVM Optimizer Clang C/C++ emscripten JavaScript!
10.
できないこと マルチスレッド ソケット通信 アセンブラ 他、JavaScriptでできないこと 主要モダンブラウザではだいたい動くけどそれぞれ制 限事項(特にIE)がある http://kripken.github.io/emscripten-site/docs/ porting/guidelines/browser_limitations.html
11.
実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
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.
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.
こんにちわ
15.
実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
16.
こんにちわ
17.
見た目を変える emsdk/emscripten/<バージョン>/src/ shell_minimal.html をもとにHTMLをカスタム $ emcc
hello.c --shell-file custom.html -o hello.html console
18.
見た目を変える #canvas OpenGLを使わないなら消してし まって構わない #output Module.printからテキストが出力 されている 他もJavaScript部分と整合性を取 りながら変更してOK {{ SCRIPT }}がscriptタグに変換 される
19.
HTMLの生成をやめる デザイン変更のたびにコンパイルするのは面倒 <script async type="text/javascript" src=/slideshow/cmu29/49627641/"hello.js">とModuleがあればHTMLは直接 編集したい $
emcc hello.c -o hello.js console hello.js
20.
実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
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.
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.
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.
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.
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.
Makefileの利用 emcmake, emconfigure, emmakeを利用すると、普通のアプリ ケーションをemscriptenでコンパイルできる 未対応のライブラリに依存していたりすると上手く動かない CC,
CXX, 他の環境変数などをemscripten用に書き換えている $ ememake cmake . $ emconfigure configure $ emmake make console
27.
実際にやる前に インストールからハローワールド HTML側のカスタマイズ JavaScriptとC/C++の連携 ポインタと文字列
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.
ポインタ ポインタ = 先頭からのインデックスと考えれば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.
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.
もっと簡単にポインタ Module.getValue(<ポインタ>, <型>); Module.setValue(<ポインタ>, <値>,
<型>); JavaScript var v = Module.getValue(Module.getptr(), 'i32'); Module.setValue(Module.getptr(), v + 1, 'i32');
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.
まとめ 基本的なC/C++とJavaScript連携はだいたいできる OpenGLや、Moduleを使ったさらなる制御もできる できることと、できないことが分かった? ポインタはタダのインデックス アルゴリズムやコアは共有できてもGUI部分は別々の実 装のほうが良いと思う C/C++からDOMを操作するライブラリとかあったらど うなんでしょうね? Moduleの中を覗いてみると凄い作りだったり…
34.
以上 ありがとうございました
Download