26

I've got some existing C++ code that does numerical processing within a stand-alone C++ application. I now want to use that code within a new node.js application.

Researching how to access C++ code from node.js, two options come up:

  1. Write a node.js extension
  2. Use node-ffi

node-ffi seems like a good option to access existing libraries, but am I right thinking if I use node-ffi I would have to write a C wrapper to make my C++ accessible? (This was the only way I could get a simple test case to work on Windows with Visual Studio).

For my case where my source code is already in C++, not C, what are the considerations in choosing between the two options above?

simon-p-r
  • 3,623
  • 2
  • 20
  • 35
pancake
  • 3,232
  • 3
  • 22
  • 35
  • Do you use a lot of inheritance, virtual functions and templates in your code – aaronman May 28 '13 at 03:10
  • No templates. No virtual functions. Some inheritance, although I could modify the code to avoid this if need be. – pancake May 28 '13 at 04:41
  • I think it would be relatively easy to write the wrappers than – aaronman May 28 '13 at 04:42
  • I agree, writing wrappers wouldn't be hard. What I'm wondering is whether I *need* to write wrappers for node-ffi, and whether or not this is a better route than writing a node extension. – pancake May 28 '13 at 13:48
  • It looks like you don't have to, from what I just read you can even make it work with objective c – aaronman May 28 '13 at 16:29

1 Answers1

31

FFI works with dynamic C libraries. This means that you have to expose your dynamic library externally. In C++, you do this with extern "C", like this:

#ifdef __cplusplus
extern "C" {
#endif

int foo (int param){
  int ret = 0;
  // do C++ things
  return ret;
}

int bar(){
  int ret = 0;
  // do C++ things
  return ret;
}

#ifdef __cplusplus
}
#endif

This will make your C++ function available to C-things, as a dynamic library method.

Here is how you wrap this in javascript, after you have compiled your C++ lib as libmylibrary.dll/.so:

var ffi = require('ffi');

var mylibrary = ffi.Library('libmylibrary', {
  "foo": [ "int", ["int"] ],
  "bar": [ "int", [] ]
});

There are lots cooler things that you can do. Check it out, here

If this is a node library, just put your methods in module.exports. Here is a full example of a wrap of the above C++ code, with synchronous & asynchronous methods:

var ffi = require('ffi');

var mylibrary = ffi.Library('libmylibrary', {
  "foo": [ "int", ["int"] ],
  "bar": [ "int", [] ]
});

module.exports = {
  fooSync : mylibrary.foo,
  foo: mylibrary.foo.async,
  barSync : mylibrary.bar,
  bar: mylibrary.bar.async
};

I haven't used node-ffi-generate, but it looks pretty cool for generating these sort of wrappers for you.

If I saved this file as mylibrary.js, I could use it like this:

var mylib = require('./mylibrary.js');

var num = mylib.fooSync(1);

// or

mylib.foo(1, function(er, num){

});

As for the question of "is it better?" I think so, for most things. If you make your methods extern C, they will work in just about every other language, some of which also have FFI, so you would write the simple equivalent of the above in whatever your target language is. This means very little code to maintain, other than the basic "load C++ lib", and "mess around with it's signature to feel right for language X". It's not specific to node. Another bonus is for common shared libraries (like sqlite, given in tutorial example.) You maybe don't care exactly what version they have, or want to wrap it with more C++ code, that needs to be compiled to use it. Using FFI, you can wrap a pre-compiled/installed lib with just javascript.

konsumer
  • 3,411
  • 1
  • 30
  • 31
  • Great detailed answer, thanks very much! It's a while since I wrote the question, and I would now agree that I think using the FFI route is probably more straightforward than writing an extension. node-ffi-generate looks interesting. – pancake Nov 16 '13 at 21:29
  • 2
    But you might want to consider the performance. If you are doing calls really often then FFI can be slower in magnitude. Here is a detailed benchmark: https://bitbucket.org/juraf/node_ffi_vs_addon/src/master/ – Tolsee May 20 '19 at 17:59
  • yep, agreed, if performance is more important than easy/dynamic linkage, NAPI is much more performant. You would need to make a native library, wrap all the functions you want access to, and users would need to compile that wrapper. – konsumer Aug 04 '22 at 00:53