Compiling Node.js for Arduino YUN

Since few weeks I was looking for a web environment to develop an IDE for the YUN. I already compiled an avr toolchain but I was not happy with a python based app server, since it makes difficult to handle websockets in an async fashion and so.

So I looked at cross compiling plain node.js for mips, but learnt that Big Endian is not supported by V8, the javascript engine on which node is based. This probably explains why OpenWRT is missing a package for node, while for example it is available on the Intel Galileo distribution.

Luckily some folks had already done a set of patches for v8 and managed to compile node.js for the YUN processor. This tutorial is based on the patches available at: https://github.com/paul99/v8m-rb/pull/19

This tutorial has been tested on Ubuntu 12.04. Make sure you have installed all the required packages for building the linino toolchain (see this thread) plus the gcc-multilib package.

1) Build the Linino toolchain, mine is located at ~/Cross/linino

2) Create a work folder, mine is called ~/Cross/node. Inside it checkout this patched v8 branch

git clone https://github.com/paul99/v8m-rb.git -b dm-dev-mipsbe

3) Now build the v8 deps

cd v8m-rb
make dependencies

5) create the v8 build script script, i called it build.sh

STAGING_DIR=/home/fiore/Cross/linino/trunk/staging_dir
PREFIX=$STAGING_DIR/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-

export CC=${PREFIX}gcc
export CXX=${PREFIX}g++
export AR=${PREFIX}ar
export RANLIB=${PREFIX}ranlib
export LINK=$CXX
LIBPATH=$STAGING_DIR/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/lib/
export LDFLAGS='-Wl,-rpath-link '${LIBPATH}

export GYPFLAGS="-Dv8_use_mips_abi_hardfloat=false -Dv8_can_use_fpu_instructions=false"

# build a standalone v8 version 
# make mips.release library=shared  snapshot=off -j4

# build the version for compiling node
make mips.release library=shared  snapshot=off -j4

6) Make it executable and run it:

chmod +x build.sh && ./build.sh

7) now go on and download node-v0.10.20 source. Uncompress it in a folder with the same name within the work dir

8) inside the created folder make a new script build.sh

export BASEDIR=/home/fiore/Cross/linino/trunk
export STAGING_DIR=${BASEDIR}/staging_dir

V8SOURCE=/home/fiore/Cross/node/v8m-rb

PREFIX=${STAGING_DIR}/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-

LIBPATH=${STAGING_DIR}/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/lib/


export AR=mips-openwrt-linux-uclibc-ar
export CC=${PREFIX}gcc
export CXX=${PREFIX}g++
export AR=${PREFIX}ar
export RANLIB=${PREFIX}ranlib
export LINK=$CXX

export LDFLAGS='-Wl,-rpath-link '${LIBPATH}

export TARGET_PATH=~/Cross/node/opt

export GYPFLAGS="-Dv8_use_mips_abi_hardfloat=false -Dv8_can_use_fpu_instructions=false"
make clean
make distclean

./configure --target=~/Cross/node/opt --without-snapshot --shared-v8 --shared-v8-includes=${V8SOURCE}/include/ --shared-v8-libpath=${V8SOURCE}/out/mips.release/lib.target/
make snapshot=off -j4
make install

9) Make it executable and run it:

chmod +x build.sh && ./build.sh

10) now you have both libv8 and node, and ready to copy them to the yun, but before make sure to strip them, and put them on the sdcard (both are around 8mb)

cp ~/Cross/node/v8/out/mips.release/lib.target/libv8.so ~/Cross/node/opt/lib

mips-openwrt-linux-strip ~/Cross/node/opt/lib/libv8.so
mips-openwrt-linux-strip ~/Cross/node/opt/bin/node

10b) you might probably also need some other libs for example libstdc++, get them from the toolchain:

cp ~/Cross/linino/trunk/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/lib/libstdc++.so.6 ~/Cross/node/opt/lib/

11) Copy the nodejs-yun folder to the Yun

scp -r  ~/Cross/node/opt root@arduino.local:/mnt/sda1

11) Now go on the Yun and make some symlinks from your /mnt/sda1/opt to the system's root

ln -sf /mnt/sda1/opt/bin/node /usr/bin/node
ln -sf /mnt/sda1/opt/bin/npm /usr/bin/npm
ln -sf /mnt/sda1/opt/lib/libv8.so /usr/lib/libv8.so
ln -sf /mnt/sda1/opt/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6

12) Node is now ready, try it!

13) YUN has limited memory you can optimize node for it with the following params:

node --stack_size=1024 --max_old_space_size=20 --max_new_space_size=2048 --max_executable_size=5 --gc_global --gc_interval=100

13) Please note that since you don't have gcc on the Yun any npm module requiring compiling must be cross-compiled on your host machine.

Make sure you have the same version of node and npm installed on your host machine.

We can use again a build script. Create build.sh inside a mips-modules

export BASEDIR=/home/fiore/Cross/linino/trunk
export STAGING_DIR=${BASEDIR}/staging_dir

V8SOURCE=/home/fiore/Cross/node/v8m-rb

PREFIX=${STAGING_DIR}/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-

LIBPATH=${STAGING_DIR}/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/lib/


export AR=mips-openwrt-linux-uclibc-ar
export CC=${PREFIX}gcc
export CXX=${PREFIX}g++
export AR=${PREFIX}ar
export RANLIB=${PREFIX}ranlib
export LINK=$CXX

export LDFLAGS='-Wl,-rpath-link '${LIBPATH}

export TARGET_PATH=~/Cross/node/opt

export GYPFLAGS="-Dv8_use_mips_abi_hardfloat=false -Dv8_can_use_fpu_instructions=false"

export npm_config_arch=mips
# path to the node source that was used to create the cross-compiled version
export npm_config_nodedir=/home/fiore/Cross/node/node-v0.10.20

npm install $1

Now chmod +x build.sh and invoke it with the name of the module you need to build i.e.

./build.sh serialport

Inside the ./node_modules folder, you will find the cross-compiled module and all its dependencies. Just move over everything via scp and you should be set.

Comments !