コンパイルするスレッドの分離
UI とは異なるスレッドでコンパイルまでを実行し、メインスレッドに引き渡す。
メインスレッドでは、コンパイル済 wasm モジュールをインスタンス化し、Emscripten ランタイム・モジュールに処理を移す。
前の記事 にあるコードの一部を Worker で指定する JavaScript に分割すれば実装できる。
以下はそのファイルの一覧となる。
C:\wasm\project\11-compile-worker\.vscode\launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "localhost:8080",
"url": "http://localhost:8080/",
}
]
}
C:\wasm\project\11-compile-worker\CMakePresets.json
{
"version": 5,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "wasm-config",
"hidden": true,
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_CXX_STANDARD": "17",
"CMAKE_CXX_STANDARD_REQUIRED": "ON",
"CMAKE_CXX_EXTENSIONS": "OFF",
"CMAKE_TOOLCHAIN_FILE": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_CONFIGURATION_TYPES": "Debug;Release"
}
},
{
"name": "wasm-config-debug",
"inherits": "wasm-config",
"cacheVariables": {
}
},
{
"name": "wasm-config-release",
"inherits": "wasm-config",
"cacheVariables": {
}
}
],
"buildPresets": [
{
"name": "wasm-build-debug",
"configurePreset": "wasm-config-debug",
"verbose": true,
"configuration": "Debug"
},
{
"name": "wasm-build-release",
"configurePreset": "wasm-config-release",
"verbose": true,
"configuration": "Release"
}
]
}
C:\wasm\project\11-compile-worker\CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(11_compile_worker LANGUAGES CXX)
add_executable(11_compile_worker main.cpp)
target_link_options(11_compile_worker PRIVATE
$<$<CONFIG:Debug>:-gsource-map -sASSERTIONS=1 -sSAFE_HEAP=1>
"-sEXPORT_ES6=1"
)
C:\wasm\project\11-compile-worker\worker.js
fetch() で取得したバイナリをコンパイルしてメインスレッドに送信する
fetch('./build/Debug/11_compile_worker.wasm').then(response => {
console.log('fetch done');
WebAssembly.compileStreaming(response).then(wasmModule => {
console.log('compile done')
self.postMessage(wasmModule);
});
});
C:\wasm\project\11-compile-worker\index.html
ワーカースレッドから postMessage により送信された値 (WebAssembly モジュール) を使ってインスタンス化する
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<script type="module">
import Module from './build/Debug/11_compile_worker.js';
const worker = new Worker('./worker.js');
worker.onmessage = e => {
console.log('on message');
const wasmModule = e.data;
const moduleInfo = {
arguments: ['compile', 'worker'],
instantiateWasm: async (imports, successCallback) =>
{
const wasmInstance = await WebAssembly.instantiate(wasmModule, imports);
console.log('instantiate');
successCallback(wasmInstance);
},
};
let v = 0;
Module(moduleInfo).then(emsModule =>
{
// Emscripten モジュールにより C++ の関数を呼び出す
v = emsModule._increment(v);
console.log(`return=${v}`);
});
};
</script>
</head>
<body>
</body>
</html>
C:\wasm\project\11-compile-worker\main.cpp
// UTF-8N CRLF
#include <emscripten.h>
#include <cstdio>
extern "C"
EMSCRIPTEN_KEEPALIVE
int increment(int v)
{
printf("-- increment(%d)\n", v);
return v + 1;
}
int main(int argc, char** argv)
{
printf("C++ main(argc=%d, argv=[", argc);
for (int i=0; i<argc; ++i)
{
if (i) {
printf(",");
}
printf("'%s'", argv[i]);
}
puts("])");
return 0;
}
// EOF
実行結果
on message
instantiate
fetch done
compile done
C++ main(argc=3, argv=['./this.program','compile','worker'])
-- increment(0)
return=1
次回 は依存関係のあるファイルの処理について試してみる。