簡體   English   中英

如何從 javascript 調用 C++ 方法

[英]How to call a C++ method from javascript

我有一個 C++ 方法(該角色正在殺死一些進程)。 她需要 2 個參數: a hostname and a port

另一方面,我正在開發一個在 Google Chrome 上運行的網絡應用程序(使用 Nodejs 和 AngularJS)。
當我通過瀏覽器單擊一個按鈕時,我希望能夠通過我的app.js文件調用 C++ function。

我還沒有找到如何將 javascript 與 C++ “綁定”。

編輯:我認為這個鏈接可能非常有用如何使用 node.js 中的 C++ 庫?

您可以使用Google's V8 V8是谷歌的開源JavaScript引擎。 V8可以standalone運行,也可以embedded到任何C++應用程序中。

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

以下來自github演示的示例,將C++類與Google V8綁定。 v8_wrap_class.cpp - 作者是尼古拉斯

/*
 * 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;
}

你可以向你的服務器發一個ajax請求,並在后端調用c ++,也許在php中。 或者這可能很有用https://code.google.com/p/tiny-js/

這個答案給出了在 javascript 中使用 C++ 的四種方法。 所示方法試圖將原始 C++ 保留在標准和簡單的 C++ 實現中。

兩種使用 WASM 的方法和兩種使用 SWIG 和 JRPC 的方法用於給出在 javascript 中執行 C++ 的示例和想法。 詳細地說,這個答案給出了一個在瀏覽器中執行的例子和一個在 nodejs 中使用 WASM 執行的例子。 這個答案的結尾還列出了另外兩種在 javascript 中執行 C++ 的方法,其中一種方法是從瀏覽器調用 nodejs,這種方法稍微復雜一些,但可以使用 jrpc-oo。

如果要在瀏覽器或 nodejs 中執行,則可以將 C++ 編譯為 WASM 並將該模塊加載到瀏覽器或 nodejs 中,在那里執行 C++。 這個WASM repo舉例說明了如何做到這一點。 我將在此處擴展WASM 存儲庫中的關鍵代碼。

創建一些 C++ 代碼並聲明您的 WASM 綁定,例如(來自文件 include/Test.H 和 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)
  ;
} 

將其編譯下來,您現在可以在 nodejs 中運行它(來自文件 nodejs/WASMTestNode.js):

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

在瀏覽器中,您也可以使用 WASM 代碼。 為此,首先導入 WASM 庫(來自文件 webcomponent/libWASM.js):

import modProm from './libwasm.js';

創建您的 Web 組件並編譯您的 WASM,然后執行 C++ 方法 Test::sayHello(來自文件 webcomponent/libWASM.js):

import { LitElement } from 'lit';
export class LibWASM extends LitElement {
 constructor() {
    super();
    modProm().then((mod)=>{
      this.libWASM = mod; // for rendered wasm that delay
      this.WASMReady();
    })
  }

  WASMReady(){
    console.log('LibWASM.libWASM module compiled and ready to go.')
    let test = new this.libWASM.Test;
    test.sayHello();
  }
}

此代碼示例在參考 repo中實現。

或者,第三種方法是僅使用此參考 repo中的 C++、SWIG 和 nodejs。

如果您想從瀏覽器執行 nodejs 或使用其他方法將 C++ 集成到 nodejs 中,您還可以查看此 SWIG 和 jrpc-oo 參考以執行相同的操作,但不僅在 nodejs 中,還從瀏覽器調用 nodejs .

還有其他方法可以從 javascript 執行 C++,但是此答案中演示的方法相當簡單,並且依賴於 WASM 綁定或 SWIG 抽象,從而將您的原始代碼保留為標准 ZF6F87C9FDCF8B3C3F07F93F1EE872。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM