2012-09-10 18 views
15

Tôi có một đoạn mã C++ được chuyển đổi thành JavaScript qua Emscripten. Tôi muốn mã C++ được chuyển đổi để gọi lại mã JavaScript để gọi nó. Một cái gì đó như:Chuyển hàm JS sang mã do Emscripten tạo ra

JavaScript:

function callback(message) { 
    alert(message); 
} 

ccall("my_c_function", ..., callback); 

C++:

void my_c_function(whatever_type_t *callback) { 
    callback("Hello World!"); 
} 

Đây có phải là có thể bằng cách nào đó?

Trả lời

13

Tôi tin rằng câu trả lời được chấp nhận hơi lỗi thời.

Vui lòng tham khảo this bullet point in the "Interacting with code" emscripten tutorial.

Ví dụ: C:

void invoke_function_pointer(void(*f)(void)) { 
    (*f)(); 
} 

JS:

var pointer = Runtime.addFunction(function() { 
    console.log('I was called from C world!'); 
}); 
Module.ccall('invoke_function_pointer', 'number', ['number'], [pointer]); 
Runtime.removeFunction(pointer); 

Bằng cách này, C-mã không cần phải nhận thức được rằng nó được transpiled để JS và bất kỳ cầu đòi hỏi hoàn toàn có thể được điều khiển từ JS .

(mã đột nhập vào nhà soạn tin; có thể chứa lỗi)

+0

một điều quan trọng là số lượng các con trỏ hàm có giá trị đồng thời được cố định và được chỉ định bởi 'emcc ... -s RESERVED_FUNCTION_POINTERS = 20 ...' –

10

Một điều thường xuyên được thực hiện trong Emscripten là ánh xạ các loại mạnh mẽ với các loại đơn giản.

JS:

function callback(message) { 
    alert(message); 
} 

var func_map = { 
    0: callback 
}; 

// C/C++ functions get a _ prefix added 
function _invoke_callback(callback_id, text_ptr) { 
    func_map[callback_id](Pointer_stringify(text_ptr)); 
} 

ccall("my_c_function", ..., 0); 

C++:

// In C/C++ you only need to declare the func signature and 
// make sure C is used to prevent name mangling 
extern "C" void invoke_callback(int callback_id, const char* text); 

void my_c_function(int callback_id) { 
    invoke_callback(callback_id, "Hello World!"); 
} 

Và dĩ nhiên, bạn có thể thêm một số mã keo, vì vậy đây được rất liền mạch.

+3

+1 để đề cập đến việc tránh mang tên C++. – Eonil

+0

bạn có thể xem câu hỏi liên quan này: http://stackoverflow.com/questions/33673575/where-should-i-defined-emscripten-extern-functions-in-js?noredirect=1#comment55119884_33673575 –

1

tôi cần phải viết một cái gì đó rất giống với những gì được mô tả trong câu hỏi. Mã của tôi đã kết thúc như thế này:

C:

void call(void (*back)(char*)){ 
    back("Hello!"); 
} 

JS:

function back(text){ 
    alert(Pointer_stringify(text)); 
} 
var pointer = Runtime.addFunction(back); 
var call = Module.cwrap('call', 'void', ['pointer']); 
call(pointer); 
Runtime.removeFunction(pointer); 

Lưu ý rằng con trỏ trở về callback phải được dereferenced với Pointer_stringify.

Bạn có thể tìm thấy example code như thế này trên GitHub.

+0

Liên kết cung cấp gần như không có thông tin bổ sung. –

0

Dưới đây là những gì tôi đã thu thập được từ một số bài viết và bằng cách nhìn vào Emscripten kèm mã:

Trong C++:

#include <iostream> 
#include <functional> 

extern "C" { 
    void registerCallback(void(*back)(const char*)); 
    void triggerCallback(char* message); // for invoking it from JS, just for this example 
} 

// global 
std::function<void(const char*)> gCallback; 

void registerCallback(void(*back)(const char*)){ 
    gCallback = back; 
} 

void triggerCallback(char* message){ 
    if (gCallback) { 
    gCallback(message); 
    } else { 
    std::cerr << "Cannot pass '"<< message <<"' to undefined callback\n"; 
    } 
} 

Một điều quan trọng, mà đã mất tích trong bài viết khác, là để biên dịch C++ với RESERVED_FUNCTION_POINTERS = ... cờ, ví dụ:

em++ -std=c++11 -s RESERVED_FUNCTION_POINTERS=20 source.cpp -s EXPORTED_FUNCTIONS="['_registerCallback','_triggerCallback']" -o try.html 

Sau khi tải try.html vào trình duyệt, bạn có thể thực thi mã JS sau trong giao diện điều khiển của nó:

// Register a callback function 
function callback(text){ alert("In JS: "+Pointer_stringify(text)); } 
var cb = Runtime.addFunction(callback); 
_registerCallback(cb); 

// Invoke it with some "C string" 
var jsStr = "XOXOXO"; 
var cStr = allocate(intArrayFromString(jsStr), 'i8', ALLOC_NORMAL) 
_triggerCallback(cStr); 

// Free Emscripten heap and release the function pointer 
_free(cStr); 
Runtime.removeFunction(cb); 

Bạn sẽ thấy một cảnh báo với "Trong JS: xoxoxo ".

2

Có một cách mới để đạt được yêu cầu của bạn qua số embind.

Hãy xem xét đoạn mã C++ sau đây.

#include <emscripten/bind.h> 
using namespace emscripten; 

void cbTest(emscripten::val cb) 
{ 
    cb(); 
} 

EMSCRIPTEN_BINDINGS(my_module) { 
    function("cbTest", &cbTest); 
} 

Hàm cbTest C++ mất một emscripten::val. Đây có thể là một đối tượng thuộc loại nào. Đối với chúng tôi, đây là một đối tượng hàm. Đây là cách bạn sẽ gọi nó từ JS

var cbFunc = function() { 
    console.log("Hi, this is a cb"); 
} 

Module.cbTest(cbFunc); 

P.S Api này vẫn đang được xây dựng.

Các vấn đề liên quan