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!

Tags:

Categories: Emscripten, LLVM

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

WP-SpamFree by Pole Position Marketing