0

I just started using JavaScript V8 and compiled a basic example from the Embedder's Guide. Now I want to bind C++ functions to the JavaScript context.

For now I only have a more or less blank class which should handle binding later on.

class Manager
{
public:
    Manager()
    {
        context = Context::New();
    }
    void Bind(string Name, function<Handle<Value>(const Arguments&)> Function)
    {
        // bind the function to the given context
    }
private:
    Persistent<Context> context;
};

How can I bind a std::function object to the JavaScript V8 context?

danijar
  • 32,406
  • 45
  • 166
  • 297
  • 1
    I used to bind functions in my engine with something like `void BindExample(v8::Handle engine) { engine->Set(v8::String::New("FunctionInJS"), v8::FunctionTemplate::New(FunctionInCPP)); }`. Does this help somehow? – Christian Ivicevic Mar 31 '13 at 20:15
  • That helps me but what exactly is the handle called engine in your example? But actually the main issue is about passing the `std::function` as a parameter. – danijar Mar 31 '13 at 20:22
  • Please refer to my full example in the answer and my suggestions on what to try about `std::function`. – Christian Ivicevic Mar 31 '13 at 20:24

2 Answers2

3

What I used in my engine was a rather complicated approach but the very first I came up with. (Sadly I moved from V8 to LLVM such that I haven't been optimizing this.)

void ExposeFunctions(v8::Handle<v8::ObjectTemplate> engine) {
    /* ... */
    engine->Set(v8::String::New("Exit"), v8::FunctionTemplate::New(NativeExit));
    engine->Set(v8::String::New("Log"), v8::FunctionTemplate::New(NativeLog));
    /* ... */
}

int SpawnEngine() {
    v8::Locker locker;
    v8::HandleScope handleScope;
    v8::TryCatch exceptionManager;
    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
    ExposeFunctions(global);
    v8::Persistent<v8::Context> context = v8::Context::New(nullptr, global);
    v8::Context::Scope scope(context);
    /* ... */
    context.Dispose();
    return 0;
}

This should give you at least a possible solution to bind native functions to the interpreter which you could rework for your needs.

Considering your problem using a function object one could try (just guessing here) to pass it directly like I did with named functions, or nest it in a lambda expression passed to v8::FunctionTemplate::New. But its quite a while since I worked with this.

Christian Ivicevic
  • 10,071
  • 7
  • 39
  • 74
0

The parameter type InvocationCallback which is requested by the Set function is a simple typedef.

typedef Handle<Value> (*InvocationCallback)(Arguments const &);

Therefore I had to convert the std::function to a raw function pointer.

void Register(string Name, function<Handle<Value>(Arguments const &)> Function)
{
    InvocationCallback* function = Function.target<InvocationCallback>();
    globals->Set(String::New(Name.c_str()), FunctionTemplate::New(*function));
}
danijar
  • 32,406
  • 45
  • 166
  • 297
  • I think you should unaccept this answer because, as you found out in another question, this doesn't work for the general case. – minexew Mar 09 '16 at 23:03
  • @minexew Can you provide a link to the other question you're referring to, please? – danijar Mar 09 '16 at 23:09