A guide to Dockerfiles for building LLVM

Introduction

You can find a number of sources to build docker images with LLVM components inllvm/utils/docker. They can be used by anyone who wants to build the dockerimages for their own use, or as a starting point for someone who wants to writetheir own Dockerfiles.

We currently provide Dockerfiles with debian8 and nvidia-cuda base images.We also provide an example image, which contains placeholders that one would needto fill out in order to produce Dockerfiles for a new docker image.

Why?

Docker images provide a way to produce binary distributions ofsoftware inside a controlled environment. Having Dockerfiles to builds docker imagesinside LLVM repo makes them much more discoverable than putting them into any otherplace.

Docker basics

If you’ve never heard about Docker before, you might find this section helpfulto get a very basic explanation of it.Docker is a popular solution for running programs inan isolated and reproducible environment, especially to maintain releases forsoftware deployed to large distributed fleets.It uses linux kernel namespaces and cgroups to provide a lightweight isolationinside currently running linux kernel.A single active instance of dockerized environment is called a dockercontainer.A snapshot of a docker container filesystem is called a docker image.One can start a container from a prebuilt docker image.

Docker images are built from a so-called Dockerfile, a source file written ina specialized language that defines instructions to be used when buildthe docker image (see officialdocumentation for moredetails). A minimal Dockerfile typically contains a base image and a numberof RUN commands that have to be executed to build the image. When building a newimage, docker will first download your base image, mount its filesystem asread-only and then add a writable overlay on top of it to keep track of allfilesystem modifications, performed while building your image. When the buildprocess is finished, a diff between your image’s final filesystem state and thebase image’s filesystem is stored in the resulting image.

Overview

The llvm/utils/docker folder contains Dockerfiles and simple bash scripts toserve as a basis for anyone who wants to create their own Docker image withLLVM components, compiled from sources. The sources are checked out from theupstream svn repository when building the image.

The resulting image contains only the requested LLVM components and a few extrapackages to make the image minimally useful for C++ development, e.g. libstdc++and binutils.

The interface to run the build is build_docker_image.sh script. It accepts alist of LLVM repositories to checkout and arguments for CMake invocation.

If you want to write your own docker image, start with an example/ subfolder.It provides an incomplete Dockerfile with (very few) FIXMEs explaining the stepsyou need to take in order to make your Dockerfiles functional.

Usage

The llvm/utils/build_docker_image.sh script provides a rather high degree ofcontrol on how to run the build. It allows you to specify the projects tocheckout from svn and provide a list of CMake arguments to use during whenbuilding LLVM inside docker container.

Here’s a very simple example of getting a docker image with clang binary,compiled by the system compiler in the debian8 image:

  1. ./llvm/utils/docker/build_docker_image.sh \
  2. --source debian8 \
  3. --docker-repository clang-debian8 --docker-tag "staging" \
  4. -p clang -i install-clang -i install-clang-resource-headers \
  5. -- \
  6. -DCMAKE_BUILD_TYPE=Release

Note that a build like that doesn’t use a 2-stage build process thatyou probably want for clang. Running a 2-stage build is a little more intricate,this command will do that:

  1. # Run a 2-stage build.
  2. # LLVM_TARGETS_TO_BUILD=Native is to reduce stage1 compile time.
  3. # Options, starting with BOOTSTRAP_* are passed to stage2 cmake invocation.
  4. ./build_docker_image.sh \
  5. --source debian8 \
  6. --docker-repository clang-debian8 --docker-tag "staging" \
  7. -p clang -i stage2-install-clang -i stage2-install-clang-resource-headers \
  8. -- \
  9. -DLLVM_TARGETS_TO_BUILD=Native -DCMAKE_BUILD_TYPE=Release \
  10. -DBOOTSTRAP_CMAKE_BUILD_TYPE=Release \
  11. -DCLANG_ENABLE_BOOTSTRAP=ON -DCLANG_BOOTSTRAP_TARGETS="install-clang;install-clang-resource-headers"

This will produce a new image clang-debian8:staging from the latestupstream revision.After the image is built you can run bash inside a container based on your imagelike this:

  1. docker run -ti clang-debian8:staging bash

Now you can run bash commands as you normally would:

  1. root@80f351b51825:/# clang -v
  2. clang version 5.0.0 (trunk 305064)
  3. Target: x86_64-unknown-linux-gnu
  4. Thread model: posix
  5. InstalledDir: /bin
  6. Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8
  7. Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8.4
  8. Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
  9. Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.2
  10. Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
  11. Candidate multilib: .;@m64
  12. Selected multilib: .;@m64

Which image should I choose?

We currently provide two images: debian8-based and nvidia-cuda-based. Theydiffer in the base image that they use, i.e. they have a different set ofpreinstalled binaries. Debian8 is very minimal, nvidia-cuda is larger, but haspreinstalled CUDA libraries and allows to access a GPU, installed on yourmachine.

If you need a minimal linux distribution with only clang and libstdc++ included,you should try debian8-based image.

If you want to use CUDA libraries and have access to a GPU on your machine,you should choose nvidia-cuda-based image and use nvidia-docker to run your docker containers. Notethat you don’t need nvidia-docker to build the images, but you need it in orderto have an access to GPU from a docker container that is running the builtimage.

If you have a different use-case, you could create your own image based onexample/ folder.

Any docker image can be built and run using only the docker binary, i.e. you canrun debian8 build on Fedora or any other Linux distribution. You don’t need toinstall CMake, compilers or any other clang dependencies. It is all handledduring the build process inside Docker’s isolated environment.

Stable build

If you want a somewhat recent and somewhat stable build, use thebranches/google/stable branch, i.e. the following command will produce adebian8-based image using the latest google/stable sources for you:

  1. ./llvm/utils/docker/build_docker_image.sh \
  2. -s debian8 --d clang-debian8 -t "staging" \
  3. --branch branches/google/stable \
  4. -p clang -i install-clang -i install-clang-resource-headers \
  5. -- \
  6. -DCMAKE_BUILD_TYPE=Release

Minimizing docker image size

Due to how Docker’s filesystem works, all intermediate writes are persisted inthe resulting image, even if they are removed in the following commands.To minimize the resulting image size we use multi-stage Docker builds.Internally Docker builds two images. The first image does all the work: installsbuild dependencies, checks out LLVM source code, compiles LLVM, etc.The first image is only used during build and does not have a descriptive name,i.e. it is only accessible via the hash value after the build is finished.The second image is our resulting image. It contains only the built binariesand not any build dependencies. It is also accessible via a descriptive name(specified by -d and -t flags).