写这篇文章的目的,是为了记录nodejs c++开发过程中踩到的坑,以及解决办法,以备以后回顾。
这里我只记录了windows下开发过程中遇到的问题,linux下的,以后有机会,或者碰到了再记录吧。
首先,大家需要记住,不要被一些报错吓到了,其实如果是一个有经验的c/c++开发者,有些问题其实并不难想到原因是什么,无非就是版本问题、符号问题等等。简单来说,在windows下,使用gyp,会生成一个ms vc工程,我们可以用visual studio打开它,然后编译,这样你可能会觉得熟悉些,好了,让我来解释一些概念或知识点吧(个人经验不是很足,有不对的地方,希望在评论里指出,谢谢)
一,编译后的c++插件是否能用,和node-gyp版本有没有关系?
没有关系。
node-gyp只是一个构建工具,它会生成ms vc工程,最后利用微软的c++编译器,编译生成最终的c++插件,即一个动态库文件。
二,windows下,设置msvs_version有什么影响?
例如很多文章都说要设置为2015,2017等等,我设为2019可不可以?
当然可以,没什么问题。唯一的影响就是,如果插件里使用了特定的函数,那么你发布后,可能还需要给别人安装相应的c++环境。
三,node版本对构建有无影响?
这个影响就大了,非常大!
首先大家都知道,nodejs c++插件开发,有很多种方式,例如nan方式,napi(Node-API)方式,以及node-addon-api方式,或者你直接引用原始的v8、uv库。常用的是napi方式,这种方式是ABI化的,但是有版本的区分,截取官方的一张图:

可以看到,不同版本的napi(横轴1,2,3。。。),在不同版本的node下得到支持(纵轴第一列)
插件的作者(或者你),在开发时的本机环境,可能与使用者是不一样的,所以有时候下载的插件不能通过编译而报错,那么其中之一的检查项,就是检查插件的node api版本。万一作者没写,那就只能一个个试了。(提示,可以安装nvm来切换nodejs版本)
查看本机napi版本的方式:

如图所示,我当前使用的,是 v14.20.0版nodejs,它的napi是8。
当然,如果你的napi版本高于你要测试的版本,例如你的版本是8,你想测试版本3行不行,可以直接在c++预定义符里指定

当然如果你的nodejs的napi版本本身就低于插件所需要的版本,那就只能升级nodejs了。这也是编译报错的原因之一。
这个问题解释也很简单,搞过c/c++开发的都知道,引入第三方库的时候,可以静态引入,也可以动态引入。静态引入,需要一个头文件,需要一个静态库(lib),最后编译时,还需要连接到真正的实现。不过头文件可能是最新的,而静态库可能不是最新的,那么node的作者,就在头文件里指定了NAPI_VERSION的版本,来启用不同的函数:

这里尤其是在electron里引用了c++插件时,需要注意这个问题,因为electron内集成的node,和官方的node版本其实是不完全一样的,除了上述NAPI_VERSION以外,还要注意abi的版本,因为这个限定了API调用的约定,如果不一致,那么即便你编译插件通过了,实际运行electron程序时,依然会报错。
关于electron下引用c++插件,首先要说明的是,你必须注意你的编译环境,即你本机运行的node,和electron内置的node的环境,即运行时环境。这两个环境是不一样的。其次,你可以直接用electron的环境来编译(以下举例,是用electron的环境来编译插件)。
看一下如何查看electron的node环境,除了查看官方文档外,还可以先运行起electron来查看。由于electron编译时,需要下载原始的electron包,那么我们可以找到该包,直接运行electron来查看。此包默认下载到了 C:\Users\用户名\AppData\Local\electron\Cache 下,打开该目录下的dos窗口,然后运行 electron -a ,就可以查看 abi 版本了。其他命令有

electron 的 abi 版本,对应本机 node 的 abi 版本字段是:process.versions.modules
所以,如果你需要编译c++插件,以用于electron,那么在编译时,需要指定运行时环境:
假设你用的 node-gyp 构建
node-gyp rebuild --target=10.1.7 --arch=x64 --dist-url=https://electronjs.org/headers
其中,target即electron的版本,arch即运行时架构,默认就是x64,后面的dist-url,用于告诉node-gyp,哪里去下载头文件、静态库等资源。
这条命令可以放到插件的脚本里运行。
假设你用的 node-pre-gyp 构建,命令和上述差不多
node-pre-gyp rebuild --target=10.4.7 --dist-url=https://electronjs.org/headers --runtime=electron
这里,我在后面指定了runtime为electron,其实不指定,差不多也可以,除非你构建的环境是早期的nodejs(NAPI_VERSION小于3),否则就是兼容的。
待续。。。。。。