Skip to content

Commit

Permalink
addon: Pass module object to NODE_MODULE init function
Browse files Browse the repository at this point in the history
mainly to allow native addons to export single functions on
rather than being restricted to operating on an existing
object.

Init functions now receive exports as the first argument, like
before, but also the module object as the second argument, if they
support it.

Related to #4634

cc: @rvagg
  • Loading branch information
isaacs committed Jan 25, 2013
1 parent 00b4b7b commit 1550858
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 13 deletions.
4 changes: 1 addition & 3 deletions lib/module.js
Expand Up @@ -488,9 +488,7 @@ Module._extensions['.json'] = function(module, filename) {


//Native extension for .node
Module._extensions['.node'] = function(module, filename) {
process.dlopen(filename, module.exports);
};
Module._extensions['.node'] = process.dlopen;


// bootstrap main module.
Expand Down
23 changes: 16 additions & 7 deletions src/node.cc
Expand Up @@ -101,6 +101,8 @@ Persistent<String> domain_symbol;

static Persistent<Object> process;

static Persistent<String> exports_symbol;

static Persistent<String> errno_symbol;
static Persistent<String> syscall_symbol;
static Persistent<String> errpath_symbol;
Expand Down Expand Up @@ -1786,8 +1788,8 @@ Handle<Value> Hrtime(const v8::Arguments& args) {

typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports);

// DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
// objects.
// DLOpen is process.dlopen(module, filename).
// Used to load 'module.node' dynamically shared objects.
Handle<Value> DLOpen(const v8::Arguments& args) {
HandleScope scope;
char symbol[1024], *base, *pos;
Expand All @@ -1800,8 +1802,13 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
return ThrowException(exception);
}

String::Utf8Value filename(args[0]); // Cast
Local<Object> target = args[1]->ToObject(); // Cast
Local<Object> module = args[0]->ToObject(); // Cast
String::Utf8Value filename(args[1]); // Cast

if (exports_symbol.IsEmpty()) {
exports_symbol = NODE_PSYMBOL("exports");
}
Local<Object> exports = module->Get(exports_symbol)->ToObject();

if (uv_dlopen(*filename, &lib)) {
Local<String> errmsg = String::New(uv_dlerror(&lib));
Expand All @@ -1812,7 +1819,7 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
return ThrowException(Exception::Error(errmsg));
}

String::Utf8Value path(args[0]);
String::Utf8Value path(args[1]);
base = *path;

/* Find the shared library filename within the full path. */
Expand Down Expand Up @@ -1869,7 +1876,7 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
}

// Execute the C++ module
mod->register_func(target);
mod->register_func(exports, module);

// Tell coverity that 'handle' should not be freed when we return.
// coverity[leaked_storage]
Expand Down Expand Up @@ -1953,7 +1960,9 @@ static Handle<Value> Binding(const Arguments& args) {

if ((modp = get_builtin_module(*module_v)) != NULL) {
exports = Object::New();
modp->register_func(exports);
// Internal bindings don't have a "module" object,
// only exports.
modp->register_func(exports, Undefined());
binding_cache->Set(module, exports);

} else if (!strcmp(*module_v, "constants")) {
Expand Down
11 changes: 8 additions & 3 deletions src/node.h
Expand Up @@ -83,6 +83,7 @@
# endif
#endif


namespace node {

NODE_EXTERN extern bool no_deprecation;
Expand Down Expand Up @@ -198,11 +199,15 @@ NODE_EXTERN v8::Local<v8::Value> WinapiErrnoException(int errorno,

const char *signo_string(int errorno);


NODE_EXTERN typedef void (* addon_register_func)(
v8::Handle<v8::Object> exports, v8::Handle<v8::Value> module);

struct node_module_struct {
int version;
void *dso_handle;
const char *filename;
void (*register_func) (v8::Handle<v8::Object> target);
node::addon_register_func register_func;
const char *modname;
};

Expand All @@ -214,7 +219,7 @@ node_module_struct* get_builtin_module(const char *name);
* an API is broken in the C++ side, including in v8 or
* other dependencies.
*/
#define NODE_MODULE_VERSION 0x000A /* v0.10 */
#define NODE_MODULE_VERSION 0x000B /* v0.11 */

#define NODE_STANDARD_MODULE_STUFF \
NODE_MODULE_VERSION, \
Expand All @@ -232,7 +237,7 @@ node_module_struct* get_builtin_module(const char *name);
NODE_MODULE_EXPORT node::node_module_struct modname ## _module = \
{ \
NODE_STANDARD_MODULE_STUFF, \
regfunc, \
(node::addon_register_func)regfunc, \
NODE_STRINGIFY(modname) \
}; \
}
Expand Down
15 changes: 15 additions & 0 deletions test/addons/hello-world-function-export/binding.cc
@@ -0,0 +1,15 @@
#include <node.h>
#include <v8.h>

using namespace v8;

Handle<Value> Method(const Arguments& args) {
HandleScope scope;
return scope.Close(String::New("world"));
}

void init(Handle<Object> exports, Handle<Object> module) {
NODE_SET_METHOD(module, "exports", Method);
}

NODE_MODULE(binding, init);
8 changes: 8 additions & 0 deletions test/addons/hello-world-function-export/binding.gyp
@@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}
4 changes: 4 additions & 0 deletions test/addons/hello-world-function-export/test.js
@@ -0,0 +1,4 @@
var assert = require('assert');
var binding = require('./build/Release/binding');
assert.equal('world', binding());
console.log('binding.hello() =', binding());

0 comments on commit 1550858

Please sign in to comment.