Towards a docker-based build of C/C++ applications
Note: Based on this post I have published buildock on GitHub.
Many C/C++ programmers and project managers know the pain of creating a reproducible build environment for all developers: Works for me is a common meme not without a reason.
My approach is to dockerize not neccessarily the application itself but the build system, encapsulating both the specific compiler version and the system around it plus all required system-level libraries in a Docker image.
Take the obligatory Hello World in C++:
// main.cpp
#include <iostream>
using namespace std;
int main() {
cout << "Hello, World!" << endl;
return 0;
}
and the corresponding Makefile
:
all:
g++ -o helloworld main.cpp
How can we compile this simple project without installing a compiler and GNU make on the local computer (no cheating by using build servers allowed)?
Actually it’s rather simple:
docker run --user $(id -u):$(id -g) -v $PWD:/app -it ulikoehler/ubuntu-gcc-make make
Breaking it down:
docker run
: Create a new docker container and run a command in it--user $(id -u):$(id -g)
: This makes the docker container run with the current user’s ID and the current user’s group - both for preventing the compiler to create output files asroot
and to safeguard against some IT security risks. Also seeĀ How to run docker container as current user & group-v $PWD:/app
: Mount the current directory ($PWD
) on/app
in the container. Since the Dockerfile used to build the container contains theWORKDIR /app
directive, whatever command we run in the container will by default be executed in the/app
directory - and therefore in the current local directory on the host.-it
runs the container in interactive mode, i.e. keypressed are passed down to the command you are running. Also, this means that our command will only finish when the container has finished executing.ulikoehler/ubuntu-gcc-make
: This is the image we’re using for that example. It’s nothing more than anubuntu:18.04
base image withbuild-essentials
andmake
installed andWORKDIR
set to/app
make
: This is the command we’ll run in the container. You can use any command here, even no command is possible (in which case the container’s default command will be used - in case ofulikoehler/ubuntu-gcc-make
that isCMD [ "/usr/bin/make" ]
)
Here’s the complete Dockerfile
used to generate ulikoehler/ubuntu-gcc-make
:
FROM ubuntu:18.04
RUN apt update && apt -y install build-essential make && rm -rf /var/lib/apt/lists/*
WORKDIR /app
CMD [ "/usr/bin/make" ]