狠狠撸

狠狠撸Share a Scribd company logo
emscriptenでC/C++プログラムを
webブラウザから使うまでの
難所攻略
伊藤 祐司
2015/6/20 Creators MeetUp #29
自己紹介
伊藤 祐司
バックエンドの設計 開発
フレームワークの作成 バイナリ?テキスト変換 クローラー
アルゴリズム 仮想マシン
下北沢OSSカフェでPROCESS WARPというシステムを作っています
http://www.processwarp.org/
GitHub llamerada-jp
facebook ito.yuuji
blog http://llamerad-jp.hatenablog.com/
背景?動機
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, SDL, OpenGLが使える
C/C++でブラウザアプリケーションが作れる!
Alon Zakai
(kripken)
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
コンパイルの流れ
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
LLVMとemscripten
LLVM
Optimizer
Clang
C/C++
emscripten
JavaScript!
できないこと
マルチスレッド
ソケット通信
アセンブラ
他、JavaScriptでできないこと
主要モダンブラウザではだいたい動くけどそれぞれ制
限事項(特にIE)がある
http://kripken.github.io/emscripten-site/docs/
porting/guidelines/browser_limitations.html
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
インストール方法
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
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
こんにちわ
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
こんにちわ
見た目を変える
emsdk/emscripten/<バージョン>/src/
shell_minimal.html をもとにHTMLをカスタム
$ emcc hello.c --shell-file custom.html -o
hello.html
console
見た目を変える
#canvas
OpenGLを使わないなら消してし
まって構わない
#output
Module.printからテキストが出力
されている
他もJavaScript部分と整合性を取
りながら変更してOK
{{ SCRIPT }}がscriptタグに変換
される
HTMLの生成をやめる
デザイン変更のたびにコンパイルするのは面倒
<script async type="text/javascript"
src=/slideshow/cmu29/49627641/"hello.js">とModuleがあればHTMLは直接
編集したい
$ emcc hello.c -o hello.js
console
hello.js
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
ループを作る
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++
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が
定義される
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++
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
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
Makefileの利用
emcmake, emconfigure, emmakeを利用すると、普通のアプリ
ケーションをemscriptenでコンパイルできる
未対応のライブラリに依存していたりすると上手く動かない
CC, CXX, 他の環境変数などをemscripten用に書き換えている
$ ememake cmake .
$ emconfigure configure
$ emmake make
console
実際にやる前に
インストールからハローワールド
HTML側のカスタマイズ
JavaScriptとC/C++の連携
ポインタと文字列
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
…… … …
ポインタ
ポインタ = 先頭からのインデックスと考えれば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]);
}
…… … …
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…… … …
もっと簡単にポインタ
Module.getValue(<ポインタ>, <型>);
Module.setValue(<ポインタ>, <値>, <型>);
JavaScript
var v = Module.getValue(Module.getptr(), 'i32');
Module.setValue(Module.getptr(), v + 1, 'i32');
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
まとめ
基本的なC/C++とJavaScript連携はだいたいできる
OpenGLや、Moduleを使ったさらなる制御もできる
できることと、できないことが分かった?
ポインタはタダのインデックス
アルゴリズムやコアは共有できてもGUI部分は別々の実
装のほうが良いと思う
C/C++からDOMを操作するライブラリとかあったらど
うなんでしょうね?
Moduleの中を覗いてみると凄い作りだったり…
以上
ありがとうございました

More Related Content

别尘蝉肠谤颈辫迟别苍で颁/颁++プログラムを飞别产ブラウザから使うまでの难所攻略