Thursday, July 7, 2011

Node-spdy on Node.js 0.5

‹prev | My Chain | next›

I had hoped last night to get express-spdy working with the newly released version 0.5 of node.js. Unfortunately both express.js and connect are pinned to only work with versions of node less than 0.5.

Interestingly, that was not a problem when I was working with node 0.5.0-pre, meaning that npm is able to account for pre-release versions. That is some good information to file away for a rainy day.

I inquired with the express/connect maintainers about the possibility of supporting 0.5, but was very politely refused. I cannot begrudge the stance—it is certainly the correct one for them. Still, it could put me in an awkward position with respect to the release of SPDY Book.

I had planned a chapter on simple web site development with express-spdy. Installation is in an appendix so complication will not affect the narrative too much. Still things could be awkward. Let's find out how much...

Instead of express-spdy, let's try node-spdy:
cstrom@debian:~/node-spdy-example$ npm install spdy

> zlibcontext@1.0.7 install /home/cstrom/node-spdy-example/node_modules/spdy/node_modules/zlibcontext
> ./configure && make

Setting srcdir to : /home/cstrom/node-spdy-example/node_modules/spdy/node_modules/zlibcontext
Setting blddir to : /home/cstrom/node-spdy-example/node_modules/spdy/node_modules/zlibcontext/build
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 /home/cstrom/local/node-v0.5.0
Checking for library z : yes
'configure' finished successfully (0.533s)
node-waf build
Waf: Entering directory `/home/cstrom/node-spdy-example/node_modules/spdy/node_modules/zlibcontext/build'
[1/2] cxx: src/node_zlib.cc -> build/default/src/node_zlib_1.o
In file included from ../src/node_zlib.cc:2:
/home/cstrom/local/node-v0.5.0/include/node/node.h:35:17: error: eio.h: No such file or directory
...
Waf: Leaving directory `/home/cstrom/node-spdy-example/node_modules/spdy/node_modules/zlibcontext/build'
Build failed: -> task failed (err #1):
{task: cxx node_zlib.cc -> node_zlib_1.o}
make: *** [build] Error 1
Oh boy.

Looking at node-v0.5.0/include/node/node.h, I see:
...
#include <eio.h>
...
Indeed, there is no eio.h in the include directory of node 0.5:
cstrom@debian:~/repos/node$ find ~/local/node-v0.5.0/include/ -name eio.h
cstrom@debian:~/repos/node$
Bisecting the node.js source code, I trace the problem down to commit 412e413edc3864cf2d6d.

If I comment out the #include <eio.h> line, I can compile and install node-spdy. So is that a legit thing to do?

In the node source, I make the same change, perform a make distclean, reconfigure and try to compile:
cstrom@debian:~/repos/node$ make distclean
rm -rf build/doc
find tools -name "*.pyc" | xargs rm -f
rm -rf build/ node node_g
cstrom@debian:~/repos/node$ git diff
diff --git a/src/node.h b/src/node.h
index cf2980d..af25aee 100644
--- a/src/node.h
+++ b/src/node.h
@@ -32,7 +32,7 @@
#endif

#include <uv.h>
-#include <eio.h>
+//#include <eio.h>
#include <v8.h>
#include <sys/types.h> /* struct stat */
#include <sys/stat.h>
cstrom@debian:~/repos/node$
cstrom@debian:~/repos/node$
cstrom@debian:~/repos/node$ ./configure --openssl-includes=$HOME/local/include --openssl-libpath=$HOME/local/lib --prefix=$HOME/local/node-v0.5.0
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 program gcc or cc : /usr/bin/gcc
Checking for gcc : ok
Checking for library dl : yes
Checking for function SSL_library_init : yes
Checking for header openssl/crypto.h : yes
Checking for library util : yes
Checking for library rt : yes
Checking for CLOCK_MONOTONIC : yes
Checking for fdatasync(2) with c++ : yes
'configure' finished successfully (2.778s)
cstrom@debian:~/repos/node$ make
...
[ 8/33] cxx: src/node.cc -> build/default/src/node_5.o
/usr/bin/g++ -pthread -g -O3 -DHAVE_OPENSSL=1 -DHAVE_MONOTONIC_CLOCK=1 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_FDATASYNC=1 -DARCH="x64" -DPLATFORM="linux" -D__POSIX__=1 -Wno-unused-parameter -D_FORTIFY_SOURCE=2 -Idefault/src -I../src -Idefault/deps/http_parser -I../deps/http_parser -Idefault/deps/uv -I../deps/uv -Idefault/deps/uv/ev -I../deps/uv/ev -Idefault/deps/uv/eio -I../deps/uv/eio -Idefault/deps/v8/include -I../deps/v8/include -Idefault/deps/uv/c-ares -I../deps/uv/c-ares -I/home/cstrom/local/include -Ideps/v8/include ../src/node.cc -c -o default/src/node_5.o
../src/node.cc: In function ‘void node::DoPoll(uv_idle_t*, int)’:
../src/node.cc:289: error: ‘eio_poll’ was not declared in this scope
../src/node.cc: In function ‘void node::WantPollNotifier(uv_async_t*, int)’:
../src/node.cc:303: error: ‘eio_poll’ was not declared in this scope
../src/node.cc: In function ‘void node::DonePollNotifier(uv_async_t*, int)’:
../src/node.cc:316: error: ‘eio_poll’ was not declared in this scope
../src/node.cc: In function ‘char** node::Init(int, char**)’:
../src/node.cc:2438: error: ‘eio_init’ was not declared in this scope
../src/node.cc:2441: error: ‘eio_set_max_poll_reqs’ was not declared in this scope
Waf: Leaving directory `/home/cstrom/repos/node/build'
Build failed: -> task failed (err #1):
{task: cxx node.cc -> node_5.o}
make: *** [program] Error 1
Bah!

Well, I suppose that should not surprise me too much. Looking at the g++ line, I see that the deps/uv/eio directory is added to the include path. There is still an eio.h header file in there which is how node compiles with that line still uncommented.

So my task it to uncomment the #include <eio.h> line, and ensure that eio.h is installed along with the other header files during a make install. Uncommenting a line is easy enough, but how to install?

I am not quite sure how the old eio headers were installed. In the node wscript file, two directives were removed by the problem commit:
# ...
conf.sub_config('deps/libeio')

# ...

bld.add_subdirs('deps/libeio')

#...
I am unsure which would have done the trick. Also I am unsure if either is appropriate now that the eio stuff is under libuv. Given that, I add the eio header files to the libuv header file installation code:
   bld.install_files('${PREFIX}/include/node/', 'deps/uv/*.h')
bld.install_files('${PREFIX}/include/node/', 'deps/uv/eio/*.h')
bld.install_files('${PREFIX}/include/node/ev', 'deps/uv/ev/*.h')
That does the trick, installing eio.h along with the other node header files. I can also install the node-spdy package now:
cstrom@debian:~/node-spdy-example$ npm install spdy
spdy@0.1.1 ./node_modules/spdy
└── zlibcontext@1.0.7
And then I notice the commit that went into node.js 4 hours after I started this: 8a9fdedc9e89f050974b. That commit resolves the problem by simply moving eio.h into the main libuv directory.

Bleh.

Ah well, I learned a bit of node.js install internals and verified that node-spdy can still install with version 0.5. The example app runs, but the test server, which relies on connect.js, does not. I still need to come up with a strategy for that. Tomorrow.


Day #68

No comments:

Post a Comment