node编写C++扩展文件并引入到项目方案总结

2023-11-07

通过Addon实现可扩展接口(可以将C++插入到前端项目中)

electron API
node c++插件官方文档

编写扩展文件

我们可以编写一个node扩展,按照官方文档一样编辑一个hello.cc

#include <node_api.h>

// 实际暴露的方法,这里只是简单返回一个字符串
napi_value HelloMethod (napi_env env, napi_callback_info info) {
    napi_value world;
    napi_create_string_utf8(env, "world", 5, &world);
    return world;
}

// 扩展的初始化方法,其中 
// env:环境变量
// exports、module:node模块中对外暴露的对象
void Init (napi_env env, napi_value exports, napi_value module, void* priv) {
    // napi_property_descriptor 为结构体,作用是描述扩展暴露的 属性/方法 的描述
    napi_property_descriptor desc = { "hello", 0, HelloMethod, 0, 0, 0, napi_default, 0 };
    napi_define_properties(env, exports, 1, &desc);  // 定义暴露的方法
}

NAPI_MODULE(hello, Init);  // 注册扩展,扩展名叫做hello,Init为扩展的初始化方法

编译扩展

使用binding.gyp完成项目描述

{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "./src/hello.cc" ]
    }
  ]
}

调用扩展

  1. 未方便调用扩展,先安装bindings。npm install --save bindings

  2. 然后,创建app.js,调用刚编译的扩展。

var addon = require('bindings')('hello');
console.log( addon.hello() );  // world
  1. 运行代码,由于N-API当前尚处于Experimental阶段,记得加上–napi-modules标记。
    node --napi-modules app.js

参考

通过Addon(n-api)实现可扩展接口

n-api入门


在项目中引入本地模块

对于某些比较大的项目,我们可能会希望将其划分成多个模块, 或是要将上面编写的插件模块引入主项目:

- module1
	- package.json
	- libs
		- file1.js
- module2
	- package.json
	- index.js

假如我们要在 module2/index.js 中直接引用 file1.js,可能就会写成这样 require('../module1/libs/file1')。这样写并不好,因为:

有时候引用方的文件处在很深的路径下,那么引用地址就得写成 …/…/…/module1/libs/file1,体验很不好。
既然我们将项目划分成了多个模块,肯定是想要降低模块之间的偶合度。这样直接引用文件的做法相当于直接深入到了模块的内部,没有将模块之间隔离出来,低耦合更无从谈起了。
解决 2 号问题最好的做法是提供一个单独的文件作为模块的接口。

module1/index.js 中把我们希望在本模块中暴露出来的函数或类 export 出来,这样的话就相当于给模块提供了一个接口。其他模块只能通过 index.js 提供的内容来访问。
假如以后需要重构 module1,将 file1.js 拆成两个文件,只需要改动一下 module1/index.js即可,不需要修改其他的模块。

现在我们的引用可以写成 require(‘…/module1’) 了,本文章的剩余内容就来讨论一下怎样解决 1 号问题——去掉前面的…。

1. 使用 npm install …/module1

我们可以把 module1 作为依赖安装给 module2。
这样的话,module2 在运行的时候就可以把 module1 当成一个普通的依赖,使用 require(‘module1’) 来引入了。
这个方法的问题在于要安装的 module1 必须在 package.json 文件中有 version 字段,否则无法安装成功。

对于一个应用程序(而不是类库)而言,每次修改都需要更新版本会比较麻烦,而且 npm5 的安装会直接创建一个软链接,会引发更多的问题。

2. 直接修改 package.json 字段,增加依赖

我们可以直接在 module2/package.json 的 dependencies 中增加一个 “module1”: “file:…/module1” 。
这样 npm5 在安装依赖的时候会自动创建相应的软链接,自动给 module1 安装依赖,而且不需要版本号。
但这个特性跟 npm5 的 package-lock 结合起来就出问题了。

对于进行过这些修改的 module2,在安装依赖的时候会把 module1 的 package-lock 也合并进 module2/package-lock.json,再一次使用 npm install 的时候就会提示 enoent ENOENT: no such file or directory

3. 使用 install-local

https://www.npmjs.com/package/install-local

这玩意跟解决方法 1 类似,只不过在 npm5 里面也能直接拷贝文件夹而不是创建软链接。这么做的话还是需要 version 字段,而且对于 module1 的改动不会直接反应到 module2 上,还需要像更新其他模块那样手动更新。

4. 使用 npm link

这个比较神奇。我们可以在 module1 目录下运行 npm link,然后在module2目录下运行npm link module1。这样的话,npm 就会自动在 module2 的 node_modules 目录下创建一个软链接,我们拥有了类似于方法 2 的效果,并且不会修改 package-lock。

但是它也不会修改 package.json。也就是说我们拿到项目源代码之后不能直接用 npm i 来安装所有依赖,还必须得加一步 npm link 才行,还是太麻烦了。

5. 使用 require-rewrite

https://www.npmjs.com/package/require-rewrite
这个方法解决了上述的所有问题。我们只需要配置一下 module2 的 package.json,加入 module1 的路径,这样就能使用require(‘module1’)来引入模块了。

不过,这个方法又引入了两个新的问题:

  1. 引入的时候得多写一步。
    我们必须要在 require(‘module1’) 前面写上 require(‘require-rewrite’)(__dirname) 才能在本文件中引入此模块。
  2. 静态代码分析失效了。
    如果你用 webstorm 的话,它显然是没法通过重写过的路径来找到 module1 的实际路径的,那基于此的代码补全也就失效了。

6. 使用 postinstall 钩子手动创建软链接

我们可以在 module2 的 package.json 的 script 字段中新建一个:

"postinstall": "node -e "
var s='../module1',
d='./node_modules/module1',
fs=require('fs'), 
r=require('path').resolve;
fs.exists(d,function(e){e||fs.symlinkSync(r(s),r(d),'junction')});""

它的命令名称为 postinstall,使得这个命令会在 npm install 安装结束之后自动执行。
它执行一段 node 脚本来自动创建链接,起到了跟 npm link 相似的效果。
只要把其中的 module1 更换成你自己的模块路径即可。
注意其中的 junction,这个参数只在 windows 下才有效果,*Unix 下这个参数是什么都没有关系。junction 代表创建目录链接。

其实这个解决办法还是有两个小问题:

  1. 不会自动安装依赖的依赖
    在 module2 下执行 npm install 并不会自动给 module1 安装依赖。

  2. 在 root 权限下执行会有问题
    默认情况下,在 root 权限下执行 npm install 会阻止 postinstall 脚本运行。我们可以使用普通权限来安装或者使用 npm install --unsafe-perm 来安装。


参考

https://juejin.cn/post/6844903582337237006
https://www.dazhuanlan.com/michael_chengzi/topics/1353246
https://blog.csdn.net/allen8612433/article/details/106937163
https://blog.csdn.net/fanweilin0123/article/details/106458861

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

node编写C++扩展文件并引入到项目方案总结 的相关文章

  • Monotouch全局异常处理

    我在野外发现了一只令人讨厌的虫子 但我无法确定它的具体情况 有没有办法拥有全局 Try Catch 块 或者有办法处理 Monotouch 中未处理的任何异常 我可以包起来吗UIApplication Main args 在 try cat
  • 无法加载程序集问题

    我收到以下错误 无法加载程序集 错误详细信息 System BadImageFormatException 无法加载文件或程序集 文件 或其依赖项之一 该程序集是由比当前加载的运行时更新的运行时构建的 无法加载 该程序集是使用 Net Fr
  • Visual Studio 中列表框的上移、下移按钮[重复]

    这个问题在这里已经有答案了 我正在尝试制作一个上移按钮和一个下移按钮 以移动 Microsoft Visual Studio 2012 中列表框中的选定项目 我已经在 WDF jquery winforms 和其他一些表单中看到了其他示例
  • 调用异步方法在视图模型的构造函数中加载数据有警告

    我的视图包含一个 ListView 它显示来自互联网的一些数据 我创建一个异步方法来加载数据并在我的视图模型的构造函数中调用该方法 它有一个警告提示我现在使用await关键字 还有其他解决方案可以在构造函数中异步加载数据吗 有几种可以应用的
  • 谷歌绘制具有相同比例的多个系列的图表

    我正在寻找一种在图形上显示多个系列的方法 这些系列具有相同的比例但仅显示一次 正如你在这里看到的 http jsfiddle net Youkoal d3xwnqdu http jsfiddle net Youkoal d3xwnqdu 我
  • 更改 Xamarin.Forms 应用中顶部栏和底部栏(ControlsBar、StatusBar)的颜色

    无论如何 即使后面需要特定于平台的代码 也可以更改顶部栏 蓝色的 和底部栏 黑色的 的颜色吗 我希望添加对浅色和深色模式的支持 因此我希望能够在运行时更改它 有可能的 Android Using Window SetStatusBarCol
  • 如何构建一棵与或树?

    我需要一个支持 与 和 或 的树结构 例如 给定一个正则表达式 如ab c d e 我想把它变成一棵树 所以 一开始我们有两个 或 分支 它可以向下ab or c d e 如果你低头ab分支 你得到两个节点 a and b or a其次是b
  • 如何使用jquery点击眼睛图标时显示和隐藏密码

    我需要在单击眼睛图标时显示和隐藏用户密码 因此我为此编写了脚本 当我单击眼睛图标时 只有类正在更改 但密码不可见 再次单击斜线眼睛图标 它应该隐藏这两个图标方法不起作用如何解决这个问题
  • Javascript For 循环在 dom 元素上执行[重复]

    这个问题在这里已经有答案了 我有 javascript 代码来获取具有类名称的元素 并迭代从元素中删除该类 var elements document getElementsByClassName test console log Leng
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • DataGridView 行背景颜色没有改变

    我想根据加载时的特定条件更改 DGV 行的背景颜色 即使在 Windows 窗体中也是如此 但我看不到任何 DGV 行的颜色有任何变化 谁能告诉我如何解决这个问题 private void frmSecondaryPumps Load ob
  • 如何在 C# 中更改公共 IP 地址

    我正在创建一个 C winform 应用程序 我想在其中更改公共 IP 地址 而不是像 Hotspot Shield ZenMate OpenVPN 等那样更改 IPv4 地址 我已经检查了以下链接 但没有找到足够的帮助 所以我发布了这个问
  • 从 DataRow 单元格解析 int [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 如何从 DataRow 单元格解析 int 值 Int32 Parse item QuestionId ToString 这段代码可以工作 但看
  • 如何让 Grunt.js 和 Meteor.js 协同工作?

    我想在我的 Meteor 应用程序中使用简单的复制和串联 但是当 Meteor 在服务器和客户端上运行所有 javascript 文件时 我遇到了问题 而我不希望它们在任何地方运行 它要么只是配置文件 例如Gruntfile js或我想以某
  • Gremlin.net 文本包含等效项

    我正在使用 Gremlin net 库连接到 janus 图形服务器 我使用 cassandra 和弹性搜索进行数据存储和索引 在我使用的 gremlin 语言和 gremlin 控制台中文本包含在属性的文本中进行搜索 我正在使用混合索引
  • D3.js - 更改鼠标悬停时元素的不透明度 IF 条件 = false

    我正在制作一个带有过滤器的交互式 D3 js 图表 当用户单击选定的复选框时 该过滤器会显示点 此外 在鼠标悬停事件上 所选点旁边将出现一个弹出窗口 其中包含一些信息 由于图表上的点数量相对较多 因此我选择在取消选中相应复选框时使相关点变得
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • Boost.asio和异步链,unique_ptr?

    我对异步编程不太熟悉 我有一个问题 我的问题如下 给出 boost asio 中 C 11 的 echo server 示例 http www boost org doc libs 1 60 0 doc html boost asio ex
  • 将一个 IEnumerable 拆分为多个 IEnumerable

    我是 linq 新手 我需要根据指示器将 Couple string text bool Indicator 类型的 IEnumerable 拆分为多个 IEnumerable 我尝试使用skipWhile 和 TakeWhile 但没有找
  • Fancybox修改。如何修改 fancybox 以停止在每个画廊的最后一项? (画廊 1 画廊 2 等)[重复]

    这个问题在这里已经有答案了 我正在为我的照片库使用 fancybox 插件 我有多个包含更多项目 照片 的画廊 我想知道如何在点击每个画廊的最后一个项目时停止幻灯片放映 我的 fancybox js 没有被修改 谢谢 您需要添加该选项loo

随机推荐

  • C# 字符串

    文章目录 C 字符串操作 1 获取长度 2 查找字符 3 字符串替换 4 字符串截取 5 字符串插入 C 类型转换 1 隐式类型转换 2 显式类型转换 C Convert方法和Parse 方法 1 Parse 2 Convert C 装箱和
  • 【机器学习-西瓜书】第5章 神经网络

    5 1 神经元模型 定义 神经网络是由具有适应性的简单单元组成的 广泛并行互连的网络 其组织能够模拟神武神经系统对真实世界物体所做出的交互反应 这里的简单单元指 神经元neuron 在神经网络中 每个神经元与其他神经元相连 当超过一个 阈值
  • Bash脚本自学 - 变量和位置自变量

    变量 在hellothere sh文件里 bin bash FIRST NAME Herbert LAST NAME Lindemans echo Hello FIRST NAME LAST NAME 在指令行输入 chmod u x he
  • [LeetCode] Binary Tree Level Order Traversal 二叉树层次遍历(DFS

    目录 1 Binary Tree Level Order Traversal 二叉树层次遍历 BFS 2 Binary Tree Level Order Traversal II 二叉树层次遍历从低往高输出 BFS 3 Maximum De
  • 如何用dev-c++创建lib(静态链接库)文件

    虽说dev c 适合初学者 但是它的功能还是很强大的 那如何用它制作一个lib 静态链接库 呢 目录 第一步 制作静态链接库 第二步 链接静态链接库 方法一 使用项目 方法二 修改编译选项 第三步 使用库函数 方法一 方法二 第一步 制作静
  • git出现fatal: unable to auto-detect email address (got ‘用户@PC机.(none)’)

    git出现fatal unable to auto detect email address got 用户 PC机 none 解决方法 cd git 进入git中的 git文件夹 找到config vim config 按i进入编辑模式 在
  • Linux入门

    1 1 Linux操作系统简介 Linux是一套免费使用和自由传播的类Unix操作系统 是一个基于POSIX和UNIX的多用户 多任务 支持多线程和多CPU的操作系统 它能运行主要的UNIX工具软件 应用程序和网络协议 它支持32位和64位
  • MP4中同时有逐行、隔行编码视频内容

    公司做了个MP4视频 一部分是逐行的 一个部门是隔行扫描方式 用mediainfo看了下 整个显示视频信息为 Scan Type Interlaced Scan Order TFF 用Stream Eye观看视频 隔行部分如下图 逐行部分
  • Windows Qt设置环境变量

    目录 附 其他相关文章 问题 在Qt软件中新建项目 可以直接构建运行 但是当我们直接双击运行项目构建生成的exe文件时 会提示以下内容 由于找不到 Qt5Core dll 无法继续执行代码 重新安装程序可能会解决此问题 另外 可能还会有Qt
  • 关于vue项目在IE11上遇到的兼容性问题

    1 chunk vendors js语法错误 分析 sockjs client包的语法错误 解决 在vue config js中配置transpileDependencies属性 module exports 打包时将转化成低语法 tran
  • 【Django基础学习】python manage.py inspectdb相关的一些问题和解决方案

    Django 之 inspectdb inspectdb简单介绍 具体用法 在Django项目下 python manage py inspecdb gt your app name models py 作用 众所周知 Django较为适合
  • windows系统中通过 运行(win+R) 的方式打开电脑程序或文件夹

    或许你有这样的经历 在电脑 win系统 中 按下win徽标加R键会弹出 运行对话框 里面输入 notepad mspaint snippingtool等后会出来系统的程序 那么我们如何也这样打开自己的程序 或文件夹呢 从而让桌面变得较为干净
  • AR-虚实融合文献阅读整理(一)

    一 增强现实中虚实融合中光照一致性的研究 http xueshu baidu com s wd paperuri 3A 28e867ba9c51b7d137175268533e46399d 29 filter sc long sign tn
  • PCIe专题学习——2.5(Flow control缓存架构及信用积分)

    之前我们讲了对PCIe的一些基础概念作了一个宏观的介绍 了解了PCIe是一种封装分层协议 packet based layered protocol 主要包括事务层 Transaction layer 数据链路层 Data link lay
  • Ubuntu的gcc卸载与安装

    1 卸载旧版本gcc sudo apt get remove gcc 2 添加软件源 sudo add apt repository ppa ubuntu toolchain r test 3 更新 sudo apt get update
  • FIR与IIR滤波器

    H z 有分母的就是IIR 因为有自环 递归型 一个冲激响应会一直在系统里循环 H z 没有分母的就是FIR 因为没有自环 非递归型 一个冲激响应不会在系统里一直循环 通过H Z 也可简单判断 一般FIR滤波器的系统函数无分母 IIR滤波器
  • 网络爬虫-----初识爬虫

    目录 1 什么是爬虫 1 1 初识网络爬虫 1 1 1 百度新闻案例说明 1 1 2 网站排名 访问权重pv 2 爬虫的领域 为什么学习爬虫 2 1 数据的来源 2 2 爬虫等于黑客吗 2 3 大数据和爬虫又有啥关系 2 4 爬虫的领域 前
  • 用户态和内核态的区别

    一 操作系统需要两种CPU状态 内核态 Kernel Mode 运行操作系统程序 操作硬件 用户态 User Mode 运行用户程序 二 指令划分 特权指令 只能由操作系统使用 用户程序不能使用的指令 举例 启动I O 内存清零 修改程序状
  • 数字电路的时序分析

    记录一下时序分析的学习 首先搞清楚以下时序分析时用到的名词 记录一下时序分析的学习 1 什么是setup time和hold time 为什么需要setup time和hold time 2 时序路径是什么 有哪些时序路径 3 如何分析时序
  • node编写C++扩展文件并引入到项目方案总结

    插入模块 通过Addon实现可扩展接口 可以将C 插入到前端项目中 编写扩展文件 编译扩展 调用扩展 参考 在项目中引入本地模块 1 使用 npm install module1 2 直接修改 package json 字段 增加依赖 3