如何从 Node.js 调用 C++ 代码?

如何从 Node.js 调用 C++ 代码?

问题描述:

我目前正在开发一个在服务器上运行并应在浏览器中显示数据的模拟器.

I'm currently developing a simulator that runs on a server and should display data in the browser.

为了提供文件、通信和诸如此类的东西,我想使用 Node.js.但是,我不确定它是否会像我希望的那样在计算部门执行,所以我想用 C++ 开发模拟部分.

For serving files, communication and things like that, I'd like to use Node.js. But, I'm not sure if it will perform as well as I'd want it to in the computation department, so I would like to develop the simulation part in C++.

模拟被分成单独的世界",它们都以一些初始参数开始.

The simulation is divided into separate "worlds", which all start with some initial parameters.

最好的方法是什么?

好吧,V8 允许从 JavaScript 调用 C++ 代码.

Well, V8 allows for C++ code to be called from JavaScript.

因此您可以拥有 3 部分代码:

So you can have 3 parts of your code:

  • 普通 C++,不知道 node.js 和 V8.这就是 World 所在的地方.
  • 粘贴 node.js/V8-C++ 代码,让 JS 能够看到"你的 World 类的部分内容.
  • 普通 JavaScript 代码,通过胶水"层与 C++ 端通信
  • Normal C++, unaware of node.js and V8. This would be where World is.
  • Glue node.js/V8-C++ code, allowing JS to "see" parts of your World class.
  • Normal JavaScript code, which communicates with the C++ side via the "glue" layer

首先了解 V8 和 C++ 是如何通信的.Google 为此提供了指南:https://developers.google.com/v8/embed

First, understand how V8 and C++ communicate. Google provides a guide for this: https://developers.google.com/v8/embed

然后,您需要 node.js 特定的胶水.请参阅 http://www.slideshare.net/nsm.nikhil/writing-native-bindings-to-nodejs-in-chttp://syskall.com/how-to-write-your-own-native-nodejs-extension

Then, you need node.js specific glue. See http://www.slideshare.net/nsm.nikhil/writing-native-bindings-to-nodejs-in-c and http://syskall.com/how-to-write-your-own-native-nodejs-extension

来自上面的幻灯片共享链接:

From the slideshare link above:

#include <v8.h>
#include <node.h>

using namespace v8;

extern "C" {
   static void init(Handle<Object> target) {}
   NODE_MODULE(module_name, init)
}

我们可以将其扩展为更接近您想要的内容:

We can expand that into something closer to what you want:

src/world.h

src/world.h

#ifndef WORLD_H_
#define WORLD_H_

class World {
    public:
        void update();
};

extern World MyWorld;

#endif

src/world.cpp

src/world.cpp

#include "world.h"
#include <iostream>

using std::cout;
using std::endl;

World MyWorld;

void World::update() {
    cout << "Updating World" << endl;
}

src/bind.cpp

src/bind.cpp

#include <v8.h>
#include <node.h>
#include "world.h"

using namespace v8;

static Handle<Value> UpdateBinding(const Arguments& args) {
    HandleScope scope;

    MyWorld.update();

    return Undefined();
}

static Persistent<FunctionTemplate> updateFunction;

extern "C" {
   static void init(Handle<Object> obj) {
      v8::HandleScope scope;

        Local<FunctionTemplate> updateTemplate = FunctionTemplate::New(UpdateBinding);

        updateFunction = v8::Persistent<FunctionTemplate>::New(updateTemplate);

      obj->Set(String::NewSymbol("update"), updateFunction->GetFunction());
   }

   NODE_MODULE(world, init)
}

演示/演示.js

var world = require('../build/Release/world.node');
world.update();

脚本

def set_options(opt):
  opt.tool_options("compiler_cxx")

def configure(conf):
  conf.check_tool("compiler_cxx")
  conf.check_tool("node_addon")

def build(bld):
  obj = bld.new_task_gen("cxx", "shlib", "node_addon") 
  obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
  # This is the name of our extension.
  obj.target = "world"
  obj.source = "src/world.cpp src/bind.cpp"
  obj.uselib = []

在 Linux shell 上,一些设置:

On Linux shell, some setup:

node-waf configure

要构建,请运行:

node-waf

测试:

node demo/demo.js

输出:

Updating World