Electron集成C++技术选型
技术论证结果:
通过node-gyp实现js和c++相互调用传参,后期再与Electron集成,直接写JS即可。
选型论证需求
研究下c++如何与Electron集成(初步看有两种方案,nodejs集成c++,或者将c++编译wasm,了解两种方案的优劣)
- 实现js中调用c++函数
- 实现c++中调用js函数 需要探索参数传递问题,除了简单的类型,还得看一些复杂的参数如何传递,如对象、函数 写几个demo进行验证,出一篇c++与Electron集成的详细文档
选型方案一:nodejs集成c++(优选)
1. 技术方案特点
Node.js 集成 C++ 是通过 Node.js 的插件机制,将 C++ 模块导入到 Electron 应用中,并实现 JavaScript 与 C++ 的互操作。
2. 优缺点分析
优点:
- 直接利用 Node.js 的插件机制,简化了与 Electron 的集成过程,方便直接调用。
缺点:
- 需要熟悉 Node.js 的插件开发,可能涉及 V8 引擎的 API 调用和内存管理,常规开发基本不涉及。
3. 选择理由
对于 Electron 集成 C++ 的首选技术方案,我会倾向于选择 Node.js 集成 C++,理由:
Electron中可以直接使用通过使用JS调用 C++,利用了 Node.js 的插件(node-gyp)机制,与 Electron 的集成相对简单直接。相比之下,将 C++ 编译为 Wasm 需要额外的工作和配置,同时直接进行语法编译转换,不方便调试,而且可能存在一些限制和兼容性问题。
选型方案二:c++编译wasm
1. 技术方案特点
将 C++ 代码编译为 WebAssembly (Wasm) 格式,可以在浏览器中直接运行,并与 JavaScript 高度集成,大致执行顺序1. 加载框架的 js 文件;2. 框架 js 文件自动加载并编译 wasm 文件;3. 执行 demo 文件。
2. 优缺点分析
优点:
- 跨平台、高性能,与 JavaScript 高度集成,适用于前端和后端代码共享。
- 避免了 Node.js 插件开发的复杂性。
缺点:
- 需要安装额外C++编译环境,如使用 Emscripten 进行编译,直接进行语法编译后还需要进行加载调用wasm,才能使用wasm文件,相当于是将c++语法转化成js语法,编译调试起来困难。
- WebAssembly 目前仍在发展中,可能存在一些限制和兼容性问题。
选型方案一:具体实现
1. 开发环境
电脑环境
window10
node环境
arduino
node版本 17.0.1
npm install -g node-gyp // node-gyp:Node.js 编写 C++ 扩展的构建工具
python环境
python-3.12.0
开发工具vscode
2. 示例说明
本demo示例分为两部分分别为js-cpp-xx和cpp-js-xx。
js-cpp-integration-demo说明:js调用c++文件,进行传值
cpp-js-integration-demo说明:cpp调用js文件,进行传值测试
3. 原理说明
addon.cpp文件中编写c++代码,binding.gyp文件
lua
|-- js-cpp-integration-demo
|-- addon
|-- build // 打包和编译后的文件
|-- addon.cpp // C++代码
|-- binding.gyp // 编译配置
|-- index.js // node入口文件,加载c++打包后文件 require('./addon/build/Release/addon.node');
4. 代码说明
代码执行步骤,以js-cpp-integration-demo为例:
bash
# 导航到你的模块目录
cd xxx/demo/js-cpp-integration-demo/addon
npm install -g node-gyp
# 读取项目根目录下的 binding.gyp 文件,生成编译配置文件
node-gyp configure
# 通过配置文件编译原生Node.js模块
node-gyp build // *** 每次更改C++代码,需要重新编译 ***
cd xxx/demo/js-cpp-integration-demo
node ./index.js
index.js文件执行结果示例:
css
// index.js中打印结果示例:
1.Adding: 13
2.函数回调结果: 测试文字
3.Send(js)Array: [ [ 'aa', 'bb', 'cc', 'dd' ], [ 'aaa', 'bbb', 'ccc', 'ddd' ] ]
Received(cpp): [[aa,bb,cc,dd],[aaa,bbb,ccc,ddd]]
4.Send(js)Object: {
amount: 99,
letters: [ [ 'aa', 'bb', 'cc', 'dd' ], [ 'aaa', 'bbb', 'ccc', 'ddd' ] ]
}
Received(cpp): {
amount: 99.000000,
letters: [['aa', 'bb', 'cc', 'dd'], ['aaa', 'bbb', 'ccc', 'ddd']]
}
index.js中文件代码:
javascript
const addon = require('./addon/build/Release/addon');
// const addon = require('./addon/build/Debug/addon.node'); debugger使用
// 1. 调用cpp函数示例
console.log('1.Adding:', addon.add(3, 10));
// 2. 向cpp传递函数示例
addon.about(function(msg){
console.log('2.函数回调结果:', msg);
})
// 3. 传二维数组值示例
const data = [["aa","bb","cc","dd"],["aaa","bbb","ccc","ddd"]]
console.log('3.Send(js)Array:', data);
addon.jsToCpp2DArray(data)
// 4. 传复杂对象数组值示例
const obj ={ "amount":99, "letters":[["aa","bb","cc","dd"],["aaa","bbb","ccc","ddd"]] }
console.log('4.Send(js)Object:', obj);
addon.jsToCppObject(obj)
说明:示例1和示例2分别为JS调用C++函数和C++调用JS函数示例,并且通过函数进行互相传值。(cpp-js-integration-demo不再赘述,C++调用JS函数,参照示例2)
C++代码见demo中addon文件夹中,代码过长不在文档中展示。