Emscripten Wasm Не может использовать большую часть C ++ при компиляции - PullRequest
0 голосов
/ 20 марта 2020

Я пытаюсь скомпилировать небольшой пример C ++, который использует стандартную библиотеку в wasm для использования с базовой точкой входа c javascript (не сгенерированный клейкий код). К сожалению, при загрузке модуля я получаю следующую ошибку:

TypeError: WebAssembly.instantiate (): Import # 0 module = "wasi_snapshot_preview1" ошибка: модуль не является объектом или функцией

Ранее я пытался создать с использованием wasisdk и автономного llvm, но у меня были похожие проблемы. Кажется, что нет никакой информации об обходе этой довольно криптической c ошибки.

Во-первых, прежде чем я go глубже, возможно ли даже построить код C ++, который использует структуры данных из стандартной библиотеки в автономный wasm? Я не уверен, смогу ли я получить эту работу, учитывая, что wasm все еще находится на ранних стадиях, но я могу что-то делать неправильно. По моему опыту, почти каждая встроенная структура данных и строка вызывает проблемы, даже если я перегружаю новую и удаляю, чтобы исключить некоторые проблемы с выделением памяти.

Для получения более подробной информации, моя система MacOS 10.14, и я Я использую Chrome 80. Я использую последнюю версию emsdk из github для компиляции.

Мои извинения за приток блоков кода, но я не уверен в лучшем примере. Я сократил количество примеров до минимума, насколько смог.

Это мой bash скрипт сборки:

em++ source.cpp \
--std=c++17 \
-flto \
-fno-exceptions \
-Os \
-o output.wasm \
-s "EXPORTED_FUNCTIONS=['_animate']" \
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \

C ++: я получаю ошибку, как только использую структура данных, такая как стандартная неупорядоченная карта.

#ifdef __cplusplus
    #define extern_c_begin() extern "C" {
    #define extern_c_end() }
#else 
    #define extern_c_begin()
    #define extern_c_end()
#endif

#include <unordered_map>

std::unordered_map<int, int> map;

int use_map() {
        // if I use the map at all, I get the error
    map.insert({1, 2});
    return (int)map.size();
}

extern_c_begin()

// call into js
void hello_js(void);

int animate(long arg) {
    int size = use_map();
    hello_js();
    return size;
}

extern_c_end()

Наконец, мой javascript / index. html:

<!DOCTYPE html><html><head></head><body>
    <script type="module">
        "use strict";
        (async () => {
          try {
            const wasmInfo = {
                instance   : null,
                memoryHeap : null,
                env        : {}
            };

            wasmInfo.env["hello_js"] = () => {
                console.log("in js, call from wasm");
            };

            // error on load
            const wasmLoadResult = await WebAssembly.instantiateStreaming(
              fetch("./output.wasm"),
              {env : wasmInfo.env}
            );
            wasmInfo.instance = wasmLoadResult.instance;

            function animate(t) {
                requestAnimationFrame(animate);
                try {
                    console.log(wasmInfo.instance.exports.animate(t));
                } catch (e) {
                    console.error(e);
                }
            }
            requestAnimationFrame(animate);

          } catch (err) {
            console.error(err);
          }
        })();
</script></body></html>

Это, кажется, происходит практически с каждой структурой данных. Я даже попытался заменить стороннюю библиотеку под названием robin_hood, но у нее та же проблема.

Есть ли решение?

Ответы [ 2 ]

1 голос
/ 20 марта 2020

Вам необходимо реализовать все системные вызовы, требуемые вашей программой. Посмотрите на вывод wasm-objdump, чтобы увидеть список всех импортов, требуемых вашей программой.

0 голосов
/ 22 апреля 2020

Во-первых, прежде чем я go глубже, возможно ли вообще встроить код C ++, который использует структуры данных из стандартной библиотеки, в автономный wasm?

Да. Пруф:

// app.cpp

#include <vector>
using std::vector;
typedef long int i32;
extern "C" {
  i32 myFunction(i32 myNumber) {
    vector<i32> myVector{ 666, 1337 }; 
    return myVector[0] + myVector[1] + myNumber;
  }
}
emcc -Os -s INITIAL_MEMORY=64kb -s MAXIMUM_MEMORY=64kb -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_STACK=0kb -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_myFunction']" -Wl,--no-entry "app.cpp" -o "app.wasm"
// javascript 

(async () => {
  const response = await fetch('app.wasm');
  const file = await response.arrayBuffer();
  const imports = { wasi_snapshot_preview1: { proc_exit: () => { } } } // dummy placeholder function, a sacrifice to the emscripten god who demands it
  const wasm = await WebAssembly.instantiate(file, imports);
  const { myFunction } = wasm.instance.exports;
  const myNumber = myFunction(123);
  console.log(myNumber); // 2126
})();
...