简体   繁体   中英

Constructing native object from NodeJS Addon

Expectation

I want to to implement using a native NodeJS module that works like the javascript module below

class C1{
  make(){return new C2()}
}
class C2{}
module.exports({C1, C2})

Approach

My attempt was, (among some other failed attempts)

// so.cpp
#include <napi.h>

class C1: public Napi::ObjectWrap<C1> {
public:
  C1(const Napi::CallbackInfo &info);
  static void Initialize(Napi::Env& env, Napi::Object& target);
  Napi::Value make(const Napi::CallbackInfo &info);
};

class C2: public Napi::ObjectWrap<C2> {
  static Napi::Function constructor;
  public:
  C2(const Napi::CallbackInfo &info);
  static void Initialize(Napi::Env& env, Napi::Object& target);
  static C2 *New(const std::initializer_list<napi_value>& args);
};
Napi::Function C2::constructor;
void C2::Initialize(Napi::Env& env, Napi::Object& target){
  constructor = Napi::ObjectWrap<C2>::DefineClass(env, "C2", {});
  target.Set("C2", constructor);
}
void C1::Initialize(Napi::Env& env, Napi::Object& target) {
  Napi::Function constructor = Napi::ObjectWrap<C1>::DefineClass(env, "C1", {
    Napi::ObjectWrap<C1>::InstanceMethod("make", &C1::make),
  });
  target.Set("C1", constructor);
}

C2 *C2::New(const std::initializer_list<napi_value>& args){
  return Napi::ObjectWrap<C2>::Unwrap(constructor.New(args));
}
C2::C2(const Napi::CallbackInfo &info): Napi::ObjectWrap<C2>(info) {}
C1::C1(const Napi::CallbackInfo &info): Napi::ObjectWrap<C1>(info) {}

// make() {return new C2()}
Napi::Value C1::make(const Napi::CallbackInfo &info){
  C2 *jsclat = C2::New({});
  return jsclat->Value();
}


// module.exports = {C1, C2}
Napi::Object Init(Napi::Env env, Napi::Object exports)
{
  C1::Initialize(env, exports);
  C2::Initialize(env, exports);
  return exports;
}
NODE_API_MODULE(so, Init);

Problem

When I try to use the compiled module from javascript Node is terminated

const m = require('bindings')('hello')
const c1 = new m.c1()
c1.make() // FATAL ERROR: Error::New napi_get_last_error_info
          // Aborted

Environment

If you want the same environment as I used, here you have a dockerfile.

FROM node:13.8.0-alpine3.11
RUN apk add --upgrade git python3 g++ make
WORKDIR /opt
RUN git clone https://github.com/nodejs/node-addon-examples.git
WORKDIR /opt/node-addon-examples/1_hello_world/node-addon-api/
RUN npm install \
 && npm install --save-dev gyp
 && npx node-gyp configure 
COPY so.cpp hello.cc
RUN npx node-gyp rebuild 

You are not allowed to use constructor outside the function that created it - it is an automatic v8::Local reference that is allocated on the stack - you need a persistent reference to do this:

#include <napi.h>

class C1: public Napi::ObjectWrap<C1> {
public:
  C1(const Napi::CallbackInfo &info);
  static void Initialize(Napi::Env &env, Napi::Object &target);
  Napi::Value make(const Napi::CallbackInfo &info);
};

class C2: public Napi::ObjectWrap<C2> {
  static Napi::Function constructor;
  public:
  static Napi::FunctionReference *New;
  C2(const Napi::CallbackInfo &info);
  static void Initialize(Napi::Env& env, Napi::Object& target);
};

Napi::FunctionReference *C2::New;

void C2::Initialize(Napi::Env& env, Napi::Object& target){
  Napi::Function constructor = Napi::ObjectWrap<C2>::DefineClass(env, "C2", {});
  target.Set("C2", constructor);
  New = new Napi::FunctionReference();
  *New = Napi::Persistent(constructor);
}
void C1::Initialize(Napi::Env& env, Napi::Object& target) {
  Napi::Function constructor = Napi::ObjectWrap<C1>::DefineClass(env, "C1", {
    Napi::ObjectWrap<C1>::InstanceMethod("make", &C1::make),
  });
  target.Set("C1", constructor);
}

C2::C2(const Napi::CallbackInfo &info): Napi::ObjectWrap<C2>(info) {}
C1::C1(const Napi::CallbackInfo &info): Napi::ObjectWrap<C1>(info) {}

// make() {return new C2()}
Napi::Value C1::make(const Napi::CallbackInfo &info){
  Napi::Value c2 = C2::New->New({});
  return c2;
}


// module.exports = {C1, C2}
Napi::Object Init(Napi::Env env, Napi::Object exports)
{
  C1::Initialize(env, exports);
  C2::Initialize(env, exports);
  return exports;
}
NODE_API_MODULE(so, Init);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM