卒研で 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