jroy
jroy

Reputation: 565

Understanding tools to write a Node.js native addon

I need to create a Node.js native addon from some existing C code and I see that there are multiple ways to do that: using the new N-API (or the easier C++ native addon API) or using Node FFI. Also, I am not familiar with tools such as node-gyp, and I have some questions to help understand how I can integrate the C code into my Node application:

  1. Is there a preferred method between N-API and Node FFI? I guess both have their pros and cons, what are they?
  2. Is it required to compile the C code using node-gyp? How should I do if I already have a library available but not compiled with node-gyp (eg. .dylib) and I want to use it in my Node application?

Upvotes: 1

Views: 467

Answers (1)

bmacnaughton
bmacnaughton

Reputation: 5308

1 - N-API is, in my perspective, the preferred method. It's faster than Node FFI and is part of the core node distribution. Node FFI's main advantage (from my quick read; I haven't used it) is that it allows making calls without writing c/c++ code. Whether you use N-API or the C++ native addon API is more a matter of preference on your part. The C++ API does remove some of the repetitive coding required by N-API. But if you're not using C++ to begin with that's probably not a good reason to change.

2 - you do not need to compile external libraries. Just put them in the binding.gyp file's libraries section as follows:

{
'targets': [{
    'target_name': 'addon-name',
    'cflags!': [ '-fno-exceptions' ],
    'cflags_cc!': [ '-fno-exceptions' ],
    'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
        'CLANG_CXX_LIBRARY': 'libc++',
        'MACOSX_DEPLOYMENT_TARGET': '10.7',
    },
    'msvs_settings': {
        'VCCLCompilerTool': { 'ExceptionHandling': 1 },
    },
    'include_dirs': [
    '<!@(node -p "require(\'node-addon-api\').include")',
    ],
    'sources': [
        'src/addon-name.cc'
    ],
    'conditions': [
        ['OS in "linux"', {
        'include_dirs': [
            '<!@(node -p "require(\'node-addon-api\').include")',
            '<(module_root_dir)/'
        ],
        'libraries': [
            '-ldylib',
            '-L<(module_root_dir)/dylib/',
            '-Wl,-rpath-link,<(module_root_dir)/dylib/',
            '-Wl,-rpath,\$$ORIGIN/../../dylib/'
        ],
        }]
    ]
    }]
}

Most of the boilerplate for bindings.gyp was generated by the conversion tool which is part of the node-addon-api package. I included my own libraries section because I distribute a library with my package and figuring out how to embed $ORIGIN as the location of the file was hard-won. So if you plan on distributing the library this provides a headstart on loading it when not installed in a system directory.

Upvotes: 3

Related Questions