如何在node.js中使用C++库?

138

我该如何在node.js中使用C++库?


10
关键词是extension。搜索c++ nodejs extension,获取相关结果。 - Peter Wood
5
请点击此链接。它提供了一个样例程序并逐步解释了它。http://www.benfarrell.com/2013/01/03/c-and-node-js-an-unholy-combination-but-oh-so-right/ - user2431227
7个回答

84

现在这个问题有了一个新的答案。SWIG,从版本3.0开始似乎为Node.js、Webkit和v8提供了javascript接口生成器

我已经长期使用SWIG来处理Java和Python代码,并且一旦你理解了SWIG的工作原理,与SWIG支持的语言进行C ++代码接口开发的工作量(与ffi或目标语言中的等效项相比)几乎可以忽略不计。

举个小例子,假设你有一个带有myclass.h头文件的库:

#include<iostream>

class MyClass {
        int myNumber;
public:
        MyClass(int number): myNumber(number){}
        void sayHello() {
                std::cout << "Hello, my number is:" 
                << myNumber <<std::endl;
        }
};

为了在Node中使用这个类,你只需编写以下SWIG接口文件(mylib.i):

%module "mylib"
%{
#include "myclass.h"
%}
%include "myclass.h"

创建绑定文件 binding.gyp:

{
  "targets": [
    {
      "target_name": "mylib",
      "sources": [ "mylib_wrap.cxx" ]
    }
  ]
}
运行以下命令:

swig -c++ -javascript -node mylib.i
node-gyp build

现在,从相同的文件夹中运行node,你可以执行以下操作:

> var mylib = require("./build/Release/mylib")
> var c = new mylib.MyClass(5)
> c.sayHello()
Hello, my number is:5

即使我们需要为如此简单的示例编写两个接口文件,但请注意,我们不必在任何地方提及MyClass构造函数或sayHello方法,SWIG会发现这些东西,并自动生成自然的接口。


2
在使用 swig/node.js 一段时间后,似乎 swig 无法处理返回数组的 C++ 函数(更准确地说:无法处理返回指向数组的指针的函数)。也就是说,在 C++ 中构建一个返回类似于 JavaScript 数组的函数,并让 swig 自动转换它似乎是不可能的。 - George
5
@George SWIG确实是一个很棒的工具,但它不是魔法,也不是能够理解你的C++代码语义并生成相应接口的通用人工智能。请注意,C++和JavaScript的语义、所有权概念和生命周期管理在根本上是不同的。 - enobayram
3
你可以从两个方面看待SWIG:它是一个能够开箱即用并按照其规则运行的工具。这意味着,你不应该期望看到由返回数组的C++函数产生的Javascript数组。相反,你可以将函数封装在 C++ 中,使其返回像数组一样的对象(例如std::vector<>,只需 %include "std_vector.i"),然后你就可以以某种笨拙的方式在Javascript端操作它了。请注意,这种方法仍然比自己编写 FFI 更容易且更安全。 - enobayram
3
你可以另一种方式使用SWIG,即了解其原理。花几个月时间使用它,深入学习其特点。然后,你可以让它生成你想要的接口。如果你想让它返回C++数组的Javascript数组,那么可以实现,但你应该首先学习如何表达你在这样一个接口中期望的精确语义,并确保它与你的问题域相匹配。 - enobayram
3
无论如何,我建议您从第一种方法开始,并在使用SWIG的过程中不断完善它。研究SWIG对您的代码所做的更改以及您如何操作它是非常有启发性的。 - enobayram
显示剩余3条评论

68

看看node-ffi

node-ffi 是一个使用纯 JavaScript 加载和调用动态库的 Node.js 插件。它可用于创建与本地库的绑定,而无需编写任何 C++ 代码。


5
不同的C++编译器会创建不同的ABI,所以为了使用node-ffi,你可能需要用C接口来包装你的C++代码,至少我在Windows上使用Visual Studio时是这样做的。关于如何操作,请参见https://dev59.com/V3I-5IYBdhLWcg3wBjrl。或者我能否在没有包装器的情况下在C++上使用node-ffi? - pancake
1
我知道这条评论已经超过一年的时间了,但是...是否有可能在没有C语言封装器的情况下使用C++库? - Miki de Arcayne
我在使用node-ffi编译时遇到了VS 2017/2019的问题。这真是个大麻烦!它是否依赖于Python 2.7,还是只是构建过程中需要?NodeJS中一定有一个LoadLibrary机制来加载标准Win32 DLL吧? - tgraupmann
1
node-ffi不再受支持,也不会无缝编译,不建议使用。 - Zvi vex

12

您可以使用emscripten将C++代码编译为js。


17
如果楼主的目标是获得编译后的C++性能优势,那么这将是一个不好的选择。严谨地说,这并没有回答问题。 - Greg
7
@Greg 但仍然值得考虑这个想法。人们来到这个页面是为了处理各种类型的项目。我认为当你有C/C++代码库并且只想在Nodejs中使用它时,Emscripten是一个不错的选择。 - AlexStack
1
如果楼主的目标是获得编译后的C++性能优势,则emscripten可提供一些好处,特别是使用WASM:无GC开销,更少的解析和JIT开销,原生整数,AOT优化。 - ArtemGr

3

有更新的方法连接Node.js和C++,请看Nan

编辑 最快最简单的方法是nbind。如果你想编写异步插件,可以结合nan中的Asyncworker类。


2
这是一篇关于使用Node.js将C++代码转移到Web的有趣文章。
引用部分写道:有三种一般的方法可以将C++代码集成到Node.js应用程序中,尽管每个类别内部有很多变化:
1.自动化-在子进程中调用您的C++作为独立应用程序。 2.共享库-将C++例程打包到共享库(dll)中,并直接从Node.js调用这些例程。 3.Node.js插件-将C++代码编译为本地Node.js模块/插件。

1
尝试使用shelljs,从Linux/Unix中使用node程序调用C/C++程序或共享库。在Windows中可以使用node-cmd选项。这两个软件包基本上使我们能够以类似于从终端/命令行调用的方式调用C/C++程序。
例如,在Ubuntu中:
const shell = require('shelljs');

shell.exec("command or script name");

在Windows中:
const cmd = require('node-cmd');
cmd.run('command here');

注意:shelljs和node-cmd用于运行操作系统命令,与C/C++无关。

0
注意使用swig和C++: http://www.swig.org/Doc1.3/SWIG.html#SWIG_nn8

Running SWIG on C++ source files (what would appear in a .C or .cxx file) is not recommended. Even though SWIG can parse C++ class declarations, it ignores declarations that are decoupled from their original class definition (the declarations are parsed, but a lot of warning messages may be generated). For example:

/* Not supported by SWIG */
int foo::bar(int) {
    ... whatever ...
}

很少有C++类只限于一个.h文件。

此外,支持JavaScript的swig版本为swig-3.0.1或更高版本。


我不明白 SWIG 会如何处理 foo::bar 的定义。类成员的定义都是关于实现的;SWIG 生成的包装器则是关于接口的。 - enobayram
这不应该是对 SWIG 答案的评论吗? - MAChitgarha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接