Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compile Node.js native api extension via meson build system

I want compile Node.js C/C++ extension without using node-gyp package.

I have experience with meson and would use it to compile Node.js module.

Can u suggest example with how to compile Node.js native module?

P.S. I use a few subproject with static proprietary library and node-gyp is very simple utilite for this hard build.

like image 971
Vitold S. Avatar asked Sep 18 '25 15:09

Vitold S.


1 Answers

I agree it's a nice idea, since node-gyp would generate Makefiles, whereas Meson uses modern Ninja that works much faster. Also, building with node-gyp results in warnings from node.h you can do little about, but Meson allows to suppress them with is_system: true.

For this answer I use an example addon from here. The C++ file:

// hello.cc
#include <node.h>

namespace demo {

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;

void Method(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  args.GetReturnValue().Set(String::NewFromUtf8(
      isolate, "world").ToLocalChecked());
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

}  // namespace demo

The meson.build; it would compile the addon and also test that it's functional by making node load it then invoke hello() from the addon:

project('C++ node example addon', 'cpp')

inc_node = include_directories('/usr/include/node', is_system: true)

# For compatibility with node-gyp we use "shared_module" rather than
# "shared_library". The difference important in the current context is that
# shared_module will happily allow undefined references at link-time. It may or may
# not be what you want, feel free to change to `shared_library`, in which case you
# have to also link it with find_library('node')
shared_module(
  'hello',
  ['hello.cc'],
  include_directories : [inc_node],
  name_prefix: '',     # don't prepend "lib"
  name_suffix: 'node', # required for addon to load properly
)

node = find_program('node')

test('addon',
     node,
     args: ['-e',
            'const addon = require("./hello.node");'
            + 'console.log(addon.hello());'
           ]
    )

Here's an example of running it:

$ meson build
The Meson build system
Version: 0.62.2
Source dir: /tmp/node_C_hello_world
Build dir: /tmp/node_C_hello_world/build
Build type: native build
Project name: C++ node example addon
Project version: undefined
C++ compiler for the host machine: c++ (gcc 12.1.1 "c++ (GCC) 12.1.1 20220507 (Red Hat 12.1.1-1)")
C++ linker for the host machine: c++ ld.bfd 2.37-27
Host machine cpu family: x86_64
Host machine cpu: x86_64
Library node found: YES
Program node found: YES (/usr/bin/node)
Build targets in project: 1

Found ninja-1.10.2 at /usr/bin/ninja
$ ninja -C build/
ninja: Entering directory `build/'
[2/2] Linking target hello.node
$ ninja -C build/ test
ninja: Entering directory `build/'
[0/1] Running all tests.
1/1 addon        OK              0.20s


Ok:                 1
Expected Fail:      0
Fail:               0
Unexpected Pass:    0
Skipped:            0
Timeout:            0

Full log written to /tmp/node_C_hello_world/build/meson-logs/testlog.txt

Some notes:

  • the addon library has to have .node postfix, otherwise node will fail to load it with a SyntaxError: Invalid or unexpected token
  • the nodejs-devel (or whatever the package with node.h is called on your system) package, unfortunately, lacks pkg-config .pc files, so you have to call include_directories() directly rather than simply using a dependency() call.
  • the node-gyp adds some fancy arguments, which I'm not sure whether are needed or not. Am not a nodejs developer, so can't say anything useful on that matter, but here are ones I deemed to be potentially important for more complicated addons:
    • link argument -rdynamic
    • compile arguments -DNODE_GYP_MODULE_NAME=addon -DUSING_UV_SHARED=1 -DUSING_V8_SHARED=1 -DBUILDING_NODE_EXTENSION
like image 147
Hi-Angel Avatar answered Sep 20 '25 05:09

Hi-Angel