Skip to content

Cross Compiling for Ubuntu 20.04 armhf with V8 8.x

Günter Obiltschnig edited this page Dec 10, 2022 · 4 revisions

This article describes how to cross-compile macchina.io (with V8 version 8.x) for an 32-bit ARM-based machine (armhf architecture) running Ubuntu 20.04.

Prerequisites

A Ubuntu 20.04 (bionic) host system (VM) with the following packages installed:

  • git
  • build-essential
  • libssl-dev
  • python (3.x)
  • crossbuild-essential-armhf

Preparing the Host System

Cross-compiling V8 for a 32-bit ARM target needs a 32-bit toolchain on the host too. So in addition to installing the cross-compiler for ARM, we also need to install support for building and running 32-bit Intel (i386) programs, as during the V8 build process, code generators are built that must run with the same bit width as the target system.

First, we prepare the package manager to add i386 packages.

$ sudo dpkg --add-architecture i386

Then we add the i386 packages.

$ sudo apt install -y binutils-multiarch libc6-dev:i386 libstdc++-9-dev:i386 gcc-9-multilib g++-9-multilib 

Then we need to prepare the package manager to install packages required for cross-compiling.
For example, the OpenSSL headers and libraries must be available for the `armhf` architecture.

$ sudo dpkg --add-architecture armhf


The Ubuntu packages for ARM are not available from the default Ubuntu package server, so we have
to add a new package source. Create a the file `/etc/apt/sources.list.d/arm-cross-compile-sources.list`
and add the following content:

deb [arch=armhf] http://ports.ubuntu.com/ focal main restricted deb [arch=armhf] http://ports.ubuntu.com/ focal-updates main restricted deb [arch=armhf] http://ports.ubuntu.com/ focal universe deb [arch=armhf] http://ports.ubuntu.com/ focal-updates universe deb [arch=armhf] http://ports.ubuntu.com/ focal multiverse deb [arch=armhf] http://ports.ubuntu.com/ focal-updates multiverse deb [arch=armhf] http://ports.ubuntu.com/ focal-backports main restricted universe multiverse


This will tell the package manager to look for packages for the specified architecture
(`armhf`) on `http://ports.ubuntu.com`.

Next, edit `/etc/apt/sources.list` and change the entries so that they are only
used for the `amd64` and `i386` architectures. This is done by inserting `[arch=amd64,i386]` after
every `deb` statement, e.g.:

newer versions of the distribution.

deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu bionic main restricted

deb-src http://archive.ubuntu.com/ubuntu bionic main restricted

Major bug fix updates produced after the final release of the

distribution.

deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu bionic-updates main restricted

deb-src http://archive.ubuntu.com/ubuntu bionic-updates main restricted

...


This change will prevent errors when updating the package index, since
`archive.ubuntu.com` only holds the packages for Intel architectures.

Next, update the package index:

$ sudo apt-get update


## Install the essential packages for building the host tools:

$ sudo apt-get install -y build-essential libssl-dev python python-is-python3


## Install the packages required for cross-compiling:

$ sudo apt-get install -y crossbuild-essential-armhf $ sudo apt-get install -y libssl-dev:armhf


# Building macchina.io

## Get macchina.io Sources from GitHub

$ git clone https://github.com/macchina-io/macchina.io.git


## Build the Host Tools

This will build the tools (e.g., *BundleCreator*) required for building macchina.io.

$ cd macchina.io $ make -s -j8 hosttools


This takes a couple of minutes.
Note: Depending on the number of CPU cores you have on your build machine, adjust the `-j8` argument accordingly.

## Build for Target

In order to build for the target, a build configuration file must be used.
You can find various build configuration files in `platform/build/config`.
Create a new build configuration file `X-Ubuntu-Focal-RPi` with the
following content:

X-Ubuntu-Focal--RPi

Make settings for Raspberry Pi (2 or newer) Ubuntu 20.04

General Settings

LINKMODE ?= SHARED TOOL ?= arm-linux-gnueabihf POCO_TARGET_OSNAME = Linux POCO_TARGET_OSARCH ?= armv7l ARCHFLAGS ?= -march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4

Define Tools

CC = $(TOOL)-gcc CXX = $(TOOL)-g++ LINK = $(CXX) LIB = $(TOOL)-ar -cr RANLIB = $(TOOL)-ranlib SHLIB = $(CXX) -shared -Wl,-soname,$(notdir $@) -o $@ SHLIBLN = $(POCO_BASE)/build/script/shlibln STRIP = $(TOOL)-strip DEP = $(POCO_BASE)/build/script/makedepend.gcc SHELL = sh RM = rm -rf CP = cp MKDIR = mkdir -p

Extension for Shared Libraries

SHAREDLIBEXT = .so.$(target_version) SHAREDLIBLINKEXT = .so

Compiler and Linker Flags

CFLAGS = -std=c99 $(ARCHFLAGS) CFLAGS32 = CFLAGS64 = CXXFLAGS = -std=gnu++14 -Wall -Wno-sign-compare $(ARCHFLAGS) CXXFLAGS32 = CXXFLAGS64 = LINKFLAGS = LINKFLAGS32 = LINKFLAGS64 = STATICOPT_CC = STATICOPT_CXX = STATICOPT_LINK = -static SHAREDOPT_CC = -fPIC SHAREDOPT_CXX = -fPIC SHAREDOPT_LINK = -Wl,-rpath,$(LIBPATH) DEBUGOPT_CC = -g -D_DEBUG DEBUGOPT_CXX = -g -D_DEBUG DEBUGOPT_LINK = -g RELEASEOPT_CC = -O2 -DNDEBUG RELEASEOPT_CXX = -O2 -DNDEBUG RELEASEOPT_LINK = -O2

System Specific Flags

SYSFLAGS = -D_XOPEN_SOURCE=600 -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DPOCO_HAVE_FD_EPOLL
-DPOCO_HAVE_ADDRINFO -DPOCO_HAVE_LIBRESOLV

System Specific Libraries

SYSLIBS = -lpthread -ldl -lrt


You may need to change the `ARCHFLAGS` setting to match your target device.
To find out the CPU features on the target device, run:

$ cat /proc/cpuinfo


processor : 0 model name : ARMv7 Processor rev 0 (v7l) BogoMIPS : 10.00 Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x3 CPU part : 0xc09 CPU revision : 0


Under `Features` you should see the available CPU features, specifically floating-point
support (like `neon`, `vfpv3` or `vfpv4`). If you build with CPU features that are
not available on the target machine (e.g., `vfpv4` on a Cortex-A8), the resulting
executable will abort with a `SIGILL` (illegal instruction). 

The `POCO_CONFIG` environment (or Makefile) variable should contain the name
of the build configuration to use. Therefore, we run:

$ POCO_CONFIG=X-Ubuntu-Focal-RPi make -s -j8 DEFAULT_TARGET=shared_release


to build macchina.io for the target. The `DEFAULT_TARGET=shared_release` argument
instructs the build system to build the release executables only. If omitted,
the build system would build both debug and release executables.

Depending on build machine performance, this takes 20-30 minutes.

## Create Tarball for Transfer to Target

To build a directory structure and tarball that can be easily transferred to the
target device (e.g., via `scp`), use the `install_runtime` make target:

$ POCO_CONFIG=X-Ubuntu-Focal-RPi make -s install_runtime INSTALLDIR=/home/admin/macchina_runtime


This will create the following directory structure:

macchina_runtime/ lib/ bundles/ bin/ etc/


Then, pack the `macchina_runtime` directory into a tarball:

$ tar cfz macchina_runtime.tgz /home/admin/macchina_runtime


# Running macchina.io on the Target

Copy the tarball to the target (e.g., using `scp`) and expand it with:

$ tar xfz macchina_runtime.tgz


Before starting macchina.io, you have to set the `LD_LIBRARY_PATH` environment variable, so that the macchina.io shared libraries (both in the `lib` directory and in the `codeCache`) will be found.

$ export LD_LIBRARY_PATH=/path/to/macchina_runtime/lib:/path/to/macchina_runtime/bin/codeCache


You should also create the `codeCache` directory before you start macchina.io, so that the dynamic linker will find it. Otherwise, the first start of macchina.io may fail.

$ mkdir /path/to/macchina_runtime/bin/codeCache


Then you can start macchina.io:

$ /path/to/macchina_runtime/bin/macchina --config=/path/to/macchina_runtime/etc/macchina.properties