Node.jsの開発スピードが速すぎて、公開しているNode-REDのライブラリがいつの間にかnpm installできなくなっていました。このライブラリはC++のドライバにアクセスするためNode.jsのC++ Addon(V8エンジン1)を利用していますが、npm install時のnode-gypで失敗しているようでした。V8 APIについては検索してもなかなか情報が見つからず参考になれば幸いです。
ちなみに、本家のサイト2によるとライブラリの開発には
- N-API
- nan
- direct use of internal V8, libuv and Node.js libraries
の3つがあると書かれていますが、ここで扱うのは3つ目のタイプです。
Node.jsのversion
10.xまでは問題なかったのですが、11.xからエラーが出るようになりました。現在最新のv13.11を対象としています。ちなみに、11.xからV8のMajor versionが6から7に上がっています。3
Object->Set()でエラー
Maybe versionになったため、引数にcontextを追加で渡せとのエラーです。Maybe versionの場合は.ToChecked()で返します。4
ログ
../nodes/***/***_wrap.cc:286:46:error:nomatchingfunctionforcallto‘v8::Array::Set(int&,v8::Local<v8::Integer>)’dst_addr->Set(i,Integer::New(isolate,tmp));^Infileincludedfrom/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_RESULTMaybe<bool>Set(Local<Context>context,^~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3547:37:note:candidateexpects3arguments,2provided/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_RESULTMaybe<bool>Set(Local<Context>context,uint32_tindex,^~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3550:37:note:candidateexpects3arguments,2provided
コード
// 修正前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:nomatchingfunctionforcallto‘v8::Object::Set(v8::MaybeLocal<v8::String>,v8::Local<v8::Integer>)’obj->Set(String::NewFromUtf8(isolate,"header"),Integer::New(isolate,mac.header));^Infileincludedfrom/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_RESULTMaybe<bool>Set(Local<Context>context,^~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3547:37:note:candidateexpects3arguments,2provided/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_RESULTMaybe<bool>Set(Local<Context>context,uint32_tindex,^~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3550:37:note:candidateexpects3arguments,2provided
コード
// 修正前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:nomatchingfunctionforcallto‘v8::Value::BooleanValue()’latest=args[0]->BooleanValue();^Infileincludedfrom/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:boolv8::Value::BooleanValue(v8::Isolate*)constboolBooleanValue(Isolate*isolate)const;^~~~~~~~~~~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:2771:8:note:candidateexpects1argument,0provided
コード
// 修正前staticvoidfoo(constFunctionCallbackInfo<Value>&args){Isolate*isolate=args.GetIsolate();latest=args[0]->BooleanValue();args.GetReturnValue().Set(Boolean::New(isolate,true));return;}// 修正後staticvoidfoo(constFunctionCallbackInfo<Value>&args){Isolate*isolate=args.GetIsolate();#if (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:nomatchingfunctionforcallto‘v8::Array::Get(int)’dst_addr[0]=arr->Get(0)->NumberValue(context).FromMaybe(0);^Infileincludedfrom/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_RESULTMaybeLocal<Value>Get(Local<Context>context,^~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3594:43:note:candidateexpects2arguments,1provided/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_RESULTMaybeLocal<Value>Get(Local<Context>context,^~~/home/***/.cache/node-gyp/13.11.0/include/node/v8.h:3597:43:note:candidateexpects2arguments,1provided
コード
// 修正前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のv10.x(V8 6.8)からv11.x(V8 7.0)でV8 APIに大きな変更が入り5、全体的に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) ↩