ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # Node.js插件(addons) Node.js 插件是用 C++ 编写的动态链接共享对象,可以使用`require()`函数加载到 Node.js 中,且像普通的 Node.js 模块一样被使用。 它们主要用于为运行在 Node.js 中的 JavaScript 与 C/C++ 库之间的沟通提供接口。 Node.js 在硬件、IoT 领域开始流行就是因为能和 C/C++ 代码合体使用。 官方文档在哪里?V8引擎的头文件代码在此——[V8引擎头文件](https://v8.whyun.com/) # 安装环境 ## Mac 下 安装 Xcode,至少打开过一次,接受它的条款。否则可能会失败! ## Windows 下 如果你通过 scoop 已经安装了 `python`,或者已经安装了 visual studio 2017 那么,你不需要再 `windows-build-tools` 了: ``` npm i -g windows-build-tools ``` [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) 主要是安装以下两个: * using Python version 3.8.5 found at "C:\Users\ChandlerVer5\scoop\apps\python\current\python.exe" * using VS2017 (15.8.28010.2036) found at: find VS "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools" > MSbuild是什么,参考msdn:[https://msdn.microsoft.com/zh-cn/library/0k6kkbsd.aspx](https://msdn.microsoft.com/zh-cn/library/0k6kkbsd.aspx) ## Linux 1. python 2. [make](https://www.gnu.org/software/make/) 3. 适当的 C/C + + 编译器工具链,比如 [GCC](https://gcc.gnu.org/) ## node-gyp GYP(全称是 Generate Your Project, 是一个用 Python 实现的[工具](https://en.wikipedia.org/wiki/GYP_(software)),所以需要环境里有对应的python)是比 Makefile 更高层次的一种 C/C++(其他语言未知)代码编译工具。 使用 [node-gyp](https://github.com/nodejs/node-gyp) 可以方便开发者直接源码分发(`binding.gyp`),用户在安装的时再直接编译,方便跨平台。 ``` npm i -g node-gyp ``` 安装过程,如果卡住,不要手动结束!(否则如果编译期间出``现莫名错误,需要重新安装,参考下面*故障问题*) > [GYP介绍](https://blog.csdn.net/xiaoshixiu/article/details/94359960) ## node-gyp 故障问题 1. 首先清除根目录下的`.node-gyp` 2. 卸载 node-gyp 模块 ``` npm uninstall node-gyp -g ``` # 开发方式 nodejs 与 C/C++ 交互目前主流的方式有两种:[N-API](https://github.com/nodejs/node-addon-api) 和 [node-ffi](https://github.com/node-ffi/node-ffi) 。 ## node-ffi(不推荐这种方式) [node-ffi](https://github.com/node-ffi/node-ffi) 是一个用于使用纯 JavaScript 加载和调用动态库的 Node.js 插件。它可以用来在不编写任何 C++ 代码的情况下创建与本地 DLL 库的绑定。同时它负责处理跨 JavaScript 和 C 的类型转换。 ~~~ 1. 性能有折损 2. 类似其他语言的 FFI 调试,此方法近似黑盒调用,差错比较困难。 ~~~ ## N-API http://nodejs.cn/s/eGYeBR [N-API](https://nodejs.cn/api/n-api.html) 类似于 Native Abstractions for Node([NAN](https://github.com/nodejs/nan)) 项目,但是是由 nodejs 官方维护,从此就不需要安装外部的依赖来导入到头文件。并且提供了可靠的抽象层 它暴露了`node_api.h`头文件,抽象了 nodejs 和包的内部实现,每次 Nodejs 更新,N-API 就会同步进行优化保证 ABI 的可靠性。 * [这里](https://nodejs.cn/api/n-api.html)是 N-API 的所有接口文档, * [这里](https://nodejs.org/zh-cn/docs/guides/abi-stability/#n-api)是官方对 N-API 的 ABI 稳定性的描述 N-API 同时适合于 C 和 C++,但是 C++ 的 API 使用起来更加的简单,于是,node-addon-api 就应运而生。 ### 使用 node-addon-api 它有自己的头文件`napi.h`,包含了 N-API 的所有对 C++ 的封装,并且跟 N-API 一样是由[官方维护](https://github.com/nodejs/node-addon-api)。因为它的使用相较于其他更加的简单,所以在进行 C++ API 封装的时候优先选择该方法。 > [前端使用 node-gyp 构建 Native Addon](https://www.cnblogs.com/BigJ/p/Cxx2JS.html) # 示例 当然官方提供了很多 C++ 插件的示例:https://github.com/nodejs/node-addon-examples ,所示的例子是直接使用 Node.js 和 V8 的 API 来实现插件。 先创建 `addon.cc ` 文件,这个代码比较好理解: ``` // addon.cc #include <node.h> // 构建与 Node 应用程序的某种接口所必需的 namespace demo { using v8::Exception; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::String; using v8::Value; // 这是 "add" 方法的实现 // 输入参数使用 const FunctionCallbackInfo<Value>& args 结构传入。 void Add(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); // 检查传入的参数的个数 if (args.Length() < 2) { // 抛出一个错误并传回到 JavaScript。 isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "参数的数量错误").ToLocalChecked())); return; } // 检查参数的类型 if (!args[0]->IsNumber() || !args[1]->IsNumber()) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "参数错误").ToLocalChecked())); return; } // 执行操作 double value = args[0].As<Number>()->Value() + args[1].As<Number>()->Value(); Local<Number> num = Number::New(isolate, value); // 设置返回值 (使用传入的 FunctionCallbackInfo<Value>&)。 args.GetReturnValue().Set(num); } void Init(Local<Object> exports) { NODE_SET_METHOD(exports, "add", Add); } NODE_MODULE(NODE_GYP_MODULE_NAME, Init) // 初始化插件,NODE_GYP_MODULE_NAME 即 binding.gyp 中 target_name } // namespace demo ``` `NODE_SET_METHOD` 接受三个参数: 1. exports 对象 2. 函数将导出的名称 3. 函数本身 通过在顶部添加 `using v8;`,可以从类型中省略所有`v8::`命名空间说明符,这可能导致名称冲突,因此请小心使用它们。 在 c++ 世界中,我们可以自由地使用 c++ 内置的类型,但是当我们处理 JavaScript 对象以及与 JavaScript 代码的互操作性时,我们必须将 c++ 类型转换为 JavaScript 上下文可以理解的类型。这些是在`v8::`命名空间中公开的类型,比`如v8::String`或`v8::Object`。 所有的 Node.js 插件都必须按照下面的模式导出一个初始化函数: ``` void Initialize(v8::Local exports); NODE_MODULE(module_name, Initialize) ``` 创建 `binding.gyp` 文件 内容一看就懂 ``` { "targets": [ { "target_name": "addon", "sources": [ "addon.cc" ] } ] } ``` 然后依次执行两个命令 ``` $ node-gyp configure build ``` 编译完成后在 `build/Release/` 下面会有一个 `addon.node` 文件。再创建 `test.js`文件: ```js // test.js const addon = require('./build/Release/addon'); console.log('This should be eight:', addon.add(3, 5)); ``` 执行 `$ node test.js` 打印出了 `This should be eight:8`。 # 参考 > https://nodeaddons.com/ > [从暴力到 NAN 再到 NAPI——Node.js 原生模块开发方式变迁](https://www.jianshu.com/p/68b134e5ece3) > [nodejs-C++ 插件](http://nodejs.cn/api/addons.html#addons_function_arguments) > [Node.js C++ 插件学习指南](https://www.cnblogs.com/lovesong/p/11217244.html) > [Node.js介绍4-Addon](https://www.jianshu.com/p/e14815ff52ee)