フェルマータ

個人用のメモ。ソフトウェアの導入とかが多くなる予定。

Emscripten を使って C++ のコードを JavaScript の世界に持っていく

ポエム

フロントエンドは大変苦手なのだが、まー最近は JavaScript 頑張らなければ、と思いつつもブラウザで何かを作るのはさほど興味がわかなかった。が、ここ数年で C++ のコードを JavaScript の世界に持ってくるのはだいぶスマートになったようで今回は Emscripten 使って過去に作った 今さら C++ で WORLD のラッパーライブラリを書いてみた - フェルマータ というやつを JavaScript の世界に持っていくのを試してみた。

できなかったこと

過去作ったコードは下記のように ExternalProject_add を通して依存性の解決をできるようにしていたが、 ExternalProject_add で作った static library を wasm から利用するのは厳しかった。

ExternalProject_add(uzume_vocoder
        PREFIX ${CMAKE_CURRENT_BINARY_DIR}/uzume_vocoder
        GIT_REPOSITORY https://github.com/haruneko/uzume_vocoder
        GIT_TAG master
        INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}
        CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}"
        )

emscripten を cmake で利用するためにはオプションに -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake (${EMSCRIPTEN} は emsdk への PATH )的なやつを使わねばならず、これをつけると cmake の add_library がなんのバイナリも作成しなくなってしまい依存性が解決できなくなってしまった。いくつか情報を調べたりしてみたが解決策が思いつかなかったので今回はこの方法は取らないことにした。

やったこと

github.com

結局こんな感じの実装にしてみたところ、 JavaScript から C++ のコードが呼べるのを確認できた。 CMakeLists.txt は下記のようにした。

cmake_minimum_required(VERSION 3.1)

project(uzume_emscripten)

include(ExternalProject)

ExternalProject_add(uzume_vocoder
        PREFIX ${CMAKE_CURRENT_BINARY_DIR}/uzume_vocoder
        GIT_REPOSITORY https://github.com/haruneko/uzume_vocoder
        GIT_TAG master
        INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}
        CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}"
        )

file(GLOB_RECURSE VOCODER_SOURCES ./lib/uzume_vocoder/src/*.cpp)
file(GLOB_RECURSE VOCODER_HEADERS ./lib/uzume_vocoder/src/*.hpp)

include_directories(uzume_emscripten PRIVATE ./lib/uzume_vocoder/src/)

add_executable(uzume_emscripten
        src/data/ContourBindings.cpp
        src/main.cpp
        ${VOCODER_SOURCES}
        ${VOCODER_HEADERS}
        )

if (EMSCRIPTEN)
    set(CMAKE_EXECUTABLE_SUFFIX ".html")
endif()

set_target_properties(uzume_emscripten PROPERTIES LINK_FLAGS "-s DEMANGLE_SUPPORT=1 --bind")

結局とっても野蛮なのだが落としてきたコードの install などは完全に無視して、直接ソースコードに依存することにした。もうちょいマシな方法はあるのかもしれないが、ネットの大海にも C++ の情報は少なく、子育てやっている状況で調べられないのでここまでとする。雑に実行した内容は下記の通り。

開発者コンソールでの実行の模様

一つハマりポインツとしてお伝えするのですが下記記事を参考にしたところ、 error: undefined symbol: _embind_register_class (referenced by top-level compiled C/C++ code) がバカスカ出てしまって困ってしまった。

qiita.com

下記記事で LINK_FLAGS ちゃんとするといいよと書かれておりこちらで解決した。まあ今回は本当に雑なのでここまで。

stackoverflow.com