0

いくつかの計算を実行するための C++ プロジェクトがあります。C++ コードは、ブラウザ ベースの GUI のバックエンドとしてサーバーに配置されます。Node.js はこの仕事に適しているようです。チュートリアルを読み、nodejs モジュールとして使用する C++ コードをビルドする方法を学びました。

簡単にするために、C++ コードをスタティック ライブラリとしてコンパイルしたいと思います。その後、nodejs 環境で使用できるこのライブラリを参照する C++ クラスを作成できます。これのポイントは、node-gyp build を使用して C++ プロジェクト全体をビルドする必要がないことです。このようにして、フロントエンドについてあまり心配することなく、C++ コードをさらに開発できます。

これを達成するために、次のことを行いました。

  1. 次のように単純な C++ ライブラリをビルドします。これを Visual Studio 2013 でビルドして .lib ファイルを取得します。

    //MyClass.h
    #pragma once
    class MyClass
    {
    public:
        double Multiply(double a, double b)
        {
            return a*b;
        }
        MyClass();
        ~MyClass();
    };
    
  2. 次のように、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
    
  3. 初期化するためのメイン 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
    
  4. binding.gyp ファイルは次のように定義されています。

        {
          "targets": [
            {
              "target_name": "cpphello",
              "sources": [ "cpphello.cpp", "myobject.cpp"],
              "libraries": [ "D:/East101/Adri/javascript/socketio/cpplib/build/x64/Debug/MyLib"]
            }
          ]
        }
    
  5. 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++とコーディング全般にまったく慣れていないので、これに間違ったアプローチをしている可能性があります。

4

2 に答える 2

1

C++ は Java などとは少し異なります。静的メンバーを宣言する場合は、CPP ファイルで定義する必要があります。次のように考えてください: オブジェクトをインスタンス化すると、通常のメンバー変数が割り当てられます。しかし、静的メンバー変数は最初から存在します。そのため、実際にメモリを割り当てるためにどこかで定義する必要があります。

cpp ファイルに以下を記述すれば解決できます。

namespace demo
{

    MyClass* MyObject::mycalcobj;

    //...

(例えば、こちらまたはこちらをご覧ください)

于 2015-11-09T15:14:28.440 に答える