11

I am writing a custom node.js addon by C++ mixed with C program.

The addon.cc consists of something like

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <node_buffer.h>

using namespace v8;
using namespace node;


/* other logic and function... */


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

    Local<Value> buffer1 = args[0];
    size_t size = Buffer::Length(buffer1->ToObject());
    char* bufferdata = Buffer::Data(buffer1->ToObject());

    /* some logic written in C style ... */

    Local<Function> cb = Local<Function>::Cast(args[1]);
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New(String::New(outputdata, outputSize)) };

    cb->Call(Context::GetCurrent()->Global(), argc, argv);

    return scope.Close(Undefined());
}

void Init(Handle<Object> target) {
    target->Set(String::NewSymbol("runCallback"), FunctionTemplate::New(RunCallback)->GetFunction());
}

NODE_MODULE(addon, Init)

It also includes other .cc files, so the wscript is like this:

srcdir = '.'
blddir = 'build'
VERSION = '0.0.1'

def set_options(opt):
  opt.tool_options('compiler_cxx')

def configure(conf):
  conf.check_tool('compiler_cxx')
  conf.check_tool('node_addon')

def build(bld):
  obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
  obj.target = 'addon'
  obj.source = ['addon.cc', 'otherFiles.cc']

When I run node-waf configure, it shows:

Checking for program g++ or c++          : /usr/bin/g++ 
Checking for program cpp                 : /usr/bin/cpp 
Checking for program ar                  : /usr/bin/ar 
Checking for program ranlib              : /usr/bin/ranlib 
Checking for g++                         : ok  
Checking for node path                   : not found 
Checking for node prefix                 : ok /usr/local 
'configure' finished successfully (0.169s)

When I run node-waf build, it shows:

Waf: Entering directory `/path/build'
[ 1/25] cxx: addon.cc -> build/Release/addon_1.o
... list of file ...
build/Release/list of file -> build/Release/addon.node
Waf: Leaving directory `/path/build'
'build' finished successfully (0.544s)

But when I try the following in node REPL, it shows:

var addon = require("./build/Release/addon");
Error: Unable to load shared library /path/build/Release/addon.node
    at Object..node (module.js:472:11)
    at Module.load (module.js:348:31)
    at Function._load (module.js:308:12)
    at Module.require (module.js:354:17)
    at require (module.js:370:17)
    at repl:1:13
    at REPLServer.eval (repl.js:80:21)
    at repl.js:190:20
    at REPLServer.eval (repl.js:87:5)
    at Interface.<anonymous> (repl.js:182:12)

It is very strange. I have checked that the file should match with the system architecture:

$ file build/Release/addon.node 
build/Release/addon.node: Mach-O 64-bit bundle x86_64 

$ file `which node`
/usr/local/bin/node: Mach-O 64-bit executable x86_64

By looking at nm, it shows the following:

nm ./build/Release/addon.node
0000000000011880 s GCC_except_table30
0000000000001160 t _Init
                 U __Unwind_Resume_or_Rethrow
                 U ___bzero
                 U ___gxx_personality_v0
0000000000013220 D _addon_module
                 U _free
0000000000013600 D _lsfmeanTbl
0000000000013420 D _memLfTbl
                 U _memcpy
                 U _memmove
                 U _puts
                 U _realloc
0000000000011950 s _ssqEn_win.2272
000000000001341c D _stMemLTbl
00000000000132e0 D _state_frgqTbl
00000000000132c0 D _state_sq3Tbl
                 U dyld_stub_binder
                 (... many are omitted ...)

What will be the possible reasons? Is that I cannot just combine C files with C++ files to compile? Should I remove all malloc/realloc/free? Or any other possible reasons?

ZachB
  • 13,051
  • 4
  • 61
  • 89
Harold Chan
  • 799
  • 3
  • 11
  • 31
  • I have tried to build on Mac and Linux, results are the same, showing error when including the library. – Harold Chan Mar 28 '12 at 10:49
  • I am quite sure the problem is due to external C files. But why? I doubt. – Harold Chan Mar 28 '12 at 12:20
  • 2
    maybe I should ask, is there any pure C solution for writing node.js addon? – Harold Chan Mar 29 '12 at 05:40
  • 5
    If you update to at least v0.7.6, then it will display a more helpful error message then "Unable to load shared library". That should give you something to go off of at least. P.S. Use [node-gyp](https://github.com/TooTallNate/node-gyp) ;) – TooTallNate Apr 01 '12 at 01:11
  • 1
    wow, for v0.7.6, it really shows mode debug message. I can spot the problem is related to a "const" variable! I just remove the "const" modifier, it works! Thanks @TooTallNate – Harold Chan Apr 02 '12 at 10:19
  • when "nm" the addon file, there was a undefined symbol. After removing the "const" modifier, it shows "The symbol is in the initialized data section." – Harold Chan Apr 02 '12 at 10:22
  • 2
    @HaroldChan really glad you resolved this issue! Please post an answer for your question and accept it so others can learn from your success. – Daniel Mendel May 27 '12 at 19:26

2 Answers2

1

Wrap the definition of Init() and the NODE_MODULE macro in extern "C" to avoid name C++ mangling of the exported symbols:

extern "C" {

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("runCallback"), FunctionTemplate::New(RunCallback)->GetFunction());
}

NODE_MODULE(addon, Init)
}
Myk Willis
  • 12,306
  • 4
  • 45
  • 62
0

By using node.js which version >= 0.7.6. the problem is solved. Also, it has a lot more debug message.

Harold Chan
  • 799
  • 3
  • 11
  • 31