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