使用node-addon-api实现从c到nodejs模块全流程

打印 上一主题 下一主题

主题 828|帖子 828|积分 2484

目次

1 前言
2 安装nodejs
3 安装开辟工具链
3.1 安装node-gyp
3.2 安装编译工具链(C/C++ 编译器)
4 初始化 Node.js 项目
4.1 创建项目目次
4.2 初始化 package.json
4.3 安装必要的库
5 编写代码
5.1 创建项目结构
5.2 编写动态库代码
5.3 编写 Node.js 原生模块代码
5.4 设置 binding.gyp
6 编译模块
7 测试模块


1 前言

我们的客户端是使用electron打包的前端步调,因为electron基于nodejs的,所以我们想实现先用c/c++实现拉流+内容解密+硬件解码+硬件格式转换的功能,然后让nodejs去调用c/c++的库,我们调研了下面3种方式:

  • webassembly:因为webassembly是运行在沙箱环境,无法访问网络资源,所以这种方式不可用。
  • node-ffi:这种方式不必要编写额外的c/c++代码,直接使用已经编译好的库就行,但我们验证发现使用node-ffi对node版本有要求,高于16的node版本无法使用,这违背了公司的安全规定。
  • node-addon-api:这种方式必要对每一个袒露的接口重写一遍,这轻微贫苦,但幸亏性能比力好且对于node版本没有什么限制,我们终极使用这种方法。
作为一个前端小白,下面具体的纪录下如何将一个c语言写的库使用node-addon-api封装为nodejs的模块,过程中碰到一些坑并终极解决,希望其他朋友可以参考下。感谢chatgpt给予的帮助,下面内容参考chatgpt的回答,且已经得到完全的验证。
安装nodejs

在我的debian环境下使用下面下令来安装nodejs
  1. curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo
  2. apt-get install -y nodejs
复制代码
3 安装开辟工具链

3.1 安装node-gyp

  1. sudo npm install -g node-gyp
复制代码
3.2 安装编译工具链(C/C++ 编译器)

  1. sudo apt-get install -y build-essential
复制代码
4 初始化 Node.js 项目

4.1 创建项目目次

  1. mkdir c2node_example
  2. cd c2node_example
复制代码
4.2 初始化 package.json

  1. npm init -y
复制代码
4.3 安装必要的库

  1. npm install node-addon-api
复制代码
5 编写代码

5.1 创建项目结构

创建以下文件和目次:
  1. c2node_example
  2. ├── binding.gyp
  3. ├── index.js
  4. ├── native
  5. │   ├── addon.cc
  6. │   ├── example.c
  7. │   └── example.h
  8. └── package.json
复制代码
5.2 编写动态库代码

创建 native/example.c 和 native/example.h:
native/example.h:
  1. #ifndef EXAMPLE_H
  2. #define EXAMPLE_H
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. int add(int num1, int num2);
  7. void say_hello(const char* name);
  8. #ifdef __cplusplus
  9. }
  10. #endif
  11. #endif
复制代码
native/example.c:
  1. #include <stdio.h>
  2. #include "example.h"
  3. int add(int num1, int num2) {
  4.         return num1 + num2;
  5. }
  6. void say_hello(const char* name) {
  7.         printf("hello,%s!\n", name);
  8. }
复制代码
生成动态库:
  1. cd native
  2. gcc -shared -fPIC -o libexample.so example.c
  3. cd ..
复制代码
5.3 编写 Node.js 原生模块代码

创建 native/addon.cc,用于封装 C 动态库。
native/addon.cc:
  1. #define NAPI_DISABLE_CPP_EXCEPTIONS
  2. #include <napi.h>
  3. #include "example.h"
  4. Napi::Value Add(const Napi::CallbackInfo& info) {
  5.     Napi::Env env = info.Env();
  6.     int a = info[0].As<Napi::Number>().Int32Value();
  7.     int b = info[1].As<Napi::Number>().Int32Value();
  8.     int result = add(a, b);
  9.     return Napi::Number::New(env, result);
  10. }
  11. Napi::Value SayHello(const Napi::CallbackInfo& info) {
  12.     Napi::Env env = info.Env();
  13.     std::string name = info[0].As<Napi::String>().Utf8Value();
  14.     say_hello(name.c_str());
  15.     return env.Null();
  16. }
  17. Napi::Object Init(Napi::Env env, Napi::Object exports) {
  18.     exports.Set("add", Napi::Function::New(env, Add));
  19.     exports.Set("sayHello", Napi::Function::New(env, SayHello));
  20.     return exports;
  21. }
  22. NODE_API_MODULE(addon, Init)
复制代码
5.4 设置 binding.gyp

binding.gyp
  1. {
  2.   "targets": [
  3.     {
  4.       "target_name": "addon",
  5.       "sources": ["native/addon.cc"],
  6.       "include_dirs": ["./node_modules/node-addon-api"],
  7.       "libraries": ["-L../native", "-lexample"],
  8.       "cflags": ["-fno-exceptions"],
  9.       "xcode_settings": {
  10.         "OTHER_CFLAGS": ["-fexceptions"]
  11.       }
  12.     }
  13.   ]
  14. }
复制代码
这里碰到了一个坑,可就是libraries的设置,不能写成-L./native,因为会在build目次下执行相应的下令,这个花费了很长时间才解决。

6 编译模块

在项目根目次运行以下下令:
  1. npx node-gyp configure
  2. npx node-gyp build
复制代码
生成的模块文件位于 build/Release/addon.node
7 测试模块

编写 index.js:
  1. const addon = require('./build/Release/addon');
  2. console.log("5 + 3 =", addon.add(5, 3)); // 输出: 5 + 3 = 8
  3. addon.sayHello("Node.js"); // 输出: Hello, Node.js!
复制代码
运行测试:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

民工心事

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表