node.js调用C++的一种方案

这篇具有很好参考价值的文章主要介绍了node.js调用C++的一种方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

nodejs官方维护了一套ABI(应用二进制接口),用于完成nodejs和C++的通信。

官网介绍的Node-API是C API,对应的node-addon-api是它的C++版本,更容易使用,本文介绍的也是这个C++的版本。

通过一个示例来说明如何使用node-addon-api

node-addon-api简单示例

1、初始化一个空项目(生成package.json文件)

npm init

2、安装node-addon-api

npm install node-addon-api

接下来,编写一个Calculate类,用于求两个数的和

3、src/Calculate.h

#ifndef __Calculate__
#define __Calculate__

class Calculate
{
public:
    static double add(double, double);
};

#endif

4、src/Calculate.cpp

#include "Calculate.h"

double Calculate::add(double a, double b)
{
    return a + b;
}

5、src/index.cpp,编写C++和nodejs的中间文件

node-addon-api在C++代码中使用,完成数据类型的统一接口的暴露

通过 node-addon-api 暴露与 nodejs 通信的参数

#include <napi.h>
#include "Calculate.h"

Napi::Value Add(const Napi::CallbackInfo& info)
{
    Napi::Env env = info.Env();
    if (info.Length() < 2)
    {
        Napi::TypeError::New(env, "参数个数异常").ThrowAsJavaScriptException();
        return env.Null(); // 返回JavaScript的null
    }
    if (!info[0].IsNumber() || !info[1].IsNumber())
    {
        Napi::TypeError::New(env, "参数类型异常").ThrowAsJavaScriptException();
        return env.Null();
    }
    // Napi::Value -> Napi::Number
    double arg0 = info[0].As<Napi::Number>().DoubleValue();
    double arg1 = info[1].As<Napi::Number>().DoubleValue();
    double sum = Calculate::add(arg0, arg1);
    Napi::Number result = Napi::Number::New(env, sum);
    return result;
}

void About(const Napi::CallbackInfo& info)
{
    Napi::Env env = info.Env();
    Napi::Function cb = info[0].As<Napi::Function>();
    // C++中向JavaScript传过来的函数传递参数并执行它
    cb.Call(env.Global(), { Napi::String::New(env, "这是一个计算类") });
}

Napi::Object Init(Napi::Env env, Napi::Object exports)
{
    exports.Set(
        Napi::String::New(env, "add"),
        Napi::Function::New(env, Add)
    );

    exports.Set(
        Napi::String::New(env, "about"),
        Napi::Function::New(env, About)
    );

    return exports;
}

// 第一个参数为模块名称,与binding.gyp中target_name对应
NODE_API_MODULE(cal, Init);

上面的代码暴露给nodejs两个方法:

  • Add方法接收nodejs传过来的两个数值,返回它们的和给调用Add的nodejs程序。
  • About方法接收nodejs传过来的回调函数,在C++中传参并调用该函数。

Add方法的最后,C++的double转换成了Napi::Value,实现了不同语言间的转换。

CallbackInfo用于接收JavaScript传递给C++的参数,用中括号索引。

凡是用node-addon-api来混合开发的程序都需要这样一个中间文件。

6、binding.gyp,编译

安装编译工具node-gyp,把C++程序编译成后缀名为.node的Native Addon二进制文件(本质是动态链接库,只不过后缀是.node,而不是.dll)。

npm install -g node-gyp

node-gyp作用类似于CMake,需要有python环境,根据配置文件binding.gyp进行编译。

binding.gyp 作用相当于CMake的CMakeLists.txt,告诉node-gyp如何去构建

{
    "targets": [
        {
            # 全局唯一的目标文件名称。本例编译生成cal.node
            "target_name": "cal",
            # C++源文件
            "sources": [
                "./src/Calculate.cpp",
                "./src/index.cpp"
            ],
            # C++头文件目录
            "include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
            "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
            "cflags!": [ "-fno-exceptions" ],
            "cflags_cc!": [ "-fno-exceptions" ],
            # 静态库
            "libraries": [],
            "msvs_settings": {
                "VCCLCompilerTool": { "ExceptionHandling": 1 },
            },
            # 预编译宏,禁用Node-API的C++异常处理和node-addon-api废弃的API
            "defines": ["NAPI_DISABLE_CPP_EXCEPTIONS", "NODE_ADDON_API_DISABLE_DEPRECATED"]
        }
    ]
}

7、生成构建文件

创建 binding.gyp 文件后,为当前平台生成项目构建文件。

node-gyp configure

新生成一个build文件夹,结构如下图。

js调用c++库,C++,node.js,c++,开发语言

8、构建并编译

根据需要选择生成Release或者Debug版本

Release版本:

node-gyp build

在build下生成一个Release文件夹

js调用c++库,C++,node.js,c++,开发语言

Debug版本:

node-gyp build --debug

在build下生成一个Debug文件夹

js调用c++库,C++,node.js,c++,开发语言

9、nodejs调用

在nodejs中以模块的方式(require)引入C++编译得到的二进制文件

根目录创建index.js

const addon = require("./build/Debug/cal.node");

const sum = addon.add(5, 3);
console.log("sum = " + sum);

addon.about(function (msg) {
    console.log(msg);
});

在控制台执行 node index.js 即可看到结果

调试配置

光把程序写出来还不够,走通调试流程也是必不可少的

创建VS Code的调试配置文件launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "JS Debug Build",
            "console": "integratedTerminal",
            "program": "${workspaceFolder}/index.js"
        },
        {
            "name": "Windows Attach",
            "type": "cppvsdbg",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}

configurations第一个花括号的内容是nodejs的调试启动项;第二个花括号是C++的调试启动项

request可以是"launch"(启动)或"attach"(附加)

console是终端选项,设置为integratedTerminal则使用VSCode内部集成终端显示调试结果

操作步骤:

1)js文件打好断点

js调用c++库,C++,node.js,c++,开发语言

2)切换到调试面板,选择js的调试启动项,开始调试

js调用c++库,C++,node.js,c++,开发语言

3)切换到C++调试启动项,再次启动

js调用c++库,C++,node.js,c++,开发语言

这时会弹出一个"Attach to process"的选择框,附加到node.exe进入C++调试

js调用c++库,C++,node.js,c++,开发语言

4)在C++代码中打好断点,F11进去

js调用c++库,C++,node.js,c++,开发语言
js调用c++库,C++,node.js,c++,开发语言

偶尔进不去,node-gyp rebuild --debug 一下就好,不知道为什么

node-gyp常用命令

  • node-gyp configure

  • node-gyp build 编译release版本

  • node-gyp build --debug 编译debug版本

  • node-gyp clean 清除编译生成的内容(build文件夹)

  • node-gyp rebuild 重新编译release版本

  • node-gyp rebuild --debug 重新编译debug版本

  • node-gyp help 查看帮助

VS Code的一个报错处理

虽然程序能正常运行,但是VS Code的C++提示会报下图所示的错误,意思是找不到node-addon-api依赖的node_api.h

js调用c++库,C++,node.js,c++,开发语言

node_api.h位于

C:\Users\<用户名>\AppData\Local\node-gyp\Cache\<Node版本号>\include\node

ctrl + shift + p,在Command Palette中选择模板创建c_cpp_properties.json

js调用c++库,C++,node.js,c++,开发语言

把node_api.h的路径写到c_cpp_properties.json的includePath下即可去除错误提示。解决了这个问题,还能获得更多的智能提示。

js调用c++库,C++,node.js,c++,开发语言

本文相关代码和配置可以在这里下载


本文参考了:

Node官方文档

node-addon-api module

Node.js Addon Examples

node-gyp 实现 nodejs 调用 C++

Configure binding.gyp file in C++ Addon - Node.js

Debugging NodeJS C++ addons using VS Code

使用VSCode混合调试C++与Node.js

Node.js native addons: where is node_api.h located?文章来源地址https://www.toymoban.com/news/detail-774254.html

到了这里,关于node.js调用C++的一种方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【滑动窗口最值】滑动窗口的最值的一种方案

    假设现在有数组a[n],和滑动的窗口长度为k = n,要求长度为k的滑动窗口的最值,一般来说,我们会遇到以下问题:   在窗口向右滑动时,由于不知道将要删除的元素在窗口中的位置,于是只能 暴力遍历窗口来删除旧元素 。增加了时间复杂度到O(n^2logn) 以下是解决该问题的一

    2024年02月04日
    浏览(40)
  • C++ 调用js 脚本

    需求: 使用Qt/C++ 调用js 脚本。Qt 调用lua 脚本性能应该是最快的,但是需要引入第三方库,虽然也不是特别麻烦,但是调用js脚本,确实内置的功能(C++ 调用lua 脚本-CSDN博客) 步骤: 1,pro 引入   2,调用js 脚本 3,js 脚本编写 4,效果 js 和lua对比:  目前Qt使用现成的js生态

    2024年02月22日
    浏览(35)
  • QT在自定义类中调用主类(界面类ui及其控件)的一种实用方法

    在实际应用中,经常会出现需要自定义类访问界面中的控件的情况,使用信号和槽进行跳转往往过于繁琐,使用下述方法可以巧妙解决: 界面类 QtWidgetsTest.h QtWidgetsTest.cpp 自定义类 CustomClass.h 首先包含ui头文件(其实也可不写,因为cpp里一定会包含QtWidgetsTest.h并包含ui文件),

    2024年02月16日
    浏览(48)
  • Win11 预览体验计划空白无显示的一种解决方案

    某一天你心血来潮,打算参与Win11 预览体验计划,但体验计划页面显示“Your PC does not meet the minimum hardware requirements for Windows11…”,经过查询网上经验并一番操作后,预览体验计划干脆什么都不显示了,一片空白: 此时的一种解决思路: 根据你想进入的预览体验计划通道,

    2024年02月05日
    浏览(69)
  • VMware 虚拟机占用磁盘空间过大的一种解决方案

    在使用VMware虚拟机的过程中,VM会自动扩大虚拟磁盘的占用空间。发现无论是VM自带的碎片整理还是压缩,这两个操作都无法明显减少虚拟机占用空间。 现在找到一种方法可以做到这点( 可能只适用于VM workstation pro,并未测试过普通版本 ),下面是方法的整理 1.正常关闭虚拟

    2024年02月13日
    浏览(87)
  • 【Default config not found for ApplicationConfig】的一种解决方案

                                                                             💧 记录一下今天遇到的 b u g color{#FF1493}{记录一下今天遇到的bug} 记录一下今天遇到的 b ug 💧           🌷 仰望天空,妳我亦是行人.✨ 🦄 个人主页——微风撞

    2024年02月16日
    浏览(50)
  • Qt QWebSocket实现JS调用C++

    本篇主要介绍实现JS调用C++的另一种方式,即QWebSocket+QWebChannel。与之前的一篇文章QWebEngine 加载网页及交互,实现C++与JS 相互调用中提到的仅通过QWebChannel 实现JS调C++相比,本文介绍的这种方式,更灵活,能实现更加复杂的业务功能。 这篇文章中提到的QWebChannel实现JS调用C++,

    2024年01月16日
    浏览(40)
  • ubuntu20.04安装NVIDIA显卡以及重启黑屏的一种解决方案

    问题描述: 安装ubuntu20.04后,安装微软浏览器edge会出现打不开、卡顿等情况,而且不支持扩展屏幕 原因分析:考虑是ubuntu自带的gdm3显卡驱动不兼容导致 解决方案:网上有很多使用终端安装NVIDIA显卡的教程,亲自踩了好多坑后,找到一种简单的安装方案: 首先在终端输入:

    2024年02月04日
    浏览(60)
  • 【linux】记录archlinux软件包更新后lualatex无法编译的一种解决方案

    操作系统:archlinux Kernel: 6.4.11-arch2-1 包管理器:pacman 日期:2023.08.25 今天一如往常地进行软件包更新: 随后,在使用luelatex对我的论文(latex)进行编译时,无法编译。想到在软件更新前还能编译,更新后就无法编译,必然是软件包版本问题。在命令行运行lualatex报错: 所以

    2024年02月11日
    浏览(46)
  • Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway)

    目前在职的公司,维护着Spring Cloud分布式微服务项目有25+个。其中有10个左右微服务都写有定时任务逻辑,采用Spring @Scheduled这种方式。 Spring @Scheduled定时任务的缺点: 不支持集群:为避免重复执行,需引入分布式锁 死板不灵活:不支持手动执行,单次执行,补偿执行,修改

    2024年02月11日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包