admin管理员组

文章数量:1291024

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?

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?

Share Improve this question edited May 23, 2017 at 10:26 CommunityBot 11 silver badge asked May 29, 2014 at 11:02 WellWellWellWellWellWell 1611 gold badge5 silver badges15 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 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./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;
}

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 plex but possible using jrpc-oo.

If you want to execute in the browser or NodeJS, then you can pile 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 webponent/libWASM.js) :

import modProm from './libwasm.js';

Then create your web ponent and pile your WASM then execute the C++ method Test::sayHello (from the file webponent/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 piled 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++.

本文标签: How to call a C method from javascriptStack Overflow