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="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

PDF
ゲーム開発者のための C++11/C++14
PDF
今日からできる!簡単 .NET 高速化 Tips
PDF
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
PDF
オブジェクト指向プログラミングのためのモデリング入門
PDF
20分くらいでわかった気分になれるC++20コルーチン
PDF
ワタシはSingletonがキライだ
PDF
いまさら聞けない!CUDA高速化入門
PPTX
画像処理ライブラリ OpenCV で 出来ること・出来ないこと
ゲーム開発者のための C++11/C++14
今日からできる!簡単 .NET 高速化 Tips
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
オブジェクト指向プログラミングのためのモデリング入門
20分くらいでわかった気分になれるC++20コルーチン
ワタシはSingletonがキライだ
いまさら聞けない!CUDA高速化入門
画像処理ライブラリ OpenCV で 出来ること・出来ないこと

What's hot (20)

PPTX
shared_ptrとゲームプログラミングでのメモリ管理
PPTX
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
PDF
今から始める Lens/Prism
PDF
Unityではじめるオープンワールド制作 エンジニア編
PDF
中3女子でもわかる constexpr
PDF
コルーチンでC++でも楽々ゲーム作成!
PDF
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
PDF
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
PPTX
【CEDEC2018】Scriptable Render Pipelineを使ってみよう
PDF
Dockerからcontainerdへの移行
PDF
すごい constexpr たのしくレイトレ!
PDF
【CEDEC2018】CPUを使い切れ! Entity Component System(通称ECS) が切り開く新しいプログラミング
PDF
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
PDF
.NET Core 3.0時代のメモリ管理
PPTX
20160526 依存関係逆転の原則
PDF
UniTask入門
PDF
【Unity道場 2017】PlayMakerによる初めてのUnityプログラミング
PDF
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
PDF
インタフェース完全に理解した
PDF
C++ マルチスレッドプログラミング
shared_ptrとゲームプログラミングでのメモリ管理
MVPパターンによる設計アプローチ「あなたのアプリ報連相できてますか」
今から始める Lens/Prism
Unityではじめるオープンワールド制作 エンジニア編
中3女子でもわかる constexpr
コルーチンでC++でも楽々ゲーム作成!
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
【CEDEC2018】Scriptable Render Pipelineを使ってみよう
Dockerからcontainerdへの移行
すごい constexpr たのしくレイトレ!
【CEDEC2018】CPUを使い切れ! Entity Component System(通称ECS) が切り開く新しいプログラミング
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
.NET Core 3.0時代のメモリ管理
20160526 依存関係逆転の原則
UniTask入門
【Unity道場 2017】PlayMakerによる初めてのUnityプログラミング
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
インタフェース完全に理解した
C++ マルチスレッドプログラミング
Ad

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

PDF
【学習メモ#1st】12ステップで作る組込みOS自作入門
PPTX
Power shell で DSL
PDF
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
PDF
Node.js勉強会 Framework Koa
PDF
Docker講習会資料
PPTX
Windows Azure PHP Tips
PDF
WTM53 phpフレームワーク いまさらcodeigniter
PDF
Adaptive optimization of JIT compiler
PPTX
13016 n分で作るtype scriptでnodejs
PPTX
CMake multiplatform build-tool
PDF
PEZY-SC programming overview
PDF
Clrh 20140906 lt
PPTX
Alt#0x008 2017/5/20
KEY
Lxc on cloud
PPT
Apache Module
PDF
Machine configoperatorのちょっとイイかもしれない話
PPT
NanoA
PDF
社内勉強会資料(Varnish Module)
ODP
Buffer overflow
PDF
今だからこそ知りたい Docker Compose/Swarm 入門
【学習メモ#1st】12ステップで作る組込みOS自作入門
Power shell で DSL
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
Node.js勉強会 Framework Koa
Docker講習会資料
Windows Azure PHP Tips
WTM53 phpフレームワーク いまさらcodeigniter
Adaptive optimization of JIT compiler
13016 n分で作るtype scriptでnodejs
CMake multiplatform build-tool
PEZY-SC programming overview
Clrh 20140906 lt
Alt#0x008 2017/5/20
Lxc on cloud
Apache Module
Machine configoperatorのちょっとイイかもしれない話
NanoA
社内勉強会資料(Varnish Module)
Buffer overflow
今だからこそ知りたい Docker Compose/Swarm 入門
Ad

More from 祐司 伊藤 (11)

PDF
Container Storage Interface のすべて
PDF
C/C++とWebAssemblyを利用したライブラリ開発
PDF
C++からWebRTC (DataChannel)を利用する
PDF
詳説WebAssembly
PDF
シンプル Processing !
PDF
PROCESS WARP「プロセスがデバイス間で移動する」仕組みを作る
PDF
PROCESS WARP
PDF
Webブラウザで使えるいろんな処理系
PDF
PROCESS WARP
PDF
PIAXで作る P2Pネットワーク
PDF
新しい分散実行の仕組み PROCESS WARPについて
Container Storage Interface のすべて
C/C++とWebAssemblyを利用したライブラリ開発
C++からWebRTC (DataChannel)を利用する
詳説WebAssembly
シンプル Processing !
PROCESS WARP「プロセスがデバイス間で移動する」仕組みを作る
PROCESS WARP
Webブラウザで使えるいろんな処理系
PROCESS WARP
PIAXで作る P2Pネットワーク
新しい分散実行の仕組み PROCESS WARPについて

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