Link Node.js 带有静态库的 C++ 附加组件
Link Node.js C++ add-on with static library
我有一个旨在执行一些计算的 C++ 项目。 C++ 代码将位于服务器上,作为基于浏览器的 GUI 的后端。 Node.js 似乎适合这份工作。我已经完成了教程并学会了构建 C++ 代码以用作 nodejs 模块。
为了简单起见,我想将C++代码编译为静态库。然后我可以编写一个 C++ class 来引用这个库,然后可以在 nodejs 环境中使用它。这样做的目的是,我不必使用 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++ 和一般编码还很陌生,所以我可能只是在接近这个错误。
C++ 与 Java 等有点不同...如果声明静态成员,则需要在 CPP 文件中定义它。可以这样想:一个normal成员变量是在你实例化一个对象的时候分配的。但是一开始就存在一个静态成员变量。所以你需要在某个地方定义它来为它实际分配内存。
如果将以下内容放入您的 cpp 文件中,您可以解决它:
namespace demo
{
MyClass* MyObject::mycalcobj;
//...
(例如看看here or here)
你的意思是类似这样的吗?
How to add dependence to static library in binding.gyp?
'libraries': ['-L/path/to/dir', '-lfoo']
我有一个旨在执行一些计算的 C++ 项目。 C++ 代码将位于服务器上,作为基于浏览器的 GUI 的后端。 Node.js 似乎适合这份工作。我已经完成了教程并学会了构建 C++ 代码以用作 nodejs 模块。
为了简单起见,我想将C++代码编译为静态库。然后我可以编写一个 C++ class 来引用这个库,然后可以在 nodejs 环境中使用它。这样做的目的是,我不必使用 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++ 和一般编码还很陌生,所以我可能只是在接近这个错误。
C++ 与 Java 等有点不同...如果声明静态成员,则需要在 CPP 文件中定义它。可以这样想:一个normal成员变量是在你实例化一个对象的时候分配的。但是一开始就存在一个静态成员变量。所以你需要在某个地方定义它来为它实际分配内存。
如果将以下内容放入您的 cpp 文件中,您可以解决它:
namespace demo
{
MyClass* MyObject::mycalcobj;
//...
(例如看看here or here)
你的意思是类似这样的吗?
How to add dependence to static library in binding.gyp?
'libraries': ['-L/path/to/dir', '-lfoo']