Some languages provide facilities for that kind of dependency. PHP jumps to mind as the obvious example. The DOM and XSL extensions in PHP are just two of several that depend on the base libxml extension. Those extensions can be installed separately, but they share dependences at the C language level with libxml. PHP handles that kind of linkage. Node.js does not.
I should note that this word of caution does not apply to modules like nan, which do not actually provide external classes or functions you must link to. The nan module is just a header file you include.
The short answer is that you'd have a lot of linkage issues to solve yourself. If you were developing on a Mac, you'd find that if you put the headers you depend upon in your include path, and required the module you depend on before loading your own bindings, things would probably work. That would not work at all on Linux, however, and you'd probably be left scratching your head as to why.
The reason for the difference between systems turns out to be a quirk in the standard
dlopen function. C/C++ addons are just dynamic libraries, and Node loads those libraries with a function in libuv called
uv_dlopen. That provides a uniform interface for loading dynamic libraries on both Windows and Unix-like systems. For Unix-style systems libuv turns that into this call:
lib->handle = dlopen(filename, RTLD_LAZY);
The only flag being passed to
RTLD_LAZY. Without any other flags specified,
dlopen on OSX will behave as though
RTLD_GLOBAL were given by default. Linux, on the other hand, will default to the behavior of
RTLD_LOCAL. That means you get completely opposite behavior on different systems. On OSX, the symbols in loaded libraries will be pulled in to the global namespace. In other words, the functions in the loaded libraries can be found and called by other libraries that are loaded. On Linux, those functions can essentially only be called from within the same library. Off hand, I'm not sure how Windows might further complicate the picture.
LoadLibraryEx, which libuv uses, doesn't appear to provide flags similar to
RTLD_GLOBAL, so it may just always put symbols in the global space, but that would just be a guess.
Alterntively, you could try to to include the other addon as an explicit dependency in your
binding.gyp. That will build a copy of the library in your local build directory, but, as far as I can tell, it won't create a link to it in your own shared library.
var DynamicLibrary = require('ffi').DynamicLibrary;
DynamicLibrary.FLAGS.RTLD_LAZY | DynamicLibrary.FLAGS.RTLD_GLOBAL
That code is going to be a bit brittle, however. It doesn't handle all of the different variations in binding output locations and naming conventions that are in the wild, and any change in the build behavior in Node would require changes to your code as well.
Overall, it just doesn't feel like a good solution for a production system. So, as I said at the beginning, my recommendation is to just avoid the problem altogether.