В последнем сообщении блога мы говорили о вызове кода 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!