native-addon-example icon indicating copy to clipboard operation
native-addon-example copied to clipboard

Equivalent example using nbind

Open jjrv opened this issue 9 years ago • 4 comments

Thought you might be interested in a port of this example to nbind. Maybe this could be a tutorial step 4?

Here's the equivalent example.cc:

#include <string>
#include "nbind/nbind.h"

const int maxValue = 10;
int numberOfCalls = 0;

std::string WhoAmI() {
  return "I'm a Node Hero!";
}

double increment(int argsValue) {
  if (numberOfCalls + argsValue > maxValue) {
    NBIND_ERR("Counter went through the roof!");
    return 0;
  }

  numberOfCalls += argsValue;

  return numberOfCalls;
}

NBIND_GLOBAL() {
  // The second parameter renaming the function is optional.
  function(WhoAmI, "whoami");

  // The nbind::Strict() policy makes passing non-numbers throw
  // instead of coercing to number like +["42"] would do in JavaScript.
  // To also rename the function, add the new name before any policies.
  function(increment, nbind::Strict());
}

To avoid having to install node-gyp and autogypi globally, I usually add these scripts in package.json:

  "scripts": {
    "autogypi": "autogypi",
    "node-gyp": "node-gyp",

Then here's the extra shell commands to install nbind:

npm install --save nbind
npm install --save-dev autogypi
rm binding.gyp
npm run -- autogypi --init-gyp -p nbind -s example.cc

index.js needs a one-line change to how the addon is loaded:

const addon = require('nbind').init().lib

Now it works! Run:

npm install
node index.js

It prints the exact same output as the original version.

jjrv avatar Nov 29 '16 10:11 jjrv

As a bonus, if you add this to scripts in package.json:

"ndts": "ndts",

Then run npm run ndts and it will print:

export class NBindBase { free?(): void }

/** float64_t increment(int32_t); -- Strict */
export function increment(p0: number): number;

/** std::string whoami(); */
export function whoami(): string;

Publishing this with your addon will make TypeScript users happier. Save it as main.d.ts and add to package.json:

  "types": "main.d.ts"

When publishing the addon on npm, you should also add an index.js file that exports the C++ API. For example:

module.exports = require('nbind').init(__dirname).lib;

The __dirname variable tells nbind to initialize the addon provided by the current npm package.

jjrv avatar Nov 29 '16 10:11 jjrv

Or if you have Emscripten installed and add this to scripts in package.json:

  "emcc-path": "emcc-path",

Then run:

npm run -- node-gyp configure build --asmjs=1
node index.js

It prints the same thing again! (except it doesn't throw the exception, I'll fix this soon).

But now build/Release/nbind.js (the C++ compiler output) is pure JavaScript and runs in a browser as well!

If possible, it might be a good idea to distribute the asm.js version in your npm package, in case someone installing it is missing Python 2.x or a properly configured C++ compiler. Otherwise, a future nbind version will also allow easily distributing precompiled native binary libraries.

jjrv avatar Nov 29 '16 10:11 jjrv

I'm definetly going to look at this library when I have the time, and include it maybe in a next post or this one, I'm not yet sure about that. Thanks a lot for your contribution this lib looks amazing! :)

peteyycz avatar Nov 29 '16 12:11 peteyycz

Thanks! And if the material above is useful, you can use it however you want.

jjrv avatar Nov 29 '16 18:11 jjrv