21

一个快速的谷歌搜索产生了至少一个为 node.js 编写C++“Hello World”的教程,但目前还不清楚是否可以只使用 C 来编写这样的扩展。假设有可能,我会面临哪些挑战/限制?

4

6 回答 6

17

如果您愿意,您可以用 C 编写部分扩展,但您至少需要一小部分 C++ 代码来将您的 C 代码与 Node.js 粘合在一起。

正如您将在 HelloWorld 中看到的那样,扩展依赖于v8.hnode.h标头,它们具有 Node 期望的所有类。没有这些,您将无法正确创建 JS 对象以导出回 Node。

也就是说,您可以很容易地编写一小组只调用 C 函数的 C++ 函数,并包装某种 C 结构。

于 2012-05-06T15:10:20.190 回答
8

在黑客新闻上找到了这个:

https://github.com/wesolows/v8plus

v8+:节点插件 C++ 到 C 边界

这一层提供了一种用 C 语言编写至少简单的 Node 插件的方法,而无需使用所有可怕的 C++ goop。那个 goop 仍然存在,但你不必写它。更重要的是,您可以在一个健全的编程环境中编写您的模块,避免令人困惑和容易出错的 C++ 语义。

于 2012-05-28T14:29:05.007 回答
6

现在我们至少有 3 个不错的选择:

node-ffi: Node.js 外部函数接口
插件,用于使用纯 JavaScript 加载和调用动态库。它可用于创建与本机库的绑定,而无需编写任何 C 代码
https://github.com/node-ffi/node-ffi

SWIG:简化的包装器和接口生成器
(它为多种语言生成包装器,一次解决了许多问题)
http://www.swig.org/

emscripten 将
C 和 C++ 编译成高度可优化的 JavaScript,即使在 Web 上也能以接近本机的速度运行,无需插件。
http://kripken.github.io/emscripten-site/

于 2015-06-06T05:09:39.337 回答
5

需要使用 extern "C" 语法在 C++ 代码中声明单个 C 函数

例子:

#define BUILDING_NODE_EXTENSION
#include <node.h>

extern "C" void f(int i, char c, float x);

using namespace v8;

如果您有多个 C 函数,则可以通过大括号对其进行分组:

extern "C" {
  void   f(int i, char c, float x);
  int    g(char* s, char const* s2);
  double sqrtOfSumOfSquares(double a, double b);
}

然后从 C++ 函数调用该函数:

Handle<Value> MyFunction(const Arguments& args) {
  HandleScope scope;
   f(7, 'x', 3.14);    // <--- 
  return scope.Close(String::New("Hello"));
}

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

  Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction);
  Local<Function> fn = tpl->GetFunction();
  fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous

  return scope.Close(fn);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("createFunction"),
      FunctionTemplate::New(CreateFunction)->GetFunction());
}


NODE_MODULE(addon, Init)

注意:使用来自Nodejs Addons的示例代码

于 2012-11-29T01:25:43.507 回答
2

如果您的模块使用 libuv,您可以将其链接到节点可执行文件。它将 libuv 函数导出为共享库。

然后你可以使用 node-ffi 与之交互(这里不需要 C++ 知识)。

这是我在 Windows 上使用 MSVS 的方法:

  • 在 MSVS 中创建新的 DLL 解决方案
  • 下载libuv并将 include 和 lib 文件复制到 MSVS
  • 下载node.lib文件,放到MSVS的lib文件夹下
  • 编译下面的示例源代码,将计时器添加到主事件循环

测试库.c:

#include <stdio.h>
#include <stdlib.h>
#include "uv.h"

void (*p_callback)(int number, char *text);

void timer_cb1 (uv_timer_t* timer, int status) {
  printf("libuv timer here\n", status);
  p_callback(123, "it worked!");
}

void set_timer (int interval, void *pfunction) {
  uv_loop_t *loop;
  uv_timer_t *timer1;

  printf("set_timer called. interval=%d callback=%p\n", interval, pfunction);

  p_callback = pfunction;

  printf("uv_version_string = %s\n", uv_version_string());

  loop = uv_default_loop();
  if (loop == 0) {
    puts("could not get the reference to the default loop");
    return;
  }

  puts("got the default loop. now allocating the timer struct");

  timer1 = (uv_timer_t *) malloc(sizeof(uv_timer_t));
  if (timer1 == 0) {
    puts("malloc failed");
    return;
  }

  puts("initializing timer");
  uv_timer_init(loop, timer1);

  puts("starting timer");
  uv_timer_start(timer1, (uv_timer_cb) &timer_cb1, interval, interval);

  puts("timer created. returning");

}

使用 testlib.def:

EXPORTS set_timer

并记得链接到 node.lib

  • 将创建的 dll 移动到测试文件夹并在那里运行这些命令:

npm install ffi (目前需要构建工具。检查说明)

node test-lib.js

test-lib.js 在这里:

var ffi = require('ffi');

var testlib = ffi.Library('testlib', {
  'set_timer': [ 'void', [ 'int', 'pointer' ] ]
});

var callback = ffi.Callback('void', ['int', 'string'],
  function(number, text) {
    console.log("javascript callback here!!!  number=" + number + "  text=" + text);
  }
);

console.log('registering the callback...');
testlib.set_timer(500, callback);
console.log('done')

动用你的想象力。我们在 libuv 中有网络、工作线程和其他选项...

于 2016-08-25T06:32:26.693 回答
1

直接与 node.js 交互的代码需要用 C++ 编写。

可以extern "C"使用不透明类型为 node.h 和 v8.h 所需的所有内容编写包装器使用C++ 可能更容易(当然,它可以调用 C 代码)。

于 2012-05-06T15:10:31.400 回答