Nodejs的C/C++ addons机制是怎么实现的?

Nodejs的C/C++ addons机制是怎么实现的?

它的编译器是GCC吗?原理是否跟GCC编译共享库的原理一样?

6 回复

Node.js 的 C/C++ Addons 机制是如何实现的?

Node.js 提供了一种强大的方式来扩展其功能,即通过编写 C/C++ Addons。这些 Addons 是用 C 或 C++ 编写的原生模块,可以直接与 Node.js 进行交互。下面我们来看看这种机制是如何实现的。

1. 原理概述

Node.js 的 C/C++ Addons 机制并不直接依赖于 GCC(尽管 GCC 可以用来编译这些 Addons),而是依赖于 Node.js 的 node-addon-api 和 V8 引擎的 API。这个机制允许开发者编写高性能的原生代码,并将其无缝集成到 Node.js 应用程序中。

2. 编写一个简单的 C++ Addon

首先,我们需要安装 node-gyp 工具,它是一个 Node.js 模块构建工具,用于编译 C/C++ Addons。

npm install -g node-gyp

接下来,我们创建一个简单的 C++ Addon 示例:

addon.cc

#include <napi.h>

// 定义一个简单的函数
Napi::String SayHello(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  return Napi::String::New(env, "Hello from C++!");
}

// 导出函数
Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "sayHello"),
              Napi::Function::New(env, SayHello));
  return exports;
}

NODE_API_MODULE(addon, Init)

binding.gyp

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ]
    }
  ]
}

3. 构建和使用 Addon

在项目根目录下运行以下命令来构建 Addon:

node-gyp configure build

然后,你可以在 Node.js 中使用这个 Addon:

index.js

const addon = require('./build/Release/addon');

console.log(addon.sayHello()); // 输出: Hello from C++!

4. 总结

通过上述步骤,你可以看到 Node.js 的 C/C++ Addons 机制并不完全依赖于 GCC,而是通过 node-addon-apinode-gyp 工具来编译和加载 C/C++ 代码。这种方式使得开发者可以充分利用 C/C++ 的性能优势,同时保持与 Node.js 生态系统的兼容性。

希望这个示例能帮助你理解 Node.js 的 C/C++ Addons 机制。


V8 好像有这个API

技术上说就是动态库,windows下就是 dll

Linux下是gcc和共享库,笔者亲测……

#define NODE_MODULE(modname, regfunc)                                 \
   extern "C" {                                                        \
     NODE_MODULE_EXPORT node::node_module_struct modname ## _module =  \
     {                                                                 \
       NODE_STANDARD_MODULE_STUFF,                                     \
       regfunc,                                                        \
       NODE_STRINGIFY(modname)                                         \
     };                                                                \
   }

NODE_MODULE(name, init);展开后就是:

extern "C" {
    node::node_module_struct name_module =
    {
        1,//NODE_MODULE_VERSION
        NULL,
        __FILE__,
        init,
        "name"
    };
}

其实就是定义了一个结构体,编译后为动态链接库 .node 文件中的一个符号,最后使用的时候由 node.cc 调用uv_dlopenuv_dlsym动态链接模块,得到初始化函数并执行。

mod->register_func(target);

uv库封装了对动态链接文件操作的具体实现,win下实际调用 LoadLibraryExW 和 GetProcAddress,*nix下实际调用dlopen和dlsym实现上诉功能。

Node.js 的 C/C++ Addons 机制允许开发者用 C 或 C++ 编写高性能的原生模块。这些模块可以在 Node.js 中直接调用,从而提高性能或访问底层系统功能。这个机制并不直接使用 GCC 作为编译器,而是依赖于 Node.js 提供的 API 和工具链来生成可被 Node.js 加载的动态链接库(.node 文件)。

实现原理

  1. 定义模块接口:你需要创建一个 C/C++ 文件,通过 NODE_MODULE 宏定义你的模块接口。
  2. 编写初始化函数:该函数会在加载模块时被调用,用于注册导出给 JavaScript 的函数。
  3. 编译成 .node 文件:使用 Node.js 提供的工具(如 node-gyp)将 C/C++ 代码编译成 .node 文件。
  4. 加载和使用:在 Node.js 中使用 require 函数加载并使用这些 C/C++ 模块。

示例代码

// addon.cc
#include <node.h>
#include <v8.h>

void Method(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world").ToLocalChecked());
}

void Initialize(v8::Local<v8::Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

编译该文件为 .node 文件:

node-gyp configure build

在 Node.js 中使用该模块:

const addon = require('./build/Release/addon');
console.log(addon.hello()); // 输出: world

这个过程涉及到了从 C/C++ 到 V8 引擎的接口绑定,确保了可以高效地传递数据和调用方法。虽然它不直接等同于 GCC 编译共享库的原理,但它们都利用了类似的动态链接库技术来提供扩展功能。

回到顶部