使用C++和N-API编写NodeJS插件的初学者指南
使用 C++ 和 N-API 编写 NodeJS 插件的初学者指南
在 Node.js 开发中,编写插件的需求可能源于以下几个原因:
- 需要访问一些使用 JavaScript 难以操作的原生 API。
- 希望集成用 C/C++ 编写的第三方库,并直接在 Node.js 中调用。
- 出于性能优化的考虑,可能需要将部分模块用 C++ 重写。
无论你的理由是什么,这篇文章将重点介绍如何使用 N-API 构建基于 C/C++ 的 Node.js 插件。
什么是 N-API?
N-API 是一个稳定的 API,用于通过 C 或 C++ 构建 Node.js 插件。从 Node.js v10 开始,N-API 已经成为稳定功能(在 v8 和 v9 中为实验性功能)。使用 N-API 构建的插件可以在不同版本的 Node.js 中保持兼容性。
为了简化开发,我们将使用 node-addon-api 包。它是 N-API 的 C++ 包装器,提供了低开销的 C++ 对象模型和异常处理语义。
创建基本的 Node.js 项目并测试插件
初始化项目
首先,创建一个新的 Node.js 项目并初始化:
mkdir test-addon
cd test-addon
git init
npm init
安装依赖
安装必要的依赖项:
npm install node-gyp --save-dev
npm install node-addon-api
node-gyp是用于编译插件的工具链。node-addon-api是一个辅助库,简化了 C++ 插件的开发。
配置项目文件
在 package.json 文件中,添加以下属性:
"gypfile": true
然后创建 binding.gyp 文件,用于定义编译配置:
{
"targets": [
{
"target_name": "testaddon",
"sources": ["cppsrc/main.cpp"]
}
]
}
接着,在 package.json 中指定主文件为 index.js。
编译并运行插件
构建插件
运行以下命令编译插件:
npm run build
如果一切顺利,你应该会看到类似以下的输出:
> test-addon@1.0.0 build
> node-gyp rebuild
测试插件
创建 index.js 文件,并添加以下内容:
const addon = require('./build/Release/testaddon');
console.log(addon);
运行 index.js,你应该看到插件的输出。
导出 C++ 函数到 Node.js
示例:导出简单函数
创建一个新的 C++ 文件 cppsrc/Samples/functionexample.cpp,内容如下:
#include
Napi::String HelloWrapped(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
return Napi::String::New(env, "Hello World");
}Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "hello"), Napi::Function::New(env, HelloWrapped));
return exports;
}NODE_API_MODULE(addon, Init)
修改 binding.gyp 文件,将新文件添加到 sources 中:
"sources": ["cppsrc/main.cpp", "cppsrc/Samples/functionexample.cpp"]
重新运行构建命令:
npm run build
更新 index.js 文件以测试新功能:
const addon = require('./build/Release/testaddon');
console.log(addon.hello());
运行 index.js,你应该看到以下输出:
Hello World
导出带参数的函数
示例:实现加法函数
在 cppsrc/Samples/functionexample.cpp 中,添加以下代码:
Napi::Number AddWrapped(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
double arg0 = info[0].As().DoubleValue();
double arg1 = info[1].As().DoubleValue();
return Napi::Number::New(env, arg0 + arg1);
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "add"), Napi::Function::New(env, AddWrapped));
return exports;
}
重新构建并运行以下代码:
const addon = require('./build/Release/testaddon');
console.log(addon.add(5, 10));
输出结果应为:
15
导出 C++ 类到 Node.js
示例:创建一个简单类
创建 cppsrc/Samples/classexample.h 和 cppsrc/Samples/classexample.cpp 文件,定义一个简单的 C++ 类,并将其导出到 Node.js。
classexample.h:
#include
class ClassExample : public Napi::ObjectWrap {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports);
ClassExample(const Napi::CallbackInfo& info);private:
double value_;
Napi::Value GetValue(const Napi::CallbackInfo& info);
void SetValue(const Napi::CallbackInfo& info, const Napi::Value& value);
};
classexample.cpp:
#include "classexample.h"
Napi::Object ClassExample::Init(Napi::Env env, Napi::Object exports) {
Napi::Function func = DefineClass(env, "ClassExample", {
InstanceMethod("getValue", &ClassExample::GetValue),
InstanceMethod("setValue", &ClassExample::SetValue)
}); exports.Set("ClassExample", func);
return exports;
}ClassExample::ClassExample(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) {
this->value_ = info[0].As().DoubleValue();
}Napi::Value ClassExample::GetValue(const Napi::CallbackInfo& info) {
return Napi::Number::New(info.Env(), this->value_);
}void ClassExample::SetValue(const Napi::CallbackInfo& info, const Napi::Value& value) {
this->value_ = value.As().DoubleValue();
}
在 binding.gyp 中添加新文件,并重新构建项目。
测试代码:
const addon = require('./build/Release/testaddon');
const instance = new addon.ClassExample(4.3);
console.log(instance.getValue());
instance.setValue(7.6);
console.log(instance.getValue());
输出结果:
4.3
7.6
总结
通过本文的介绍,我们学习了如何使用 N-API 和 C++ 开发 Node.js 插件。从简单的函数导出到复杂类的实现,N-API 提供了强大的功能和稳定的接口。如果你想深入了解,可以参考 完整代码示例。希望本文能帮助你更好地理解和使用 N-API! 🚀
原文链接: https://blog.atulr.com/node-addon-guide/
最新文章
- 构建更智能的搜索:面向开发者的Anthropic AI API – Just Think AI
- 基于N-API和node-addon-api的Node.js异步C++扩展
- 理解每种API类型的基本指南
- REST API 安全最佳实践
- 银行卡OCR识别API在Java、Python、PHP中的使用教程
- 使用WEB3钱包API实现智能合约交互的完整教程
- 如何获取心知天气 API Key 密钥(分步指南)
- REST APIs与微服务:关键差异
- Sabre API 集成:领先的 GDS 实践经验
- 函数调用与工具使用入门 – Apideck
- 什么是API测试?其优势、类型及最佳实践
- API 安全策略和基础指南