开发Node的C++插件环境配置说明(以Node-gyp为例)

796 阅读4分钟

前言


基于Node-API构建C++插件目前主要两种构建方式,一种基于node-gyp,一种基于CMake。本文以Node-gyp为示例。

此外,开发Node插件,也有三种方式:

1、基于Nan

适用于Node.js v0.8~v14,不建议使用

2、直接使用内部 V8、libuv 和 Node.js 库

除非需要直接访问 Node-API 未暴露的功能,否则请使用 Node-API

3、Node-API(原N-API)

Node-API 是一种 C API,可确保跨 Node.js 版本和不同编译器级别的 ABI 稳定性。C++ API 可以更容易使用。为了支持使用 C++,该项目维护了一个名为 node-addon-api 的 C++ 封装器模块。此封装器提供可内联的 C++ API。

本文以Node-API为示例。

1、安装 Node.js


如果没有安装 Node.js,请去 Node.js 官网 下载合适版本的 Node.js 并安装。

如果未来不需要多个node版本,可以不使用例如nvm、fnm等包管理器软件

2、配置NPM源(可选项)


本文不再赘述

3、安装Python


本文不再赘述,注意配置Python的环境变量,供node-gyp使用

4、安装 node-gyp


node-gyp 是一个用于编译 Node.js 原生模块的命令行工具,你可以使用 npm 来安装它:

//安装node-gyp包
npm install -g node-gyp

注:在某些系统上可能需要管理员权限(如 Windows 上的管理员提示符或在 Linux/Mac 上使用 sudo)

//默认情况下,Windows 的执行策略可能禁止运行脚本,windows下PowerShell使用管理员权限
//1.使用管理员权限打开 PowerShell  
//    (Windows下可以同时按住Ctrl+Shift,然后点击Windows PowerShell打开软件,临时使用管理员权限)
//2.执行以下命令来更改执行策略:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

//这个命令将允许运行本地作者的脚本以及从 Internet 下载的经过签名的脚本
//它会询问你确认更改执行策略,输入 Y 然后回车
//请记住,改变执行策略可能会影响到系统的安全性




//如果你不想全局更改执行策略,可以尝试以更受限制的方式运行 node-gyp 命令
//将只为单次命令的执行临时绕过执行策略,而不影响全局设置
//windows下PowerShell内执行单次命令提权参考示例:

PowerShell -ExecutionPolicy ByPass -Command "node-gyp install 16.20.2"
 

参考文档:node-gyp - npm (npmjs.com)

如果系统内有具有多个Python版本,需要使用node-gyp的相关命令指明其使用的Python路径

5、安装Visual Studio的C++开发套件


多种方式(5.1、5.2选其一)下载相关套件,注意配置相关环境变量

5.1 按照node-nyp文档的指导

node-gyp npm

image.png

5.2 微软的node环境指导

nodejs-guidelines/windows-environment.md

文档内说明需要安装 Python2.7.10(不支持 v3.x.x

笔者测试Python3.8.6可以,供参考

5.3 配置Visual Studio环境变量

Windows11下配置Visual Studio2022 环境变量(Windows下配置Visual Studio 通用)_visual studio环境变量设置-CSDN博客

笔者用户变量参考:

  • 用户变量:

    • PATH:

image.png

  • 系统变量:

    • INCLUED:

image.png

    • LIB:

image.png

    • PATH:

image.png

6、安装node-addon-api头文件


项目目录下运行如下代码,下载头文件库node-addon-api 使用C++版的头文件napi.h

//下载node插件头文件库
npm install node-addon-api

7、创建原生模块项目


在你的项目目录中,创建一个 binding.gyp 文件来描述你的编译配置,如:

{
  "targets": [
    {
      "target_name": "your_module",  #扩展的名称
      "sources": [ "your_module.cc" ], #扩展的源文件
      "include_dirs": [ #头文件的路径
        "<!@(node -p "require('node-addon-api').include")"
      ],
      "dependencies": [ #需要链接的库
        "<!(node -p "require('node-addon-api').gyp")"
      ],
      'defines': [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
      "libraries": [
        # 这里列出需要链接的第三方 DLL 文件。
        # 如: "<(module_root_dir)/path/to/your/libfile.lib"
        # 如: "WS2_32.lib"
      ],
      # 条件编译
    }
  ]
}
  1. 其中 "sources" 需要列出所有的源代码文件。

8、编写 C++ 代码


在项目的源代码文件中(如 your_module.cc),你可以包含 napi.h 头文件进行开发:

#include <napi.h>

// ... 这里是你的 N-API 使用代码 ...

开发Node的插件,需要参考本文档:Node-API | Node.js v16 文档 (nodejs.cn)

提供一份add方法的插件参考代码:

// add.cc
#include <napi.h>

Napi::Value Add(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  // 检查输入参数个数
  if (info.Length() < 2) {
    Napi::TypeError::New(env, "need two params").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  // 检查参数类型
  if (!info[0].IsNumber() || !info[1].IsNumber()) {
    Napi::TypeError::New(env, "param must be number type").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  // 执行加法
  double value1 = info[0].As<Napi::Number>().DoubleValue();
  double value2 = info[1].As<Napi::Number>().DoubleValue();
  Napi::Number sum = Napi::Number::New(env, value1 + value2);

  return sum;
}

// 初始化 addon
Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "add"),
              Napi::Function::New(env, Add));
  return exports;
}

NODE_API_MODULE(addon, Init)

9、编译模块


接下来,在项目目录下使用以下命令来配置和编译你的原生模块:

node-gyp configure
node-gyp build

这些命令会使 node-gyp 下载对应的 Node.js 头文件,并编译你的模块。

可以使用node-gyp help查看命令,参考:如何使用node-gyp

10、测试模块


写一份JS代码调用插件测试,如下:

// testAdd.js
const addon = require('./build/Release/addonAdd'); //addonAdd为binding.gyp内的target_name

console.log('This should be 8:', addon.add(3, 5));

调用命令:

//执行testAdd.js文件
node testAdd.js

11、参考文档

零基础开发 Node.js Addons 插件:Hello Node-API-腾讯云开发者社区-腾讯云 (tencent.com)

实战篇:开启C++扩展制作之旅——node-addon-api教程前言

node-addon-api/doc/README.md

nodejs/node-addon-examples