Node.JS cross-compilation for Socionext development board

I assume that all the following steps will be performed in native / virtual Debian / Ubuntu-based 64-bit Linux environment. In 32-bit Linux-system the Socionext’s toolchain won’t work for sure.

Step #1: First of all, we need to install some specific packages. As long as the target platform is ARM/32-bit we need to get 32-bit related headers that will be directly used at cross-compilation stage:

sudo dpkg --add-architecture i386
sudo apt install build-essential binutils-multiarch 
sudo apt install libc6-dev:i386 libstdc++-7-dev:i386

The whole following work will be done in directory ~/socionext. In particular, the toolchain is supposed to be placed in subdirectory ~/socionext/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf.

I would also highly recommend to install the mentioned packages:

sudo apt install ccache ninja-build

ninja-build - a Makefile-like build system that is also used by NodeJS project;

ccache - compilator cache - really saves a lot of time when you have to recompile the whole project’s source tree several times;

Make sure that you have installed a host GCC - e.g. the GCC compiler for your host. In can be easily checked with the following command:

gcc --version

If everything’s fine you’ll get something like:

gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Otherwise you have to install gcc as well.

Step #2: Let’s download the NodeJS source tree and put it in the ~/socionext directory also. Within all available there versions the 8.15.1 is the most interesting for us at the moment, so after downloading we have to unpack it into ~/socionext/node-v8.15.1.

As soon as the nodejs’s source tree is unpacked we need to build it with our toolchain. Below is a shell-script that has to be launched every time you make changes in project’s building configuration:

export LANG="en_US.UTF-8"

TOOLCHAIN=~/socionext/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf
TOOLCHAIN_BIN=${TOOLCHAIN}/bin
TOOLCHAIN_LIB=${TOOLCHAIN}/lib
TOOLCHAIN_INC=${TOOLCHAIN}/arm-linux-gnueabihf/libc/usr/include/

export PATH=${TOOLCHAIN_BIN}:${PATH}
export ARM_TARGET_LIB=${TOOLCHAIN_LIB}

export NM=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-nm
export AS=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-as
export AR=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-ar
export OBJCOPY=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-objcopy
export CC="ccache ${TOOLCHAIN_BIN}/arm-linux-gnueabihf-gcc -march=armv7ve"
export CXX="ccache ${TOOLCHAIN_BIN}/arm-linux-gnueabihf-g++ -march=armv7ve"

export LINK=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-g++
export LD=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-g++
export CCLD=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-gcc
export RANLIB=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-ranlib
export STRIP=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-strip
export OBJDUMP=${TOOLCHAIN_BIN}/arm-linux-gnueabihf-objdump

export CC_host="ccache gcc -m32"
export CXX_host="ccache g++ -m32" 

export ARCH=arm
export CFLAGS="-I${TOOLCHAIN_INC} -O2"
export CXXFLAGS="-I${TOOLCHAIN_INC} -O2"
export LDFLAGS="-ldl -Wl,-dynamic-linker,/lib/ld-linux.so.3"

./configure --without-snapshot --cross-compiling --ninja  --dest-os=linux 
            --dest-cpu=arm --with-arm-float-abi=hard --with-arm-fpu=neon

# In case if you'll need full internationalization support
#./configure --without-snapshot --cross-compiling --ninja  --dest-os=linux 
#            --dest-cpu=arm --with-arm-float-abi=hard --with-arm-fpu=neon 
#            --with-intl=full-icu  --download=all

Let’s save this shell-script as cross-config.sh in the project’s root directory. After the script is saved let’s launch it:

chmod +x cross-config.sh
./cross-config.sh

If everything was fine you’ll get something like:

creating icu_config.gypi
* Using ICU in deps/icu-small
creating icu_config.gypi
{ 'target_defaults': { 'cflags': [],
                       'default_configuration': 'Release',
                       'defines': [],
                       'include_dirs': [],
                       'libraries': []},
  'variables': { 'arm_float_abi': 'hard',
                 'arm_fpu': 'neon',
                 'arm_thumb': 0,
                 'arm_version': '7',
                 'asan': 0,
                 'coverage': 'false',
                 'debug_devtools': 'node',
                 'debug_http2': 'false',
                 'debug_nghttp2': 'false',
                 'force_dynamic_crt': 0,
                 'gas_version': 0,
                 'host_arch': 'ia32',
                 'icu_data_file': 'icudt60l.dat',
                 'icu_data_in': '../../deps/icu-small/source/data/in/icudt60l.dat',
                 'icu_endianness': 'l',
                 'icu_gyp_path': 'tools/icu/icu-generic.gyp',
                 'icu_locales': 'en,root',
                 'icu_path': 'deps/icu-small',
                 'icu_small': 'true',
                 'icu_ver_major': '60',
                 'llvm_version': 0,
                 'node_byteorder': 'little',
                 'node_enable_d8': 'false',
                 'node_enable_v8_vtunejit': 'false',
                 'node_install_npm': 'true',
                 'node_module_version': 57,
                 'node_no_browser_globals': 'false',
                 'node_prefix': '/usr/local',
                 'node_release_urlbase': '',
                 'node_shared': 'false',
                 'node_shared_cares': 'false',
                 'node_shared_http_parser': 'false',
                 'node_shared_libuv': 'false',
                 'node_shared_nghttp2': 'false',
                 'node_shared_openssl': 'false',
                 'node_shared_zlib': 'false',
                 'node_tag': '',
                 'node_target_type': 'executable',
                 'node_use_bundled_v8': 'true',
                 'node_use_dtrace': 'false',
                 'node_use_etw': 'false',
                 'node_use_lttng': 'false',
                 'node_use_openssl': 'true',
                 'node_use_perfctr': 'false',
                 'node_use_v8_platform': 'true',
                 'node_without_node_options': 'false',
                 'openssl_fips': '',
                 'openssl_no_asm': 0,
                 'shlib_suffix': 'so.57',
                 'target_arch': 'arm',
                 'uv_parent_path': '/deps/uv/',
                 'uv_use_dtrace': 'false',
                 'v8_enable_gdbjit': 0,
                 'v8_enable_i18n_support': 1,
                 'v8_enable_inspector': 1,
                 'v8_no_strict_aliasing': 1,
                 'v8_optimized_debug': 0,
                 'v8_promise_internal_field_count': 1,
                 'v8_random_seed': 0,
                 'v8_trace_maps': 0,
                 'v8_use_snapshot': 'false',
                 'want_separate_host_toolset': 0}}
creating config.gypi
creating config.mk

It’s a current detailed nodejs configuration that can be launched to build right now.

 

Step #3

: I would recommend the following script or its derivatives for building the project up as it also minimizes strange errors. Everytime before launch the building process you need to remove all earlier made binaries. Otherwise the nodejs’s behaviour can be really strange. The building script itself is much shorter than the config script:

make clean && rm -rf out
ninja -C out/Release

Let’s save it as cross-build.sh and launch like we did before:

chmod +x cross-build.sh
./cross-build.sh

The cross-compilation will begin as soon as you launch this script. It will take significant amount of time depending on your PC’s hardware configuration. It takes 12-15 minutes to build nodejs from scratch on 8-core Intel Core i7-6700 with 16 GB RAM and SSD.

As soon as the compilation finishes we need to gather all required files in one place. It can be done with provided by NodeJS-developers Python-script:

python tools/install.py install ./ 8.15-release

After executing the script above you should see the following directory list in 8.15-release subdirectory:

alexey@dell:~/socionext/node-v8.15.1$ ls -l 8.15-release/
total 16
drwxrwxr-x 2 alexey alexey 4096 mar  6 19:16 bin
drwxrwxr-x 3 alexey alexey 4096 mar  6 19:16 include
drwxrwxr-x 3 alexey alexey 4096 mar  6 19:16 lib
drwxrwxr-x 5 alexey alexey 4096 mar  6 19:16 share

 

Step #4: The whole 8.15-release directory has to be copied onto microSD-card now. Right after copying put the SD-card into dev-board as was shown in previous tutorial. The SD-card will be automatically mounted on the path /run/SD/mmcblk0p1 . Let’s check our distribution:

# We're going to the node.js release root subdirectory
cd /run/SD/mmcblk0p1/8.15-release
# We're copying the whole release into system path
cp -R * /usr
# Going back to the system root top-level directory
cd /
# Checking the node.js version
node -v

 

© "Ctrl-V" 2012 - 2019