javascript — обратный вызов asm.js Module.ccall / Module.cwrap

У меня есть некоторые функции обратного вызова в C ++, я хотел бы воссоздать в javascript после компиляции с emscripten.

Кто-нибудь знает, как вызвать тех, кто использует ccall или cwrap?

Спасибо!

0

Решение

Техника, которую я использовал, заключалась в преобразовании указателя в unsigned int (технически, uint32_t), который я затем передал в JS. Когда я был готов сделать обратный вызов, я передал значение обратно в C ++, преобразовал его обратно в указатель функции и затем вызвал связанную функцию.

Многое из этого может быть автоматизировано; Например, вы можете настроить свой класс обратного вызова на базовый класс, в который будут преобразованы все указатели перед вызовом виртуальной функции, которая перенаправляет на правильный производный класс (в моем случае я использую это для обработки параметров и типов возврата).

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

https://github.com/mercere99/Empirical

emp::JSWrap() это функция, которая принимает объект std :: function и возвращает uint32_t, Вы можете найти его определение здесь: https://github.com/mercere99/Empirical/blob/master/emtools/JSWrap.h Он должен правильно обрабатывать основные параметры и возвращаемые типы и std::string, но я работаю, чтобы расширить это. Если вы извлекаете только некоторые файлы из проекта, обратите внимание, что JSWrap включает в себя несколько других, но не слишком много.

Другой важный файл, о котором вам нужно беспокоиться — это library_emp.js (https://github.com/mercere99/Empirical/blob/master/emtools/library_emp.js), который определяет emp.Callback(), который может быть использован на стороне JS.

Чтобы интегрировать оба этих файла в вашу программу, вам необходимо:

  • Добавьте в свой код C ++ #include "JSWrap.h" а также #include "init.h" (возможно, с дополнительной информацией о пути)
  • Добавьте к своей подборке: --js-library ../../emtools/library_emp.js
  • Прежде чем использовать какие-либо обратные вызовы, запустите emp::Initialize(); на стороне C ++.
  • Оберните функцию, которую вы используете, вызвав uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped); Он вернет значение идентификатора функции, которое вы можете передать в JS. Кроме того, вы можете позвонить uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped, "JS_Function_Name"); и он создаст функцию JS для вас с указанным именем.
  • С помощью JS вы можете предоставить указанный идентификатор функции, вызвав функцию обратного вызова с emp.Callback(id, parameters) или вы можете использовать предоставленное имя, если вы использовали один emp.JS_Function_Name(parameters...) и он перезвонит оригинальной функции. Любое возвращаемое значение будет передано обратно.

Позвольте мне знать, если это помогает! В верхней части JSWrap.h также есть некоторая документация и тестовые файлы на https://github.com/mercere99/Empirical/tree/master/UTests/emtools (включая Makefile, файл кода с именем JSWrap.cc и файл HTML с именем JSWrap.html).

редактироватьНиже приведен пример кода, который отправляет указатель на объект функции в JS, а затем вызывает его обратно из JS.

#include <emscripten.h>
#include <functional>

// A couple of possible callbacks, all with the same signature.
double Times2(double val) { return val * 2; }
double Plus7(double val) { return val + 7; }

// A function callback from JS that takes a callback id and an arg and does the callback.
extern "C" {
double Callback_dd(uint32_t cb_id, double val) {
auto * fun_ptr = reinterpret_cast<std::function<double(double)>*>(cb_id);
return (*fun_ptr)(val);
}
}

int main() {
// Pick the function you want to run
auto fun = std::function<double(double)>(Times2);
// auto fun = std::function<double(double)>(Plus7);

// Convert a function pointer to a uint32_t.
// Note double casting to first convert it to a number and then reduce it to 32-bits.
// Using reintepret_cast would be better, but looked confusing with the double cast.
uint32_t cb_id = (uint32_t) (long long) &fun;

// The following code passed the callback ID to JavaScript.  The JS code then uses the
// ID to call back the original function.
EM_ASM_ARGS({
Callback_dd = Module.cwrap('Callback_dd', 'number', ['number']);
var x = 12.5;
alert('Result: fun(' + x + ') = ' + Callback_dd($0, x));
}, cb_id);

}

Обратите внимание, что если вы собираетесь выполнить обратный вызов после того, как main () завершится, вам нужно убедиться, что вызываемые вами функции будут сохраняться.

Чтобы скомпилировать этот код, поместите его в файл (назовем его callback_test.cc) и затем из командной строки запустите:

em++ -s EXPORTED_FUNCTIONS="['_Callback_dd', '_main']" -std=c++11 callback_test.cc -o callback_test.html

Теперь вы должны иметь возможность открыть callback_test.html в вашем веб-браузере, и он будет вызывать из JS любой указатель функции C ++, который вы ему передали.

В этом случае вам нужно знать сигнатуру функции заранее, но, как я уже упоминал выше, вы можете использовать более сложный обратный вызов, который может запомнить сигнатуру.

2

Другие решения


По вопросам рекламы [email protected]