6

I have a C++ method (which role is killing some processes). She needs 2 parameters : a hostname and a port.

On the other hand, I am developing a web-application (using Nodejs and AngularJS), running on Google Chrome.
When I click on a button through the browser, I would like to be able to call the C++ function, through my app.js file.

I haven't found how to "bind" javascript with C++.

EDIT : I think this link could be very useful How can I use a C++ library from node.js?

2 Answers 2

3

You can use Google's V8. V8 is Google's open source JavaScript engine. V8 can run standalone, or can be embedded into any C++ application.

http://code.google.com/p/v8/

Following example from github demonstrates, binding a C++ class with Google V8. v8_wrap_class.cpp - Author is nicholas

/*
 * v8_wrap_class.cpp
 *
 *  Created on: 14/01/2013
 *      Author: nicholas
 *     License: public domain
 */


#include <v8.h>
#include <cstdio>
#include <string>
#include <stdexcept>
#include <memory>

using namespace v8;

/*
var Simple = function(v)
{
    this.value = v;
}
Simple.prototype.func = function()
{
    alert(this.value);
}

var obj = new Simple(4);
obj.func();
*/
struct Simple
{
    double value;

    Simple(double v)
     : value(v)
    {
        fprintf(stderr, "Simple::ctor\n");
    }

    void func()
    {
        fprintf(stderr, "Simple::func(%f)\n", value);
    }

    ~Simple()
    {
        fprintf(stderr, "Simple::dtor\n");
    }
};

namespace js
{

/*
 * Retrieve the c++ object pointer from the js object
 */
template <typename T>
T* unwrap(const Arguments& args)
{
    auto self = args.Holder();
    auto wrap = Local<External>::Cast(self->GetInternalField(0));
    return static_cast<T*>(wrap->Value());
}

/*
 * Construct a new c++ object and wrap it in a js object
 */
template <typename T, typename... Args>
Persistent<Object> make_object(Handle<Object> object, Args&&... args)
{
    auto x = new T(std::forward<Args>(args)...);
    auto obj = Persistent<Object>::New(object);
    obj->SetInternalField(0, External::New(x));

    obj.MakeWeak(x, [](Persistent<Value> obj, void* data)
    {
        auto x = static_cast<T*>(data);
        delete x;

        obj.Dispose();
        obj.Clear();
    });

    return obj;
}

}

void bind_Simple(Local<Object> global)
{
    // Name the class in js
    auto name = String::NewSymbol("Simple");

    auto tpl = FunctionTemplate::New([&](const Arguments& args) -> Handle<Value>
    {
        if (!args.IsConstructCall())
            return ThrowException(String::New("Cannot call constructor as function"));

        HandleScope scope;

        // Read and pass constructor arguments
        js::make_object<Simple>(args.This(), args[0]->NumberValue());

        return args.This();
    });

    tpl->SetClassName(name);
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    auto prototype = tpl->PrototypeTemplate();

    // Add object properties to the prototype
    // Methods, Properties, etc.
    prototype->Set(String::New("func"), FunctionTemplate::New([](const Arguments& args) -> Handle<Value>
    {
        auto s = js::unwrap<Simple>(args);
        s->func();
        return {};
    })->GetFunction());

    auto constructor = Persistent<Function>::New(tpl->GetFunction());
    global->Set(name, constructor);
}

int main()
{
    std::string js_source = R"(
        for(var i = 0; i < 1000; ++i)
        {
            var s = new Simple(4);
            s.value = 5;
            s.func();
        }
    )";

    /*
     * This code is mostly uninteresting.
     * Just run the vm with the script provided.
     */
    {
        HandleScope handle_scope;
        Handle<ObjectTemplate> global_template = ObjectTemplate::New();

        Persistent<Context> context = Context::New(0, global_template);
        Context::Scope context_scope(context);

        auto global = context->Global();

        // Wrap the class and bind to the global scope.
        bind_Simple(global);

        {
            HandleScope handle_scope;

            TryCatch trycatch;

            Local<String> source = String::New(js_source.c_str(), js_source.size());

            Local<Script> script = Script::Compile(source);
            if (script.IsEmpty())
            {
                Handle<Value> exception = trycatch.Exception();
                String::AsciiValue exception_str(exception);
                throw std::runtime_error(*exception_str);
            }

            Local<Value> result = script->Run();
            if (result.IsEmpty())
            {
                Local<Value> exception = trycatch.Exception();
                String::AsciiValue exception_str(exception);
                throw std::runtime_error(*exception_str);
            }
        }

        context.Dispose();
        context.Clear();
    }

    // Run the GC until there is nothing to reclaim.
    while (!V8::IdleNotification())
        ;
    return 0;
}
Sign up to request clarification or add additional context in comments.

3 Comments

How would you use it to call a C++ function from js? Can you give an example?
You'd have to wrap the whole thing up as a node addon module. Alternately, compile the C++ to a small executable you run with child_process.
Brainy, if you are going to mass edit posts, make sure you fix all problems in each post. Adding [.net] to [c#] questions is not helpful on its own, please stop flooding the review queue in pursuit of +2s.
3

This answer gives four appraoches to using C++ in JavaScript. The methods shown try to keep the original C++ in a standard and simple C++ implementation.

Two methods using WASM and two using SWIG and JRPC are used to give examples and ideas on executing C++ in JavaScript. In detail, this answer gives one example for executing in the browser and one for executing in NodeJS using WASM. The end of this answer also lists two other ways to execute C++ in JavaScript, one of which calls NodeJS from the browser, which is slightly more complex but possible using jrpc-oo.

If you want to execute in the browser or NodeJS, then you can compile your C++ to WASM and load that module in the browser or NodeJS, executing the C++ there. This WASM repo exemplifies how to do that. I will expand the key code in the WASM repo here.

Create some C++ code and declare your WASM binding, for example (from the files include/Test.H and src/Test.C):

class Test {
  public:
    void sayHello(){
      printf("Hi, my name is test\n");
    }
  };
  
  
  #include <emscripten/bind.h>
  EMSCRIPTEN_BINDINGS(Test_ex) {
    emscripten::class_<Test>("Test")
    .function("sayHello", &Test::sayHello)
    ;
  }

Compile that down and you can now run that in NodeJS (from the file nodejs/WASMTestNode.js):

libWASM = require('./libwasmNode.js');
libWASM().then((mod)=>{
  libWASM = mod;
  let test = new libWASM.Test;
  test.sayHello();
});

In the browser you can use the WASM code as well. To do that firs import the WASM library (from the file webcomponent/libWASM.js) :

import modProm from './libwasm.js';

Then create your web component and compile your WASM then execute the C++ method Test::sayHello (from the file webcomponent/libWASM.js):

import { LitElement } from 'lit';

export class LibWASM extends LitElement {
  constructor() {
    super();
    modProm().then((mod)=>{
      this.libWASM = mod; // for rendered WASM that delays
      this.WASMReady();
    })
  }
    
  WASMReady(){
    console.log('LibWASM.libWASM module compiled and ready to go.')
    let test = new this.libWASM.Test;
    test.sayHello();
  }
}

This code example is implemented in the reference repo.

Alternatively a third way to do this is to only use C++, SWIG and nodejs from this reference repo.

If you want to execute NodeJS from the browser or use a a different method of integrating C++ into nodejs, you can also look at this SWIG and jrpc-oo reference for doing the same thing, not only in NodsJS, but also from the browser calling NodeJS.

There are also other ways to execute C++ form JavaScript, however the methods demonstrated in this answer are reasonably straightforward and either rely on WASM binding or SWIG abstraction which leaves your original code as standard C++.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.