いくつかの計算を実行するための C++ プロジェクトがあります。C++ コードは、ブラウザ ベースの GUI のバックエンドとしてサーバーに配置されます。Node.js はこの仕事に適しているようです。チュートリアルを読み、nodejs モジュールとして使用する C++ コードをビルドする方法を学びました。
簡単にするために、C++ コードをスタティック ライブラリとしてコンパイルしたいと思います。その後、nodejs 環境で使用できるこのライブラリを参照する C++ クラスを作成できます。これのポイントは、node-gyp build を使用して C++ プロジェクト全体をビルドする必要がないことです。このようにして、フロントエンドについてあまり心配することなく、C++ コードをさらに開発できます。
これを達成するために、次のことを行いました。
次のように単純な C++ ライブラリをビルドします。これを Visual Studio 2013 でビルドして .lib ファイルを取得します。
//MyClass.h #pragma once class MyClass { public: double Multiply(double a, double b) { return a*b; } MyClass(); ~MyClass(); };
次のように、nodejs モジュールとして使用する C++ オブジェクトを作成しました。
// myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include <node.h> #include <node_object_wrap.h> #include "MyLib\MyClass.h" namespace demo { class MyObject : public node::ObjectWrap { public: static void Init(v8::Local<v8::Object> exports); static MyClass* mycalcobj; private: explicit MyObject(double value = 0); ~MyObject(); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args); static v8::Persistent<v8::Function> constructor; double value_; }; } // namespace demo #endif
そしてcppファイル
// myobject.cpp #include "myobject.h" //#include "worker.h" namespace demo { using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::Persistent; using v8::String; using v8::Value; Persistent<Function> MyObject::constructor; MyObject::MyObject(double value) : value_(value) { } MyObject::~MyObject() { } void MyObject::Init(Local<Object> exports) { Isolate* isolate = exports->GetIsolate(); // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); constructor.Reset(isolate, tpl->GetFunction()); exports->Set(String::NewFromUtf8(isolate, "MyObject"), tpl->GetFunction()); } void MyObject::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } //define functions here void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder()); double x = obj->value_; mycalcobj = new MyClass(); x=mycalcobj->Multiply(2, x); obj->value_= x; args.GetReturnValue().Set(Number::New(isolate, obj->value_)); } } // namespace demo
初期化するためのメイン cpp ファイルを作成します
#include <node.h> #include "myobject.h" namespace demo { using v8::Local; using v8::Object; void InitAll(Local<Object> exports) { MyObject::Init(exports); } NODE_MODULE(addon, InitAll) } // namespace demo
binding.gyp ファイルは次のように定義されています。
{ "targets": [ { "target_name": "cpphello", "sources": [ "cpphello.cpp", "myobject.cpp"], "libraries": [ "D:/East101/Adri/javascript/socketio/cpplib/build/x64/Debug/MyLib"] } ] }
node-gyp configure build を使用してプロジェクトをビルドする
次のメッセージが表示されます。
MyLib.lib(MyClass.obj) : warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/OPT:ICF' specification [D:\East101\Adri\javascript\socketio\cpplib\build\cpphello.vcxproj]
LINK : warning LNK4098: defaultlib 'MSVCRTD' conflicts with use of other libs;use /NODEFAULTLIB:library [D:\East101\Adri\javascript\socketio\cpplib\build\cpphello.vcxproj]
myobject.obj : error LNK2001: unresolved external symbol "public: static class MyClass * demo::MyObject::mycalcobj" (?mycalcobj@MyObject@demo@@2PEAVMyClass@@EA) [D:\East101\Adri\javascript\socketio\cpplib\build\cpphello.vcxproj] D:\East101\Adri\javascript\socketio\cpplib\build\Release\cpphello.node : fatal error LNK1120: 1 unresolved externals [D:East101\Adri\javascript\socketio\cpplib\build\cpphello.vcxproj]
このエラーを修正して思い通りに動作させるか、より良い方法があるかどうかをお知らせください。私はC++とコーディング全般にまったく慣れていないので、これに間違ったアプローチをしている可能性があります。