Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js c++ extension multiple cc files into one module

i´m playing a little bit with node.js to evaluate how a complexe c based library could be connected with node.js. This lib perform several actions with a database and nodejs shall call this functions and return the results via rest api.

While playing aroung with the examples from the node.js side, i faced a problem:

I´m trying to build one addon based on two cc files:

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)

And my binding.gyp:

{
  "targets": [
    {
      "target_name": "addon",
      "sources": ["addon1.cc", "addon2.cc"]
    }
  ]
}

calling node.gyp configure build ends with following error messages:

  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 

I hope anyone of you have a hint how to solve this issue.

Thanks in advance.

like image 411
solick Avatar asked Nov 02 '22 02:11

solick


1 Answers

The problem is pretty clear: You have a function named Init in both translation units (source files). As you are building a single module, you should have only one Init function.

The simple way to solve this is to remove one Init function, and "register" both add and del names in the remaining Init function.


Solution: In one source file you have the only Init function, and declare the missing Add or Del function (i.e. you make function prototypes):

// 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)

Actually, you can now have this as a separate source file.

like image 115
Some programmer dude Avatar answered Nov 12 '22 16:11

Some programmer dude