Hello, Emscripten World!
Posted on 3月 22nd, 2013 by cx20
Emscripten
Emscripten は LLVM アセンブリコードより JavaScript のコードを生成する変換ツールである。
clang/clang++ を用いることにより C/C++ より JavaScript へのコード変換が可能となっている。
ソースコード(C言語)
#include <stdio.h>
int main( int argc, char* argv[] )
{
printf( "Hello, Emscripten World!\n" );
return 0;
} |
#include <stdio.h>
int main( int argc, char* argv[] )
{
printf( "Hello, Emscripten World!\n" );
return 0;
}
上記コードを LLVM に変換した場合、以下のコードが生成される。
ソースコード(LLVM Assembler)
; ModuleID = 'hello.c'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32"
target triple = "i686-w64-mingw32"
@str = private unnamed_addr constant [25 x i8] c"Hello, Emscripten World!\00"
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
%puts = tail call i32 @puts(i8* getelementptr inbounds ([25 x i8]* @str, i32 0, i32 0))
ret i32 0
}
declare i32 @puts(i8* nocapture) nounwind |
; ModuleID = 'hello.c'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32"
target triple = "i686-w64-mingw32"
@str = private unnamed_addr constant [25 x i8] c"Hello, Emscripten World!\00"
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
%puts = tail call i32 @puts(i8* getelementptr inbounds ([25 x i8]* @str, i32 0, i32 0))
ret i32 0
}
declare i32 @puts(i8* nocapture) nounwind
上記コードを JavaScript に変換した場合、以下のコードが生成される。
ソースコード(JavaScript)
(中略)
:
var FUNCTION_TABLE = [0, 0];
function _main($argc, $argv) {
var label = 0;
var $puts=_puts(((5242880)|0));
return 0;
}
Module["_main"] = _main;
// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
var i64Math = null;
// === Auto-generated postamble setup entry stuff ===
Module.callMain = function callMain(args) {
var argc = args.length+1;
function pad() {
for (var i = 0; i < 4-1; i++) {
argv.push(0);
}
}
var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_STATIC) ];
pad();
for (var i = 0; i < argc-1; i = i + 1) {
argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_STATIC));
pad();
}
argv.push(0);
argv = allocate(argv, 'i32', ALLOC_STATIC);
var ret;
ret = Module['_main'](argc, argv, 0);
return ret;
}
function run(args) {
args = args || Module['arguments'];
if (runDependencies > 0) {
Module.printErr('run() called, but dependencies remain, so not running');
return 0;
}
if (Module['preRun']) {
if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
var toRun = Module['preRun'];
Module['preRun'] = [];
for (var i = toRun.length-1; i >= 0; i--) {
toRun[i]();
}
if (runDependencies > 0) {
// a preRun added a dependency, run will be called later
return 0;
}
}
function doRun() {
var ret = 0;
calledRun = true;
if (Module['_main']) {
preMain();
ret = Module.callMain(args);
if (!Module['noExitRuntime']) {
exitRuntime();
}
}
if (Module['postRun']) {
if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
while (Module['postRun'].length > 0) {
Module['postRun'].pop()();
}
}
return ret;
}
if (Module['setStatus']) {
Module['setStatus']('Running...');
setTimeout(function() {
setTimeout(function() {
Module['setStatus']('');
}, 1);
doRun();
}, 1);
return 0;
} else {
return doRun();
}
}
Module['run'] = Module.run = run;
// {{PRE_RUN_ADDITIONS}}
if (Module['preInit']) {
if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
while (Module['preInit'].length > 0) {
Module['preInit'].pop()();
}
}
initRuntime();
var shouldRunNow = true;
if (Module['noInitialRun']) {
shouldRunNow = false;
}
if (shouldRunNow) {
var ret = run();
}
// {{POST_RUN_ADDITIONS}}
// {{MODULE_ADDITIONS}}
// EMSCRIPTEN_GENERATED_FUNCTIONS: ["_main"] |
(中略)
:
var FUNCTION_TABLE = [0, 0];
function _main($argc, $argv) {
var label = 0;
var $puts=_puts(((5242880)|0));
return 0;
}
Module["_main"] = _main;
// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
var i64Math = null;
// === Auto-generated postamble setup entry stuff ===
Module.callMain = function callMain(args) {
var argc = args.length+1;
function pad() {
for (var i = 0; i < 4-1; i++) {
argv.push(0);
}
}
var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_STATIC) ];
pad();
for (var i = 0; i < argc-1; i = i + 1) {
argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_STATIC));
pad();
}
argv.push(0);
argv = allocate(argv, 'i32', ALLOC_STATIC);
var ret;
ret = Module['_main'](argc, argv, 0);
return ret;
}
function run(args) {
args = args || Module['arguments'];
if (runDependencies > 0) {
Module.printErr('run() called, but dependencies remain, so not running');
return 0;
}
if (Module['preRun']) {
if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
var toRun = Module['preRun'];
Module['preRun'] = [];
for (var i = toRun.length-1; i >= 0; i--) {
toRun[i]();
}
if (runDependencies > 0) {
// a preRun added a dependency, run will be called later
return 0;
}
}
function doRun() {
var ret = 0;
calledRun = true;
if (Module['_main']) {
preMain();
ret = Module.callMain(args);
if (!Module['noExitRuntime']) {
exitRuntime();
}
}
if (Module['postRun']) {
if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
while (Module['postRun'].length > 0) {
Module['postRun'].pop()();
}
}
return ret;
}
if (Module['setStatus']) {
Module['setStatus']('Running...');
setTimeout(function() {
setTimeout(function() {
Module['setStatus']('');
}, 1);
doRun();
}, 1);
return 0;
} else {
return doRun();
}
}
Module['run'] = Module.run = run;
// {{PRE_RUN_ADDITIONS}}
if (Module['preInit']) {
if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
while (Module['preInit'].length > 0) {
Module['preInit'].pop()();
}
}
initRuntime();
var shouldRunNow = true;
if (Module['noInitialRun']) {
shouldRunNow = false;
}
if (shouldRunNow) {
var ret = run();
}
// {{POST_RUN_ADDITIONS}}
// {{MODULE_ADDITIONS}}
// EMSCRIPTEN_GENERATED_FUNCTIONS: ["_main"]
コンパイル方法(C言語 → LLVM Assembler)
C:¥> clang hello.c -S -O4 -o hello.ll |
C:¥> clang hello.c -S -O4 -o hello.ll
コンパイル方法(LLVM Assembler → JavaScript)
C:¥> python emcc hello.ll -o hello.js |
C:¥> python emcc hello.ll -o hello.js
実行方法(Node.js による実行例)
実行結果
Tags: Emscripten
Categories: Emscripten, LLVM