Archive for the ‘Emscripten’ Category
-
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; }
上記コードを 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
上記コードを 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"]
コンパイル方法(C言語 → LLVM Assembler)
C:¥> clang hello.c -S -O4 -o hello.ll
コンパイル方法(LLVM Assembler → JavaScript)
C:¥> python emcc hello.ll -o hello.js
実行方法(Node.js による実行例)
C:¥> node Hello.js
実行結果
Hello, Emscripten World!