В последнем сообщении блога мы говорили о вызове кода C / C ++ из JavaScript с использованием WebAssembly и Emscripten. Сегодня мы обсудим, как вызывать код JavaScript из C / C ++ с Emscripten и без него.

Использование объекта импорта

Помните, как мы в прошлый раз передали объект импорта для создания экземпляров наших модулей WebAssembly? Сегодня мы поговорим об этом более подробно.

importObject (необязательно)

Объект, содержащий значения, которые нужно импортировать во вновь созданный Instance, например функции или объекты WebAssembly.Memory. Для каждого объявленного импорта скомпилированного модуля должно быть одно совпадающее свойство, иначе будет выброшено WebAssembly.LinkError.

Мы передадим нашу функцию JavaScript в аргументе env объекта importObject. Опираясь на наш прошлый пример -

Здесь мы передали функцию console.log моему модулю WebAssembly. Наша программа на C ++ получит console.log и вызовет его, вызвав consoleLog. Вы также можете писать и передавать свои собственные функции.

Вызов импортированных функций в C / C ++

В нашем файле C ++ нам нужно определить функцию consoleLog, которую он будет получать от JavaScript. Сигнатура функции должна соответствовать тому, что вы передали. Sum - это функция, которую мы экспортировали в JavaScript и используемую выше в нашем файле index.html как result.instance.exports.Sum

em++ -std=c++11 main.cc  -Os -s WASM=1 -s SIDE_MODULE=1 -o main.wasm

Когда мы вызываем функцию C ++ _ 9_ в нашем коде JavaScript, она записывает результат в консоль перед его возвратом.

Использование Emscripten

Мы обсудим следующие два подхода к вызову кода JavaScript из C / C ++:

  • Запуск сценария с использованием emscripten_run_script () (медленнее)
  • Написание встроенного JavaScript (быстрее)

Использование emscripten_run_script ()

void emscripten_run_script (const char * script) - это наиболее прямой способ вызова JavaScript из C / C ++. Он эффективно запускает код, используя eval(), функцию JavaScript, которая оценивает код, представленный в виде строки. Он подходит для таких целей, как отладка, но для повышения производительности вы должны писать JavaScript «inline».

emscripten_run_script("console.log('hello world')");

Вы также можете использовать emscripten_run_script_int, если результат оценки возвращает int, или emscripten_run_script_string, если оценка возвращает строку.

Использование встроенного JavaScript

Более быстрый способ - написать встроенный JavaScript, используя EM_JS() или EM_ASM() (и связанные с ним макросы).

EM_ASM

Это позволяет вам объявлять JavaScript в вашем коде C «встроенным». Код JavaScript выполняется немедленно и не может быть повторно использован в файле C / C ++, в котором он содержится.

Аргументы типа int или double могут быть переданы в блок кода JavaScript, где они поступают как переменные $ 0, $ 1 и т. Д. Он также может возвращать значения обратно. Вам необходимо указать, является ли возвращаемое значение int или double, используя соответствующий макрос EM_ASM_INT или EM_ASM_DOUBLE.

em++ -std=c++11 main.cc  -O3 -s WASM=1 -o main.wasm -o main.js -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]'

При компиляции и запуске Emscripten будет выполнять строки JavaScript, заключенные в блок EM_ASM, как если бы они появлялись непосредственно в сгенерированном коде.

Однако обратите внимание, что под капотом Emscripten по-прежнему выполняет вызов функции даже в этом случае, что связано с некоторыми накладными расходами.

В приведенном выше примере результаты функции theSum фактически будут регистрироваться дважды: один раз через EM_ASM_INT (), а второй раз через наш index.html.

EM_JS (тип_ возврата, имя_функции, аргумент, код)

Если вы хотите, чтобы ваш JavaScript можно было повторно использовать в C ++ в качестве функции, вы можете вместо этого использовать EM_JS, который создает оболочку для кода JavaScript и позволяет нам выполнять ее, как обычную функцию C / C ++.

Подробнее об этих макросах можно прочитать здесь.

Вы также можете вызывать функции JavaScript как указатели на функции из C, а также реализовать C API в JavaScript, где вы можете определить интерфейс на C и реализовать API в JavaScript.

Вы также можете использовать WebIDL Binder и Embind для создания привязок между C ++ и JavaScript, что позволяет естественным образом использовать объекты кода C ++ из JavaScript. Embind дополнительно поддерживает вызов кода JavaScript из C ++. Однако сегодня мы не будем их обсуждать, но вы всегда можете узнать больше на сайте Emscripten!