Compile code with Docker

Every time I need to compile some code which I downloaded on the Internet, I have to spend a lot of time installing tools and libraries. Sometimes I need to cross-compile code or patch a library, and I need to configure some local environment which occupies space on my disk, but I can't throw away because I might need it again later.

What if I could easily and reliabily create the environment when I need?

Docker represents a versatile tool which can help to simplify and eliminate tedious operations such as preparing an environment for compiling code. This principle can be extended to any build process, and actually there are already companies such as CircleCI, which have adopted Docker for providing CI/CD solutions.

Personally I find Docker extremely helpful for creating a build environment. I don't need to install tools and libraries on my local computer or on a virtual machine. I can build an environment for each library or application I want to build, I can throw it away and then recreate it everytime I need. I can have multiple versions of the same tools, but in different containers, so I don't need to worry about conflicts. I can commit my Dockerfile into some git repository, I can change computer, checkout my code and still be able to build, because I just need Docker and the Dockerfile. No more "it works for me" excuses :)

Pull base image

There are many images which we can use to create our build environment. We can choose among Ubuntu, Debian, Fedora, Centos, and others which are available on Docker Hub. Let's assume we choose Ubuntu, we can pull any version we want just passing a tag:

docker pull ubuntu:latest
docker pull ubuntu:16.04

Create Dockerfile

We want to create our build environment using Ubuntu as operating system. We can do that creating a Dockerfile where we declare the commands required to install all the tools we need, for example the GNU C compiler:

mkdir build-c-image

cat <<EOF >build-c-image/Dockerfile
FROM ubuntu:16.04
RUN apt-get update -y && apt-get install -y gcc
EOF

Build custom image

We can now create a new image using our Dockerfile:

docker build -t build-c build-c-image

Compile and execute code

We can easily compile and execute a simple C program:

mkdir -p project/src project/bin

cat <<EOF >project/src/main.c
#include <stdio.h>
int main(int argv, char ** argc) {
    printf("Hello Docker!\n");
}
EOF

docker run -it -v $(pwd)/project:/project build-c gcc -o /project/bin/main /project/src/main.c

docker run -it -v $(pwd)/project:/project build-c /project/bin/main

Cross-compile code

We can install cross compilation tools like Mingw-w64 and compile code for Windows:

mkdir build-mingw-w64-image

cat <<EOF >build-mingw-w64-image/Dockerfile
FROM ubuntu:16.04
RUN apt-get update -y && apt-get -y install mingw-w64
EOF

docker build -t build-mingw-w64 build-mingw-w64-image

mkdir -p project/src project/bin

cat <<EOF >project/src/main.c
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MessageBox(NULL, "Hello World!", "My app", MB_OK);
}
EOF

docker run -it -v $(pwd)/project:/project build-mingw-w64 /usr/bin/i686-w64-mingw32-gcc -o /project/bin/main.exe -luser32 /project/src/main.c

Customize a library

We can compile a customized version of a library like ffmpeg:

mkdir build-autotools-image

cat <<EOF >build-autotools-image/Dockerfile
FROM ubuntu:16.04
RUN apt-get update -y && apt-get -y install git make gcc autoconf nasm yasm pkg-config
EOF

docker build -t build-autotools build-autotools-image

mkdir output

docker run -it --rm -v $(pwd)/output:/output build-autotools git clone https://github.com/FFmpeg/FFmpeg.git /output/ffmpeg
docker run -it --rm -v $(pwd)/output:/output build-autotools bash -c "cd /output/ffmpeg && ./configure --enable-gpl --disable-ffserver && make"