node-gyp rebuildのerrorを解決する


Node.jsの開発スピードが速すぎて、公開しているNode-REDのライブラリがいつの間にかnpm installできなくなっていました。このライブラリはC++のドライバにアクセスするためNode.jsのC++ Addonを利用していますが、npm install時のnode-gypで失敗しているようでした。V8 API1のトラブルシューティングに関しては、検索してもなかなか情報が見つからず、参考になれば幸いです。

ちなみに、本家のサイト2によるとライブラリの開発には

  • N-API
  • nan
  • direct use of internal V8, libuv and Node.js libraries

の3つがあると書かれていますが、ここで扱うのは3つ目のタイプです。

Node.jsのversion

10.xまでは問題なかったのですが、11.xからエラーが出るようになりました。現在最新の13.11を対象としています(※2020/05/15追記:もう最新ではなくなりました)。ちなみに、11.xからV8のMajor versionが6から7に上がっています。3

Object->Set()でエラー

Maybe versionになったため、引数にcontextを追加で渡せとのエラーです。Maybe versionの場合は.ToChecked()で返します。4

ログ

../nodes/***/***_wrap.cc:286:46: error: no matching function for call to v8::Array::Set(int&, v8::Local<v8::Integer>)
     dst_addr->Set(i,Integer::New(isolate,tmp));
                                              ^
In file included from /home/***/.cache/node-gyp/13.11.0/include/node/node.h:67:0,
                 from ../nodes/***/***_wrap.cc:29:
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3547:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, v8::Local<v8::Value>, v8::Local<v8::Value>)
   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
                                     ^~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3547:37: note:   candidate expects 3 arguments, 2 provided
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3550:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, uint32_t, v8::Local<v8::Value>)
   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
                                     ^~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3550:37: note:   candidate expects 3 arguments, 2 provided

コード


// 修正前
Local<Array> dst_addr = Array::New(isolate,4);
...
dst_addr->Set(i,Integer::New(isolate,tmp));

// 修正後
Local<Context> context = isolate->GetCurrentContext();
Local<Array> dst_addr = Array::New(isolate,4);
...
dst_addr->Set(context,i,Integer::New(isolate,tmp)).ToChecked();

Object->Set()でエラー その2

別パターンですが、Maybe versionに関するエラーです。同様にcontextを渡して、.ToChecked()で返します。String::NewFromUtf8()の引数、戻り値の型もMaybeLocalに変わったので、引数にNewStringType::kNormalを追加し、.ToLocalChecked()で返します。

ログ

../nodes/***/***_wrap.cc:292:83: error: no matching function for call to v8::Object::Set(v8::MaybeLocal<v8::String>, v8::Local<v8::Integer>)
    obj->Set(String::NewFromUtf8(isolate,"header"),Integer::New(isolate,mac.header));
                                                                                   ^
In file included from /home/***/.cache/node-gyp/13.11.0/include/node/node.h:67:0,
                 from ../nodes/***/***_wrap.cc:29:
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3547:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, v8::Local<v8::Value>, v8::Local<v8::Value>)
   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
                                     ^~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3547:37: note:   candidate expects 3 arguments, 2 provided
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3550:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, uint32_t, v8::Local<v8::Value>)
   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
                                     ^~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3550:37: note:   candidate expects 3 arguments, 2 provided

コード

// 修正前
obj->Set(String::NewFromUtf8(isolate,"header"),Integer::New(isolate,mac.header));

// 修正後
obj->Set(context,(String::NewFromUtf8(isolate,"header",NewStringType::kNormal)).ToLocalChecked(),Integer::New(isolate,mac.header)).ToChecked();

BooleanValue()でエラー

BooleanValueの引数が空なので、Isolate* isolateを引数で渡せとのエラーです。

※V8 7.4の前後でエラーの内容が変わるので両対応しています。

ログ

../nodes/***/***_wrap.cc:196:33: error: no matching function for call to v8::Value::BooleanValue()
  latest = args[0]->BooleanValue();
                                 ^
In file included from /home/***/.cache/node-gyp/13.11.0/include/node/node.h:67:0,
                 from ../nodes/***/***_wrap.cc:29:
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:2771:8: note: candidate: bool v8::Value::BooleanValue(v8::Isolate*) const
   bool BooleanValue(Isolate* isolate) const;
        ^~~~~~~~~~~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:2771:8: note:   candidate expects 1 argument, 0 provided

コード

// 修正前
static void foo(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate();
    latest = args[0]->BooleanValue();
    args.GetReturnValue().Set(Boolean::New(isolate,true));
    return;
}

// 修正後
static void foo(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate();
#if (V8_MAJOR_VERSION > 7) || ((V8_MAJOR_VERSION == 7) && (V8_MINOR_VERSION >= 4))
    latest = args[0]->BooleanValue(isolate);
#elif (V8_MAJOR_VERSION >= 7)
    Local<Context> context = isolate->GetCurrentContext();
    latest = args[0]->BooleanValue(context).ToChecked();
#else
    latest = args[0]->BooleanValue();
#endif
    args.GetReturnValue().Set(Boolean::New(isolate,true));
    return;
}

Object->Get()でエラー

Object->Set()と同様。Maybe versionに関するエラー。

ログ

../nodes/***/***_wrap.cc:449:26: error: no matching function for call to v8::Array::Get(int)
  dst_addr[0] = arr->Get(0)->NumberValue(context).FromMaybe(0);
                          ^
In file included from /home/***/.cache/node-gyp/13.11.0/include/node/node.h:67:0,
                 from ../nodes/***/***_wrap.cc:29:
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3594:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, v8::Local<v8::Value>)
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
                                           ^~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3594:43: note:   candidate expects 2 arguments, 1 provided
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3597:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, uint32_t)
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
                                           ^~~
/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3597:43: note:   candidate expects 2 arguments, 1 provided

コード

// 修正前
dst_addr[0] = arr->Get(0)->NumberValue(context).FromMaybe(0);

// 修正後
Local<Context> context = isolate->GetCurrentContext();

dst_addr[0] = arr->Get(context,0).ToLocalChecked()->NumberValue(context).FromMaybe(0);

まとめ

Node.jsの10.x(V8 6.8)から11.x(V8 7.0)でV8 APIに大きな変更が入り5 (※2020/05/15追記:予告されていたDeprecatedなAPIを削除した、が正解でした)、全体的にMaybe versionが適用されているAPIでnode-gypエラーが出ていました。V8の文法に慣れず読み解くのに苦労しました。