ホーム » スタッフ » 斉藤徹 » Computer » Network » WebAssembly環境の構築

2021年11月
 123456
78910111213
14151617181920
21222324252627
282930  

検索・リンク

WebAssembly環境の構築

卒研で WebAssembly を使った開発をしてもらっているけど、自分でも試したいので環境の構築。

Debian emscripten パッケージだけではダメだった

卒研の学生さんが、emscripten 使っているという話だったので、”aptitude search emscripten” を実行したら、パッケージがあったので、”aptitude install emscripten” を実行。鉄板の hello world をコンパイルしようとしたら、”LLVM version appears incorrect (seeing “11.0”, expected “10.0”)”というエラーが出て、コンパイルに失敗。

llvm の C コンパイラとのバージョンが合わない様子。ということで、git より環境を構築してみる。

git で emsdk 環境の構築

通常ユーザであれば、”git clone https://github.com/juj/emsdk.git” を実行すると、その PATH 直下に環境が作られるみたい。こういう使い方は好きじゃないので…

$ sudo bash
((( ひとまず emscripten は必要みたい )))
# apt-get install emscripten # 導入後は不要?
((( emsdk のインストール )))
# cd /usr/local
# git clone https://github.com/juj/emsdk.git
# cd emsdk
# ./emsdk install latest
# ./emsdk activate latest

Hello World を試す

((( 自分の環境で以下のコマンドにより環境変数をセット )))
$ source /usr/local/emsdk/emsdk_env.sh
((( Hello World をコンパイル )))
$ cd ~/public_html
$ mkdir test
$ cd test
$ vi hello.c
#include 
int main( int argc , char* argv[] ) {
   printf( "Hello World\n" ) ;
   return 0 ;
}
$ emcc test.c -s WASM=1 -o test.html
$ ブラウザで test.html を開く http://...URL.../~t-saitoh/test/test.html

ブラウザから自分のC言語(wasm)を呼び出し結果を出力

$ mkdir html_template
$ cp /usr/local/emsdk/upstream/emscripten/src/shell_minimal.html html_template
$ vi html_template/shell_minimal.html
((( C言語側を呼び出すボタンを埋め込む )))
<textarea class="emscripten" id="input"></textarea>
<input type="button" value="CALL WASM" onclick="Module._ems_func();"/>

((( test.cxx )))
#include <stdio.h>
#include <emscripten/emscripten.h>
#include <string>

int main( int argc , char* argv[] ) {
  return 0 ;
}

// void* getElementValue_( char const* id ) { ... } が作られる
EM_JS( void* , getElementValue_ , (char const* id) ,
{
  var e = document.getElementById( UTF8ToString( id ) ) ;
  var str = e.value ;
  var len = lengthBytesUTF8( str ) + 1 ;
  // コンパイル時に -s EXPORTED_FUNCTIONS="['_malloc']" しないとエラーがでる
  var heap = _malloc( len ) ;

  stringToUTF8( str , heap , len ) ;
  return heap ;
 } ) ;

// std::string型はC++の文字列処理の型
//   std::string s( "abcde" ) ;
//   s.c_str() で、C言語のNULターミネータ付きの文字列を参照できる。

std::string getElementValue( std::string const &id )
{
  void *p = getElementValue_( id.c_str() ) ;
  std::string s( (char const*) p ) ;
  free( p ) ;
  return s ;
}

void setElementValue( std::string const &id , std::string const &value )
{
  EM_ASM( {
      var e = document.getElementById( UTF8ToString( $0 ) ) ;
      e.value = UTF8ToString( $1 ) ;
    } , id.c_str() , value.c_str() ) ;
}

#ifdef __cplusplus
extern "C" {
#endif

  /* HTMLに埋め込んだ onclick=_ems_func() で呼び出される*/
  void EMSCRIPTEN_KEEPALIVE ems_func() {
    std::string input = getElementValue( "input" ) ;
    setEnvironmentValue( "output" , input ) ;
  }

#ifdef __cplusplus
}
#endif

((( test.cxx をコンパイル )))
$ source /usr/local/emsdk/emsdk_env.sh
$ em++ -o test.html test.cxx -O3 -s WASM=1 -s EXPORTED_FUNCTIONS="['_main','_malloc']" --shell-file html_template/shell_minimal.html