| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 1 | ========================================= | 
|  | 2 | A guide to Dockerfiles for building LLVM | 
|  | 3 | ========================================= | 
|  | 4 |  | 
|  | 5 | Introduction | 
|  | 6 | ============ | 
|  | 7 | You can find a number of sources to build docker images with LLVM components in | 
|  | 8 | ``llvm/utils/docker``. They can be used by anyone who wants to build the docker | 
|  | 9 | images for their own use, or as a starting point for someone who wants to write | 
|  | 10 | their own Dockerfiles. | 
|  | 11 |  | 
|  | 12 | We currently provide Dockerfiles with ``debian8`` and ``nvidia-cuda`` base images. | 
|  | 13 | We also provide an ``example`` image, which contains placeholders that one would need | 
|  | 14 | to fill out in order to produce Dockerfiles for a new docker image. | 
|  | 15 |  | 
|  | 16 | Why? | 
|  | 17 | ---- | 
|  | 18 | Docker images provide a way to produce binary distributions of | 
|  | 19 | software inside a controlled environment. Having Dockerfiles to builds docker images | 
|  | 20 | inside LLVM repo makes them much more discoverable than putting them into any other | 
|  | 21 | place. | 
|  | 22 |  | 
|  | 23 | Docker basics | 
|  | 24 | ------------- | 
|  | 25 | If you've never heard about Docker before, you might find this section helpful | 
|  | 26 | to get a very basic explanation of it. | 
|  | 27 | `Docker <https://www.docker.com/>`_ is a popular solution for running programs in | 
|  | 28 | an isolated and reproducible environment, especially to maintain releases for | 
|  | 29 | software deployed to large distributed fleets. | 
|  | 30 | It uses linux kernel namespaces and cgroups to provide a lightweight isolation | 
|  | 31 | inside currently running linux kernel. | 
|  | 32 | A single active instance of dockerized environment is called a *docker | 
|  | 33 | container*. | 
|  | 34 | A snapshot of a docker container filesystem is called a *docker image*. | 
|  | 35 | One can start a container from a prebuilt docker image. | 
|  | 36 |  | 
|  | 37 | Docker images are built from a so-called *Dockerfile*, a source file written in | 
|  | 38 | a specialized language that defines instructions to be used when build | 
|  | 39 | the docker image (see `official | 
|  | 40 | documentation <https://docs.docker.com/engine/reference/builder/>`_ for more | 
|  | 41 | details). A minimal Dockerfile typically contains a base image and a number | 
|  | 42 | of RUN commands that have to be executed to build the image. When building a new | 
|  | 43 | image, docker will first download your base image, mount its filesystem as | 
|  | 44 | read-only and then add a writable overlay on top of it to keep track of all | 
|  | 45 | filesystem modifications, performed while building your image. When the build | 
|  | 46 | process is finished, a diff between your image's final filesystem state and the | 
|  | 47 | base image's filesystem is stored in the resulting image. | 
|  | 48 |  | 
|  | 49 | Overview | 
|  | 50 | ======== | 
|  | 51 | The ``llvm/utils/docker`` folder contains Dockerfiles and simple bash scripts to | 
|  | 52 | serve as a basis for anyone who wants to create their own Docker image with | 
|  | 53 | LLVM components, compiled from sources. The sources are checked out from the | 
|  | 54 | upstream svn repository when building the image. | 
|  | 55 |  | 
| Ilya Biryukov | d950201 | 2018-03-26 15:12:30 +0000 | [diff] [blame] | 56 | The resulting image contains only the requested LLVM components and a few extra | 
|  | 57 | packages to make the image minimally useful for C++ development, e.g. libstdc++ | 
|  | 58 | and binutils. | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 59 |  | 
| Ilya Biryukov | d950201 | 2018-03-26 15:12:30 +0000 | [diff] [blame] | 60 | The interface to run the build is ``build_docker_image.sh`` script. It accepts a | 
|  | 61 | list of LLVM repositories to checkout and arguments for CMake invocation. | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 62 |  | 
|  | 63 | If you want to write your own docker image, start with an ``example/`` subfolder. | 
| Ilya Biryukov | d950201 | 2018-03-26 15:12:30 +0000 | [diff] [blame] | 64 | It provides an incomplete Dockerfile with (very few) FIXMEs explaining the steps | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 65 | you need to take in order to make your Dockerfiles functional. | 
|  | 66 |  | 
|  | 67 | Usage | 
|  | 68 | ===== | 
|  | 69 | The ``llvm/utils/build_docker_image.sh`` script provides a rather high degree of | 
|  | 70 | control on how to run the build. It allows you to specify the projects to | 
|  | 71 | checkout from svn and provide a list of CMake arguments to use during when | 
|  | 72 | building LLVM inside docker container. | 
|  | 73 |  | 
|  | 74 | Here's a very simple example of getting a docker image with clang binary, | 
|  | 75 | compiled by the system compiler in the debian8 image: | 
|  | 76 |  | 
|  | 77 | .. code-block:: bash | 
|  | 78 |  | 
|  | 79 | ./llvm/utils/docker/build_docker_image.sh \ | 
|  | 80 | --source debian8 \ | 
|  | 81 | --docker-repository clang-debian8 --docker-tag "staging" \ | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 82 | -p clang -i install-clang -i install-clang-headers \ | 
|  | 83 | -- \ | 
|  | 84 | -DCMAKE_BUILD_TYPE=Release | 
|  | 85 |  | 
| Ilya Biryukov | 7f02a75 | 2017-07-06 12:46:51 +0000 | [diff] [blame] | 86 | Note that a build like that doesn't use a 2-stage build process that | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 87 | you probably want for clang. Running a 2-stage build is a little more intricate, | 
|  | 88 | this command will do that: | 
|  | 89 |  | 
|  | 90 | .. code-block:: bash | 
|  | 91 |  | 
|  | 92 | # Run a 2-stage build. | 
|  | 93 | #   LLVM_TARGETS_TO_BUILD=Native is to reduce stage1 compile time. | 
|  | 94 | #   Options, starting with BOOTSTRAP_* are passed to stage2 cmake invocation. | 
|  | 95 | ./build_docker_image.sh \ | 
|  | 96 | --source debian8 \ | 
|  | 97 | --docker-repository clang-debian8 --docker-tag "staging" \ | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 98 | -p clang -i stage2-install-clang -i stage2-install-clang-headers \ | 
|  | 99 | -- \ | 
|  | 100 | -DLLVM_TARGETS_TO_BUILD=Native -DCMAKE_BUILD_TYPE=Release \ | 
|  | 101 | -DBOOTSTRAP_CMAKE_BUILD_TYPE=Release \ | 
|  | 102 | -DCLANG_ENABLE_BOOTSTRAP=ON -DCLANG_BOOTSTRAP_TARGETS="install-clang;install-clang-headers" | 
|  | 103 |  | 
| Ilya Biryukov | d950201 | 2018-03-26 15:12:30 +0000 | [diff] [blame] | 104 | This will produce a new image ``clang-debian8:staging`` from the latest | 
|  | 105 | upstream revision. | 
|  | 106 | After the image is built you can run bash inside a container based on your image | 
|  | 107 | like this: | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 108 |  | 
|  | 109 | .. code-block:: bash | 
|  | 110 |  | 
|  | 111 | docker run -ti clang-debian8:staging bash | 
|  | 112 |  | 
|  | 113 | Now you can run bash commands as you normally would: | 
|  | 114 |  | 
|  | 115 | .. code-block:: bash | 
|  | 116 |  | 
|  | 117 | root@80f351b51825:/# clang -v | 
|  | 118 | clang version 5.0.0 (trunk 305064) | 
|  | 119 | Target: x86_64-unknown-linux-gnu | 
|  | 120 | Thread model: posix | 
|  | 121 | InstalledDir: /bin | 
|  | 122 | Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8 | 
|  | 123 | Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8.4 | 
|  | 124 | Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9 | 
|  | 125 | Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.2 | 
|  | 126 | Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9 | 
|  | 127 | Candidate multilib: .;@m64 | 
|  | 128 | Selected multilib: .;@m64 | 
|  | 129 |  | 
|  | 130 |  | 
|  | 131 | Which image should I choose? | 
|  | 132 | ============================ | 
|  | 133 | We currently provide two images: debian8-based and nvidia-cuda-based. They | 
|  | 134 | differ in the base image that they use, i.e. they have a different set of | 
|  | 135 | preinstalled binaries. Debian8 is very minimal, nvidia-cuda is larger, but has | 
|  | 136 | preinstalled CUDA libraries and allows to access a GPU, installed on your | 
|  | 137 | machine. | 
|  | 138 |  | 
|  | 139 | If you need a minimal linux distribution with only clang and libstdc++ included, | 
|  | 140 | you should try debian8-based image. | 
|  | 141 |  | 
|  | 142 | If you want to use CUDA libraries and have access to a GPU on your machine, | 
|  | 143 | you should choose nvidia-cuda-based image and use `nvidia-docker | 
|  | 144 | <https://github.com/NVIDIA/nvidia-docker>`_ to run your docker containers. Note | 
|  | 145 | that you don't need nvidia-docker to build the images, but you need it in order | 
|  | 146 | to have an access to GPU from a docker container that is running the built | 
|  | 147 | image. | 
|  | 148 |  | 
|  | 149 | If you have a different use-case, you could create your own image based on | 
|  | 150 | ``example/`` folder. | 
|  | 151 |  | 
|  | 152 | Any docker image can be built and run using only the docker binary, i.e. you can | 
|  | 153 | run debian8 build on Fedora or any other Linux distribution. You don't need to | 
|  | 154 | install CMake, compilers or any other clang dependencies. It is all handled | 
|  | 155 | during the build process inside Docker's isolated environment. | 
|  | 156 |  | 
|  | 157 | Stable build | 
|  | 158 | ============ | 
|  | 159 | If you want a somewhat recent and somewhat stable build, use the | 
|  | 160 | ``branches/google/stable`` branch, i.e. the following command will produce a | 
|  | 161 | debian8-based image using the latest ``google/stable`` sources for you: | 
|  | 162 |  | 
|  | 163 | .. code-block:: bash | 
|  | 164 |  | 
|  | 165 | ./llvm/utils/docker/build_docker_image.sh \ | 
|  | 166 | -s debian8 --d clang-debian8 -t "staging" \ | 
| Ilya Biryukov | af351da | 2017-06-30 09:46:45 +0000 | [diff] [blame] | 167 | --branch branches/google/stable \ | 
|  | 168 | -p clang -i install-clang -i install-clang-headers \ | 
|  | 169 | -- \ | 
|  | 170 | -DCMAKE_BUILD_TYPE=Release | 
|  | 171 |  | 
|  | 172 |  | 
|  | 173 | Minimizing docker image size | 
|  | 174 | ============================ | 
| Ilya Biryukov | d950201 | 2018-03-26 15:12:30 +0000 | [diff] [blame] | 175 | Due to how Docker's filesystem works, all intermediate writes are persisted in | 
|  | 176 | the resulting image, even if they are removed in the following commands. | 
|  | 177 | To minimize the resulting image size we use `multi-stage Docker builds | 
|  | 178 | <https://docs.docker.com/develop/develop-images/multistage-build/>`_. | 
|  | 179 | Internally Docker builds two images. The first image does all the work: installs | 
|  | 180 | build dependencies, checks out LLVM source code, compiles LLVM, etc. | 
|  | 181 | The first image is only used during build and does not have a descriptive name, | 
|  | 182 | i.e. it is only accessible via the hash value after the build is finished. | 
|  | 183 | The second image is our resulting image. It contains only the built binaries | 
|  | 184 | and not any build dependencies. It is also accessible via a descriptive name | 
|  | 185 | (specified by -d and -t flags). |