I did a bunch of Googling this morning looking for how to build a C++ node.js module, using the new gyp build system. There a plenty of blog posts on doing native module builds via node-waf but not with the gyp_addon python script.
I took the liberty of basing this example off Teemu Ikonen’s blog entry on threaded extensions.
Here is the C++ node.js module source. This is an extension which creates a thread, and then makes a callback every 5 seconds. It’s a good example because it also uses some of node’s internal libraries (namely libev):
GYP build system: gyp_addon
Go ahead and look at the original blog entry if you want to build with node-waf. Going forward, however, with new versions of node you will need to use the gyp build system. Luckily, there is a great project on github which will make this easier depending on your circumstances. This is TooTallNate’s node-gyp script, which itself uses node to make cross-platform building of your extension easier. I highly suggest going this route if
- You are developing a standard extension for the node.js system
- You are not doing cross compiling
- and you want cross platform support (who wouldn’t)
On the other hand, if you are working off the tip and/or are doing cross-compiling, or some other case where you need a custom node.js source tree itself, then you may want to go this route… First you need a gyp build file. Here is one for the texample.cpp extension. More description follows.
Now, we are doing a few extra things here:
- We are specifying a build for x86_64 arch. See target_arch line in variables. (For some reason node pays no attention to config.gypi in the root of the source folder. Not sure why… post something if you know.)
- And to also support x86_64 we have a line ['cflags'] line under Linux section specifying -fPIC. You need this option when building shared libraries on x86_64 for node.
- Notice node_root, a variable defined at the top. This is where the node.js source is in comparison to your source files
- We also include some non-standard include directories, specifically stuff used inside node. deps/uv/include/uv-private is where the libev headers are. And this example uses those.
Building
For gyp_addon to work, you will need to run it out of the tools directory, unless you have node more permanently installed. Since texample.gyp references everything relative to where it (texample.gyp) is, then this will be fine. Just point gyp_addon to it:
ed@computer:~/node-0.7.0/tools$ ./gyp_addon ../../src/texample.gyp ed@computer:~/node-0.7.0/tools$ make ACTION Regenerating Makefile CXX(target) out/Debug/obj.target/texample/../../src/texample.o SOLINK_MODULE(target) out/Debug/obj.target/../../src/texample.node SOLINK_MODULE(target) out/Debug/obj.target/../../src/texample.node: Finished COPY out/Debug/texample.node ed@computer:~/node-0.7.0/tools$ ls out/Debug/ linker.lock obj.target src texample.node
and your output should be similar.
At some later point we will show an example of cross-compiling using this method.
Quick test:
ed@computer:~/node-0.7.0$ ./node
> texample = require('./texample');
{ start: [Function] }
> texample.callback = function(i) {
... console.log("bang: " + i );
... }
[Function]
> texample.start();
true
> bang: 0
bang: 1
bang: 2
bang: 3
“Unable to open shared library”
If you get such an error, and you know for certain that node.js really is finding your library file (you could verify with strace), its likely that your object format’s are not compatible. This means you built the node.js for x86_64 and your object file is ia32. You can verify this by doing something similar to:
ed@computer:~/node-0.7.0/tools$ objdump -g out/Debug/texample.node out/Debug/texample.node: file format elf32-i386
This command also run on the node executable needs to output the same format, here elf32-i386. If you’re on 64-bit linux, it would be elf64-x86-64. Putting this here because I suspect folks running node on x64 will run into this issue.






