Node.js on OpenEmbeded
The successful build instructions in a nutshell:
opkg install python python-modules python-distutils python-misc
opkg install task-sdk-native
opkg install openssl openssl-dev
wget http://nodejs.org/dist/node-v0.1.102.tar.gz
tar xf node-v0.1.102.tar.gz
cd node-v0.1.102
export CC='gcc -march=armv7-a -mtune=cortex-a8' # -march=armv5te works for older systems
export CXX='g++ -march=armv7-a -mtune=cortex-a8'
./configure
make
make install
Tracing Errors
There are a number of DIY kits for embedded development which support OpenEmbedded. BeagleBoard and Gumstix are two that have a growing community and a good name for themselves.
Over the weekend I had the pleasure of borrowing a Gumstix Overo Earth with the Tobi expansion board to see if I could get Node.js running on it before I bought my own. I'm going to give you the red-green step-through starting with a bitbake build of a console-image using the default gumstix opkg repository (I believe this is a clone of the Angstrom repo - the same as BeagleBoard, etc - with a few tweaks), but assuming you have the OpenEmbedded environment of your choice up and running, the instructions should be pretty much the same.
Prerequisits:
- A pre-built or hand-tailored console image.
- An SD card with a specially crafted partition layout
- A basic understanding of opkg
Note on Rolling your own
Rolling your own is always optional and is done on your host system (the x86 or x86-84 box you cross-compile from, not the OpenEmbedded device).
You will need to find the ipk files in a sub-directory of ./tmp/deploy/glibc/ipk/
, copy them over with scp
, and install them with opkg install _package-name_.ipk
Red
cd ~/
wget http://nodejs.org/dist/node-v0.1.102.tar.gz
tar xf node-v0.1.102.tar.gz
cd node-v0.1.102
./configure
make
And we see that we don't have gcc...
task-sdk-native: The native arm compiler
Rolling your own: several hours
bitbake task-sdk-native
On some Linuxes (Ubuntu pre-10.04, for example) you will get [an error][xz-error]
/bin/sh: xz: command not found
tar: This does not look like a tar archive
tar: Exiting with failure status due to previous errors
NOTE: Task failed:
ERROR: TaskFailed event exception, aborting
ERROR: Build of /home/mark/overo-oe/org.openembedded.dev/recipes/grep/grep_2.6.3.bb do_unpack failed
ERROR: Task 1727 (/home/mark/overo-oe/org.openembedded.dev/recipes/grep/grep_2.6.3.bb, do_unpack) failed
NOTE: Tasks Summary: Attempted 2437 tasks of which 2411 didn't need to be rerun and 1 failed.
ERROR: '/home/mark/overo-oe/org.openembedded.dev/recipes/grep/grep_2.6.3.bb' failed
This is because lzma
has been replaced by xz-utils
. You can run apt-get install xz-utils
and safely ignore the warning that by uninstalling lzma
that You are about to do something potentially harmful.
and enter Yes, do as I say!
.
Installing from the repo: several minutes
opkg install task-sdk-native
Now let's try again.
cd ~/node-v0.1.102
make
And we see that we don't have python
python: runs the WAF compiler tools
This first error is that python isn't installed, that seems intuitive enough to fix
./configure
/usr/bin/env: python: No such file or directory
opkg install python
Next is a BOM enocding error. This has to do with utf-8 / unicode / ISOxxxx stuff.
./configure
File "/home/root/node-v0.1.102/tools/waf-light", line 2
SyntaxError: encoding problem: with BOM
# edit /home/root/node-v0.1.102/tools/waf-light
# change `# encoding: ISO8859-1` to `# encoding: utf-8`
shutil is missing. After some hunting, I found it.
./configure
Traceback (most recent call last):
File "/home/root/node-v0.1.102/tools/waf-light", line 157, in <module>
import Scripting
File "/home/root/node-v0.1.102/tools/wafadmin/Scripting.py", line 7, in <module>
import os, sys, shutil, traceback, datetime, inspect, errno
ImportError: No module named shutil
opkg install python-modules
The next error is quite interesting. You'd think string would be part of python
./configure
ImportError: No module named string
opkg install python-distutils
We find that the gcc compiler isn't installed, which almost seems like we're getting out of the python errors... but not quite
./configure
Checking for program g++ or c++ : not found
Checking for program icpc : not found
Checking for program c++ : not found
/home/root/node-v0.1.102/wscript:130: error: could not configure a cxx compiler!
opkg install task-sdk-native
Finally our last python error - python doesn't know which platform we're on. I would like to note that misc, util, modules, and tools are terrible names for packages...
./configure
/home/root/node-v0.1.102/deps/c-ares/wscript: error: Traceback (most recent call last):
File "/home/root/node-v0.1.102/tools/wafadmin/Utils.py", line 274, in load_module
exec(compile(code, file_path, 'exec'), module.__dict__)
File "/home/root/node-v0.1.102/deps/c-ares/wscript", line 2, in <module>
import platform
ImportError: No module named platform
opkg install python-misc
And now on to compiler errors...
v8: the engine behind node
I knew that the OMAP3530 has thumb support, so this was confusing
/home/root/node-v0.1.101/deps/v8/src/arm/macro-assembler-arm.cc:59:3: error: #error "For thumb inter-working we require an architecture which supports blx"
scons: *** [obj/release/arm/macro-assembler-arm.o] Error 1
scons: building terminated because of errors.
Waf: Leaving directory `/home/root/node-v0.1.101/build'
Build failed: -> task failed (err #2):
{task: libv8.a SConstruct -> libv8.a}
make: *** [all] Error 1
At first I thought the best course of action was to fake CAN_USE_THUMB_INSTRUCTIONS by manually defining it in the code
g++ -o obj/release/platform-linux.o -c -Wall -W -Wno-unused-parameter -Wnon-virtual-dtor -pedantic -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections -ansi -fno-rtti -fno-exceptions -Wall -W -Wno-unused-parameterc
/tmp/ccNcgrdW.s: Assembler messages:
/tmp/ccNcgrdW.s:150: Error: bad instruction `int $3'
scons: *** [obj/release/platform-linux.o] Error 1
scons: building terminated because of errors.
Waf: Leaving directory `/home/root/node-v0.1.101/build'
Build failed: -> task failed (err #2):
{task: libv8.a SConstruct -> libv8.a}
make: *** [all] Error 1
But that wasn't enough so I figured ARM_V7_A should be faked too
/tmp/ccxCSjUb.s: Assembler messages:
/tmp/ccxCSjUb.s:47: Error: selected processor does not support `bkpt 0'
scons: *** [obj/release/arm/cpu-arm.o] Error 1
scons: building terminated because of errors.
Waf: Leaving directory `/home/root/node-v0.1.101/build'
Build failed: -> task failed (err #2):
{task: libv8.a SConstruct -> libv8.a}
make: *** [all] Error 1
Further investigation revealed that the compiler was faking (and forcing) the platform to appear as an ARMv4:
touch foo.cc
g++ foo.cc -dM -E | grep ARM
#define __ARMEL__ 1
#define __ARM_ARCH_4T__ 1
#define __ARM_EABI__ 1
I found that the way to fix this is to use -march
, -mtune
, and -mcpu
flags:
touch foo.cc
g++ foo.cc -march=armv7-a -mtune=cortex-a8 -dM -E | grep ARM
#define __ARMEL__ 1
#define __ARM_ARCH_7A__ 1
#define __ARM_EABI__ 1
I couldn't figure out how to pass compiler arguments directly to WAF
./configure -march=armv7-a
waf-light: error: no such option: -march
I did find that WAF respects environment variables.
export CC='gcc -march=armv7-a'
export CXX='g++ -march=armv7-a'
Viola!
make
#... lots of successful output
Waf: Leaving directory `/home/root/node-v0.1.101/build'
'build' finished successfully (40m36.030s)
Other Notes
production: node.js - without python and gcc
I believe the binary node
is the only thing necessary to be able to run node, assuming that the shared libraries that it is linked against are present - those being openssl
and optionally v8
, libev
, libio
.
You shouldn't need python, or g++. However, you will need libcstd++
overo-oe/tmp/work/armv7a-angstrom-linux-gnueabi/gcc-cross-4.3.3-r12.1/staging-pkg/deploy/glibc/ipk/armv7a/libstdc++6_4.3.3-r12.1.5_armv7a.ipk
openssl support
opkg install openssl
opkg install openssl-dev
running on other distros
librt.so.1 => /lib/librt.so.1 (0x40026000)
libssl.so.0.9.8 => /usr/lib/libssl.so.0.9.8 (0x40035000)
libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8 (0x4007c000)
libdl.so.2 => /lib/libdl.so.2 (0x401a3000)
libm.so.6 => /lib/libm.so.6 (0x401ae000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x40221000)
libpthread.so.0 => /lib/libpthread.so.0 (0x40233000)
libc.so.6 => /lib/libc.so.6 (0x40252000)
/lib/ld-linux.so.3 (0x40000000)
Leftover warnings
I'm pretty sure that sync_file_range is a fairly new operation that isn't implemented in all file io libraries yet.
default/deps/libeio/eio_1.o: In function `eio__sync_file_range':
/home/root/node-v0.1.102/build/../deps/libeio/eio.c:872: warning: warning: sync_file_range is not implemented and will always fail
creating a static binary
And the solution is to add conf.env["FULLSTATIC"] = True
to the wscript
TODO: create a patch for this and post it to the mailing list
vim wscript
opt.add_option( '--shared-libev-libpath'
, action='store'
, default=False
, help='A directory to search for the shared libev DLL'
, dest='shared_libev_libpath'
)
+ opt.add_option( '--static'
+ , action='store'
+ , default=False
+ , help='Whether to compile node statically'
+ , dest='full_static'
+ )
def configure(conf):
conf.check_tool('compiler_cxx')
if not conf.env.CXX: conf.fatal('c++ compiler not found')
conf.check_tool('compiler_cc')
if not conf.env.CC: conf.fatal('c compiler not found')
o = Options.options
conf.env["USE_DEBUG"] = o.debug
# TODO --static = o.static
+ conf.env["FULLSTATIC"] = o.full_static
conf.env["USE_SHARED_V8"] = o.shared_v8 or o.shared_v8_includes or o.shared_v8_libpath or o.shared_v8_libname
conf.env["USE_SHARED_CARES"] = o.shared_cares or o.shared_cares_includes or o.shared_cares_libpath
conf.env["USE_SHARED_LIBEV"] = o.shared_libev or o.shared_libev_includes or o.shared_libev_libpath
You can't link static libraries against dynamic libraries, so your friendly error might look like:
/arm-angstrom-linux-gnueabi/bin/ld: cannot find -lssl
opkg install openssl-static
make
Leftover warnings
I'm not sure if these matter or not, but they're the warnings I got
root/node-v0.1.102/build/default/node -pthread -rdynamic /home/root/node-v0.1.102/build/default/libv8.a -static -lrt -lssl -lcrypto -ldl
default/src/node_4.o: In function `node::DLOpen(v8::Arguments const&)':
/home/root/node-v0.1.102/build/../src/node.cc:1271: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
default/src/node_4.o: In function `node::SetGid(v8::Arguments const&)':
/home/root/node-v0.1.102/build/../src/node.cc:1099: warning: Using 'getgrnam_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
default/src/node_4.o: In function `node::SetUid(v8::Arguments const&)':
/home/root/node-v0.1.102/build/../src/node.cc:1134: warning: Using 'getpwnam_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
default/src/node_net_4.o: In function `node::Resolve(eio_req*)':
/home/root/node-v0.1.102/build/../src/node_net.cc:1165: warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
default/deps/c-ares/ares_getnameinfo_1.o: In function `lookup_service':
/home/root/node-v0.1.102/build/../deps/c-ares/ares_getnameinfo.c:310: warning: Using 'getservbyport_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
Other Resources
- http://www.mail-archive.com/v8-users@googlegroups.com/msg01519.html
hicolor-icon-theme
There's this rather annoying (but benign) error that pops up on console systems. For some reason consolekit depends on hicolor-icon-theme, which isn't correctly installed on the console system.
Configuring hicolor-icon-theme.
//usr/lib/opkg/info/hicolor-icon-theme.postinst: line 7: can't create /etc/gtk-2.0/gdk-pixbuf.loaders: nonexistent directory
//usr/lib/opkg/info/hicolor-icon-theme.postinst: line 7: gdk-pixbuf-query-loaders: not found
//usr/lib/opkg/info/hicolor-icon-theme.postinst: line 13: gtk-update-icon-cache: not found
Configuring openssl-dev.
Collected errors:
* pkg_run_script: postinst script returned status 127.
* opkg_configure: hicolor-icon-theme.postinst returned 127.
opkg remove --force-depends hicolor-icon-theme
Removing package hicolor-icon-theme from root...
//usr/lib/opkg/info/hicolor-icon-theme.postrm: line 6: gtk-update-icon-cache: not found
Collected errors:
* pkg_run_script: postrm script returned status 127.
The last error is also meaningless.
opkg remove --force-depends hicolor-icon-theme
No packages removed.
Updated at 2010-07-26
blog comments powered by Disqus