Using Docker to host ARM toolchain to cross-compile C code

By: ; Date: 2017-01-19 16:27

Tags: Docker » Cross Compilation » ARM Compilation » Emdebian

I'm starting up a project that will see me doing custom software development for an ARM single-board-computer running Linux. The recommendation isn't to do compiles ON the board, but instead to cross compile from a Linux workstation (Debian). But, I use a Mac laptop, as do most software engineers these days. While I could run VirtualBox to set up a Debian cross-compiling environment, Docker is much lighter weight. While Docker was originally targeted for deploying server applications, it is useful for packaging anything. In this case there's a ready-made set of Docker containers for cross-compilation including for ARM CPU's.

My likely ARM hardware vendor conveniently gave excellent instructions for setting up a Debian workstation for cross-compiling: Those instructions rely on cross-compilation tools created by and while the Emdebian project is essentially dead, they seem to still be maintaining the cross-compilation tools. Even that's not 100% true (it seems) because the Emdebian website refers you over to for instructions for the latest Debian (Jessie). But then those instructions tell you to add the Emdebian repository to your APT sources. Fortunately it's not entirely important for this tutorial to understand the status of the Emdebian project. For whatever reason we are to still use the Emdebian repository to access the compilation toolchain.

Simple Emdebian cross-compiling Docker container

My first stab at a Docker image was to transliterate the instructions on into a simple Dockerfile. But as we'll see in a minute there's a simpler method.

FROM debian:jessie

RUN apt-get update && apt-get install -y \
    apt-utils \
    curl \
    build-essential \
    automake \
    autogen \
    bash \
    build-essential \
    bc \
    bzip2 \
    ca-certificates \
    curl \
    file \
    git \
    gzip \
    make \
    ncurses-dev \
    pkg-config \
    libtool \
    python \
    rsync \
    sed \
    bison \
    flex \
    tar \
    vim \
    wget \
    runit \

RUN echo "deb jessie main" > /etc/apt/sources.list.d/emdebian.list
RUN curl | apt-key add -
RUN dpkg --add-architecture armel
RUN apt-get update && apt-get install -y crossbuild-essential-armel

# The cross-compiling emulator
RUN apt-get update && apt-get install -y \
    qemu-user \

Create an empty directory and save that as Dockerfile. This Dockerfile brings in a lot of useful command-line tools that developers normally use.

With this you can run.

docker build --tag emdebian-for-technologic .
docker run -it --volume `pwd`:/workdir emdebian-for-technologic bash

The first command builds the Dockerfile, giving the image name emdebian-for-technologic. The second gives you a running shell inside the container. Use ls to look in /usr/bin and you'll see commands with names like arm-linux-gnueabi-gcc that are the cross-compilation toolchain.

Then you can create a file named hello.c containing:

#include <stdio.h>
int main(){
    printf("Hello World\n");

Then compile and run it as so:

root@c8007516bb30:/workdir# arm-linux-gnueabi-gcc hello.c -o hello
root@c8007516bb30:/workdir# file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/, for GNU/Linux 2.6.32, BuildID[sha1]=007ea7c5826104168af839653c3075b474a4d084, not stripped
root@c8007516bb30:/workdir# ./hello
Hello World

We've proved that GCC produced for us an ARM binary for ARMv5. The last command works because we installed qemu-user-static and qemu-user. The qemu tools let you run binaries for other architectures, like ARM, on your regular x86 workstation.

Dockcross - simplifying cross compilation for a wide range of platforms

While that's useful and straight-forward, I promised there was a simpler method. The Dockcross project - - makes cross-compilation using a Docker container simple. They provide Docker images for a long list of CPU architectures, and a simple way to use their Docker images from a regular command-line.

The first step is to install Docker on your laptop - presumably you're running either Mac OS X and need to install Docker for Mac, or you're using Windows and need to install Docker for Windows. Both are the modern currently recommended way to run Docker on a non-Linux workstation.

The next step is to set up Dockcross for the given cross-compilation target. Unfortunately it's not clear from the EmbeddedARM website whether to use ARMv5 or what. By reading the Dockerfiles in the Dockcross project I see that the armel architecture corresponds to ARMv5. Therefore I ran this:

docker run --rm dockcross/linux-armv5 >dockcross-linux-armv5
chmod +x dockcross-linux-armv5
mv dockcross-linux-armv5 ~/bin

I can then compile code like so:

dockcross-linux-armv5 bash -c '$CC hello.c -o hello'

And run it as so:

$ file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped
$ file hello.c
hello.c: ASCII c program text
$ dockcross-linux-armv5 ./hello
Hello World

Since the hello binary is compiled for ARM, it shouldn't work. But the Dockcross container includes qemu-user-static allowing the binary to run.

You can also get a command-line shell in the container with this command:

dockcross-linux-armv5 bash
« The MEADS missile defense system. Will Romania be part of it? Why did Christopher Eccleston leave after just one season? »
2016 Election Acer C720 Android Apple Hardware History Apple iPhone Hardware April 1st ARM Compilation Authoritarianism Big Brother Botnets Cassette Tapes Cellphones Christopher Eccleston Chrome Apps Chromebook Chromebooks ChromeOS CIA CitiCards Civil Liberties Clinton Cluster Computing Computer Hardware Computer Repair Cross Compilation Crouton Cybermen Daleks Darth Vader Data backup Data Storage David Tenant DIY Repair Docker Doctor Who Drobo DVD Emdebian ESP8266 Eurovision Fake News FireFly Fraud Freedom of Speech Gallifrey git Google Google Chrome Google Gnome Great Britain Home Automation HTTPS Internet Internet of Things Internet Privacy iPad iPhone iPhone hacking Iron Man Iternet of Things John Simms Lets Encrypt Linux Single Board Computers Mac OS MEADS Anti-Missile Mercurial Michele Gomez Military Hardware Missy Mobile Applications Mondas Monty Python MQTT Music Player Music Streaming MySQL NanoPi Node Web Development Online Fraud Open Media Vault Open Source Software OpenVPN Personal Flight Peter Capaldi Plex Media Server Political Protest Power Control Privacy Public Violence Raspberry Pi Raspberry Pi 3 Raspberry Pi Zero Recycling Retro-Technology Right to Repair Rocket Ships Russia Season 1 Season 10 Season 11 Security Security Cameras Silence Simsimi Skype Social Media Warfare Software Development Space Flight Space Ship Reuse Space Ships SpaceX SQLite3 SSD Drives SSD upgrade SSL Terrorism The Cybermen The Daleks The Master Trump Trump Administration Ubuntu Virtual Private Networks VOIP Web Developer Resources Weeping Angels WhatsApp