将多个C++文件打包成一个Node.js模块的扩展。

5
我正在使用node.js进行一些小实验,以评估如何将一个复杂的基于C的库与node.js连接。这个库可以对数据库执行多种操作,而node.js应该通过rest api调用这些函数并返回结果。
在尝试使用node.js示例时,我遇到了一个问题:
我正在尝试构建一个基于两个cc文件的插件:
addon1.c:
#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> Add(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    ThrowException(Exception::TypeError(String::New("Wrong arguments")));
    return scope.Close(Undefined());
  }

  Local<Number> num = Number::New(args[0]->NumberValue() +
      args[1]->NumberValue());
  return scope.Close(num);
}

void Init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("add"),
      FunctionTemplate::New(Add)->GetFunction());
}

NODE_MODULE(addon, Init)

addon2.c:

#define BUILDING_NODE_EXTENSION
#include <node.h>

using namespace v8;

Handle<Value> Del(const Arguments& args) {
  HandleScope scope2;

  if (args.Length() < 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope2.Close(Undefined());
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    ThrowException(Exception::TypeError(String::New("Wrong arguments")));
    return scope2.Close(Undefined());
  }    

  Local<Number> num = Number::New(args[0]->NumberValue() -
      args[1]->NumberValue());
  return scope2.Close(num);
}

void Init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("del"),
      FunctionTemplate::New(Del)->GetFunction());
}

NODE_MODULE(addon, Init)

我的 binding.gyp 文件:
{
  "targets": [
    {
      "target_name": "addon",
      "sources": ["addon1.cc", "addon2.cc"]
    }
  ]
}

调用 node.gyp 配置构建以以下错误消息结束:
  CXX(target) Release/obj.target/addon/addon2.o
  SOLINK_MODULE(target) Release/addon.node
duplicate symbol __Z4InitN2v86HandleINS_6ObjectEEE in:
    Release/obj.target/addon/addon1.o
    Release/obj.target/addon/addon2.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Release/addon.node] Error 1
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/opt/local/lib/node_modules/node-gyp/lib/build.js:267:23)
gyp ERR! stack     at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (child_process.js:797:12)
gyp ERR! System Darwin 13.1.0
gyp ERR! command "node" "/opt/local/bin/node-gyp" "configure" "build"
gyp ERR! cwd /Applications/MAMP/htdocs/nodejs/test2
gyp ERR! node -v v0.10.26
gyp ERR! node-gyp -v v0.13.0
gyp ERR! not ok 

我希望你们中的任何一个都有解决这个问题的提示。
提前感谢。

дҪ зҡ„й—®йўҳдёӯж–Ү件зҡ„жү©еұ•еҗҚжҳҜ.cиҝҳжҳҜ.ccпјҹдёҚеӨӘжё…жҘҡгҖӮ - Some programmer dude
2个回答

1
从您的实现中,我可以看到您正在尝试实现两个不同的模块 add 和 del
node.js 提供了不同类型的 Addon 模式,建议参考http://nodejs.org/api/addons.html
在我看来,您所尝试实现的内容可以通过包装 C++ 对象来实现。

1
嗨,我正在寻找一种方法来创建一个模块(插件),该模块有两个方法(del、add),并在两个不同的cpp文件中实现每个方法。 - solick
是的,这是可能的。但不是根据原始帖子中您尝试实现的方式。如果您仔细查看整个页面,您肯定会找到答案。 - Rahul Shukla

1
问题很明显:你在两个翻译单元(源文件)中都有一个名为“Init”的函数。由于你正在构建一个“单一”模块,应该只有一个“Init”函数。
解决这个问题的简单方法是删除一个“Init”函数,并在剩余的“Init”函数中“注册”“add”和“del”名称。
解决方案:在一个源文件中,您只有唯一的Init函数,并且声明缺失的AddDel函数(即创建函数原型):
// Declare function prototypes
Handle<Value> Add(const Arguments& args);
Handle<Value> Del(const Arguments& args);

// The one and only initialization function
void Init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("add"),
      FunctionTemplate::New(Add)->GetFunction());
  exports->Set(String::NewSymbol("del"),
      FunctionTemplate::New(Del)->GetFunction());
}

NODE_MODULE(addon, Init)

实际上,现在你可以将其作为单独的源文件。

但是如果没有init函数,我该如何初始化“del”方法呢?我尝试将其重命名为init2,但仍然出现相同的错误。 - solick
不,那也不行。如果我将del的初始化移动到addon1.c的init函数中,会出现未声明标识符“Del”的错误。将init函数移动到addon2.c会产生相同的错误,但现在是标识符“Add”。 - solick
谢谢,我已经自己找到了这个解决方案。显然,Node.js开发人员没有打算将同一模块中的函数拆分为不同的文件。 - solick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接