Skip to content

Commit 1550858

Browse files
committed
addon: Pass module object to NODE_MODULE init function
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
1 parent 00b4b7b commit 1550858

File tree

6 files changed

+52
-13
lines changed

6 files changed

+52
-13
lines changed

lib/module.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,7 @@ Module._extensions['.json'] = function(module, filename) {
488488

489489

490490
//Native extension for .node
491-
Module._extensions['.node'] = function(module, filename) {
492-
process.dlopen(filename, module.exports);
493-
};
491+
Module._extensions['.node'] = process.dlopen;
494492

495493

496494
// bootstrap main module.

src/node.cc

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ Persistent<String> domain_symbol;
101101

102102
static Persistent<Object> process;
103103

104+
static Persistent<String> exports_symbol;
105+
104106
static Persistent<String> errno_symbol;
105107
static Persistent<String> syscall_symbol;
106108
static Persistent<String> errpath_symbol;
@@ -1786,8 +1788,8 @@ Handle<Value> Hrtime(const v8::Arguments& args) {
17861788

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

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

1803-
String::Utf8Value filename(args[0]); // Cast
1804-
Local<Object> target = args[1]->ToObject(); // Cast
1805+
Local<Object> module = args[0]->ToObject(); // Cast
1806+
String::Utf8Value filename(args[1]); // Cast
1807+
1808+
if (exports_symbol.IsEmpty()) {
1809+
exports_symbol = NODE_PSYMBOL("exports");
1810+
}
1811+
Local<Object> exports = module->Get(exports_symbol)->ToObject();
18051812

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

1815-
String::Utf8Value path(args[0]);
1822+
String::Utf8Value path(args[1]);
18161823
base = *path;
18171824

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

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

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

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

19591968
} else if (!strcmp(*module_v, "constants")) {

src/node.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
# endif
8484
#endif
8585

86+
8687
namespace node {
8788

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

199200
const char *signo_string(int errorno);
200201

202+
203+
NODE_EXTERN typedef void (* addon_register_func)(
204+
v8::Handle<v8::Object> exports, v8::Handle<v8::Value> module);
205+
201206
struct node_module_struct {
202207
int version;
203208
void *dso_handle;
204209
const char *filename;
205-
void (*register_func) (v8::Handle<v8::Object> target);
210+
node::addon_register_func register_func;
206211
const char *modname;
207212
};
208213

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

219224
#define NODE_STANDARD_MODULE_STUFF \
220225
NODE_MODULE_VERSION, \
@@ -232,7 +237,7 @@ node_module_struct* get_builtin_module(const char *name);
232237
NODE_MODULE_EXPORT node::node_module_struct modname ## _module = \
233238
{ \
234239
NODE_STANDARD_MODULE_STUFF, \
235-
regfunc, \
240+
(node::addon_register_func)regfunc, \
236241
NODE_STRINGIFY(modname) \
237242
}; \
238243
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <node.h>
2+
#include <v8.h>
3+
4+
using namespace v8;
5+
6+
Handle<Value> Method(const Arguments& args) {
7+
HandleScope scope;
8+
return scope.Close(String::New("world"));
9+
}
10+
11+
void init(Handle<Object> exports, Handle<Object> module) {
12+
NODE_SET_METHOD(module, "exports", Method);
13+
}
14+
15+
NODE_MODULE(binding, init);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'sources': [ 'binding.cc' ]
6+
}
7+
]
8+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var assert = require('assert');
2+
var binding = require('./build/Release/binding');
3+
assert.equal('world', binding());
4+
console.log('binding.hello() =', binding());

0 commit comments

Comments
 (0)