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の文法に慣れず読み解くのに苦労しました。
-
v8.dev (https://v8.dev) ↩
-
C++ Addons (https://nodejs.org/api/addons.html#addons_c_addons) ↩
-
Previous Releases (https://nodejs.org/en/download/releases/) ↩
-
Use Maybe version of V8 APIs (https://github.com/joyeecheung/node/blob/v8-maybe-doc/CPP_STYLE_GUIDE.md#use-maybe-version-of-v8-apis)
v8/node deprecated APIs and how to handle them #7 (https://github.com/bcoin-org/bcrypto/issues/7) ↩ -
V8 API changes (https://docs.google.com/document/d/1g8JFi8T_oAE_7uAri7Njtig7fKaPDfotU6huOa1alds/edit) ↩