Archive for the ‘Emscripten’ Category

  1. 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!