Electron新项目调用 C++ Node 插件问题记录

736 阅读3分钟

最近有个新项目,其中有录屏功能,需要调用 C++ Node 插件。

调试阶段初期,C++ 同事很快就发过来插件 Zip,里面包含 plugin.node 文件。

简单,写个 app.js,直接引入插件,然后打印出来。

const plugin = require("./Plugin/DemoPlugin.node");
console.log(plugin);

用 node 执行 node app.js

没想到直接报错:

DemoPlugin.node is not a valid Win32 application.

这个提示就有迷惑性,语义上来说,是指这个插件不是 32 位的,但 C++ 同事明确地说,这就是 32位,想要 64位还暂时给不了呢。

其实是因为我本地安装的 Node 是 64 位,用 64 位的 Node 启动 32 位的 node 插件,就会出现上面的错误。

怎么看自己本地安装的 Node 是 64 位还是 32 位呢?

参考 stackoverflow.com/questions/2…

node -p "process.arch"

可以看到我的本地输出 x64,如果是 32 位,则是显示 ia32,注意不是 x86。

顺便了解一下,关于 x86、x86-64和IA-32、IA-64 的区别

然后我又下载了 32 位版本的 Node,又发现了新的报错,NODE_MODULE_VERSION 版本不匹配。

Error: The module '\Plugin\DemoPlugin.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 87. This version of Node.js requires
NODE_MODULE_VERSION 108. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).
    at Module._extensions..node (node:internal/modules/cjs/loader:1310:18)
    at Module.load (node:internal/modules/cjs/loader:1089:32)
    at Module._load (node:internal/modules/cjs/loader:930:12)
    at Module.require (node:internal/modules/cjs/loader:1113:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (C:\Users\fujinxiang\Downloads\node-v18.14.0-win-x86\app.js:1:16)
    at Module._compile (node:internal/modules/cjs/loader:1226:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1280:10)
    at Module.load (node:internal/modules/cjs/loader:1089:32)
    at Module._load (node:internal/modules/cjs/loader:930:12) {
  code: 'ERR_DLOPEN_FAILED'
}

刚开始不清楚 Node 版本对应的 NODE_MODULE_VERSION,直接把 node-v18.14.0,node-v16.18.1,node-v15.14.0,node-v14.9.0 的 32 位版本都下载下来,都会报错。

后来发现在 nodejs.org/zh-cn/downl… 有 Node 版本和 NODE_MODULE_VERSION 对应关系。

image.png

Node v14.x 对应 NODE_MODULE_VERSION 83,Node v15.x 对应 NODE_MODULE_VERSION 88。

根本没有 NODE_MODULE_VERSION 是 87 的 Node 版本啊!

难怪 node-v15.14.0,node-v14.9.0 的 32 位都不行。

后来 electron程序,如何理解NODE_MODULE_VERSION? 提供思路。

NODE_MODULE_VERSION 87 这个版本号,其实是来自 Electron。

验证看看,写一个 version.js,内容如下

console.log(process.versions.modules);

执行 electron version.js,输出 87

所以,这个 DemoPlugin.node,其实是 C++ 同事基于 Electron v12.0.16 版本编译的,复用了此前某项目的环境。

image.png

可以看的这个版本的 Electron 有点旧了,而目前新项目中选择的 Electron 版本是 v21.3.0,对应的 Node 版本是 v16.16.0,而 NODE_MODULE_VERSION 是 109。

image.png

所以,接下来,我需要下载 32 位 Electron v21.3.0 版本,并要求 C++ 同事重新编译对应版本的 DemoPlugin.node 插件。

而编译 node 插件,需要对应版本的 node-gyp,但这个 node-gyp 只能从 Electron 去下载,Node 官网并没有对应版本。

网上会找到一些文章告诉我们这样下载,target 后面是 Electron 对应的版本

node-gyp rebuild --target=4.1.5 --dist-url=https://atom.io/download/electron 

但其实这个写法已经过时了,因为 Electron 已经从 atom-shell 更名很久了。

正确的写法应该下面这样,参考 www.electronjs.org/docs/latest…

node-gyp rebuild --target=21.3.0 --arch=ia32 --dist-url=https://electronjs.org/headers

此处一定要注意保证网络情况,可能有必要科学上网,否则可能会遇到类似下面这样的错误。

gyp WARN install got an error, rolling back install
gyp ERR! configure error
gyp ERR! stack Error: EPERM: operation not permitted, unlink 'C:\Users\~\AppData\Local\node-gyp\Cache\21.3.0\arm64\node.lib'
gyp ERR! System Windows_NT 10.0.22000

看起来是权限不足,其实就是网络不行。

执行 node-gyp rebuild --target=21.3.0 --arch=ia32 --dist-url=https://electronjs.org/headers 之后,会在 \AppData\Local\node-gyp\Cache 目录下看到 21.3.0 目录,其中就包含重新编译 node 插件需要的依赖文件。

image.png

至此,问题终于解决。