是否有可能在C(而不是C ++)中编写node.js扩展?

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

如果需要,可以用C语言编写扩展的部分内容,但是至less需要一小部分C ++代码来将C代码和Node结合在一起。

正如你将在HelloWorld中看到的那样,扩展依赖于v8.hnode.h头文件,这些头文件包含了Node所期望的所有类。 没有这些,你将无法正确地创buildJS对象导出回节点。

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

在黑客新闻上find这个:

https://github.com/wesolows/v8plus

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

这一层提供了一种方法来写至less在C中的简单的节点插件没有所有可怕的C ++ goop你否则会被使用。 那个goop仍然存在,但你不必写。 更重要的是,你可以在一个健全的编程环境中编写你的模块,避免混淆和容易出错的C ++语义。

需要使用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插件的示例代码

现在我们至less有三个不错的select:

node-ffi: Node.js外部函数接口
用于使用纯JavaScript加载和调用dynamic库的插件。 它可以用来创build绑定到本地库而无需编写任何C代码
https://github.com/node-ffi/node-ffi

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

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

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

可以使用不透明types来编写extern "C"包装器,以满足你在node.h和v8.h中需要的所有东西,但是使用C ++代替它(当然这可以调用C代码)可能更容易。

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

然后你可以使用node-ffi来与它接口(这里没有C ++知识)。

下面是我使用MSVS在Windows上创build的:

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

testlib.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

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

npm install ffi (目前需要构build工具,查看说明)

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里有networking,工作线程和其他选项。