1#!/bin/bash
2#===- llvm/utils/docker/build_docker_image.sh ----------------------------===//
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7#
8#===----------------------------------------------------------------------===//
9set -e
10
11IMAGE_SOURCE=""
12DOCKER_REPOSITORY=""
13DOCKER_TAG=""
14BUILDSCRIPT_ARGS=""
15CHECKOUT_ARGS=""
16CMAKE_ENABLED_PROJECTS=""
17
18function show_usage() {
19  cat << EOF
20Usage: build_docker_image.sh [options] [-- [cmake_args]...]
21
22Available options:
23  General:
24    -h|--help               show this help message
25  Docker-specific:
26    -s|--source             image source dir (i.e. debian8, nvidia-cuda, etc)
27    -d|--docker-repository  docker repository for the image
28    -t|--docker-tag         docker tag for the image
29  Checkout arguments:
30    -b|--branch         svn branch to checkout, i.e. 'trunk',
31                        'branches/release_40'
32                        (default: 'trunk')
33    -r|--revision       svn revision to checkout
34    -c|--cherrypick     revision to cherry-pick. Can be specified multiple times.
35                        Cherry-picks are performed in the sorted order using the
36                        following command:
37                        'svn patch <(svn diff -c \$rev)'.
38    -p|--llvm-project   name of an svn project to checkout. Will also add the
39                        project to a list LLVM_ENABLE_PROJECTS, passed to CMake.
40                        For clang, please use 'clang', not 'cfe'.
41                        Project 'llvm' is always included and ignored, if
42                        specified.
43                        Can be specified multiple times.
44    -c|--checksums      name of a file, containing checksums of llvm checkout.
45                        Script will fail if checksums of the checkout do not
46                        match.
47  Build-specific:
48    -i|--install-target name of a cmake install target to build and include in
49                        the resulting archive. Can be specified multiple times.
50
51Required options: --source and --docker-repository, at least one
52  --install-target.
53
54All options after '--' are passed to CMake invocation.
55
56For example, running:
57$ build_docker_image.sh -s debian8 -d mydocker/debian8-clang -t latest \ 
58  -p clang -i install-clang -i install-clang-resource-headers
59will produce two docker images:
60    mydocker/debian8-clang-build:latest - an intermediate image used to compile
61      clang.
62    mydocker/clang-debian8:latest       - a small image with preinstalled clang.
63Please note that this example produces a not very useful installation, since it
64doesn't override CMake defaults, which produces a Debug and non-boostrapped
65version of clang.
66
67To get a 2-stage clang build, you could use this command:
68$ ./build_docker_image.sh -s debian8 -d mydocker/clang-debian8 -t "latest" \ 
69    -p clang -i stage2-install-clang -i stage2-install-clang-resource-headers \ 
70    -- \ 
71    -DLLVM_TARGETS_TO_BUILD=Native -DCMAKE_BUILD_TYPE=Release \ 
72    -DBOOTSTRAP_CMAKE_BUILD_TYPE=Release \ 
73    -DCLANG_ENABLE_BOOTSTRAP=ON \ 
74    -DCLANG_BOOTSTRAP_TARGETS="install-clang;install-clang-resource-headers"
75EOF
76}
77
78CHECKSUMS_FILE=""
79SEEN_INSTALL_TARGET=0
80SEEN_CMAKE_ARGS=0
81while [[ $# -gt 0 ]]; do
82  case "$1" in
83    -h|--help)
84      show_usage
85      exit 0
86      ;;
87    -s|--source)
88      shift
89      IMAGE_SOURCE="$1"
90      shift
91      ;;
92    -d|--docker-repository)
93      shift
94      DOCKER_REPOSITORY="$1"
95      shift
96      ;;
97    -t|--docker-tag)
98      shift
99      DOCKER_TAG="$1"
100      shift
101      ;;
102    -r|--revision|-c|-cherrypick|-b|--branch)
103      CHECKOUT_ARGS="$CHECKOUT_ARGS $1 $2"
104      shift 2
105      ;;
106    -i|--install-target)
107      SEEN_INSTALL_TARGET=1
108      BUILDSCRIPT_ARGS="$BUILDSCRIPT_ARGS $1 $2"
109      shift 2
110      ;;
111    -p|--llvm-project)
112      PROJ="$2"
113      if [ "$PROJ" == "cfe" ]; then
114        PROJ="clang"
115      fi
116
117      CHECKOUT_ARGS="$CHECKOUT_ARGS $1 $PROJ"
118      if [ "$PROJ" != "clang-tools-extra" ]; then
119        CMAKE_ENABLED_PROJECTS="$CMAKE_ENABLED_PROJECTS;$PROJ"
120      fi
121
122      shift 2
123      ;;
124    -c|--checksums)
125      shift
126      CHECKSUMS_FILE="$1"
127      shift
128      ;;
129    --)
130      shift
131      BUILDSCRIPT_ARGS="$BUILDSCRIPT_ARGS -- $*"
132      SEEN_CMAKE_ARGS=1
133      shift $#
134      ;;
135    *)
136      echo "Unknown argument $1"
137      exit 1
138      ;;
139  esac
140done
141
142
143if [ "$CMAKE_ENABLED_PROJECTS" != "" ]; then
144  # Remove the leading ';' character.
145  CMAKE_ENABLED_PROJECTS="${CMAKE_ENABLED_PROJECTS:1}"
146
147  if [[ $SEEN_CMAKE_ARGS -eq 0 ]]; then
148    BUILDSCRIPT_ARGS="$BUILDSCRIPT_ARGS --"
149  fi
150  BUILDSCRIPT_ARGS="$BUILDSCRIPT_ARGS -DLLVM_ENABLE_PROJECTS=$CMAKE_ENABLED_PROJECTS"
151fi
152
153command -v docker >/dev/null ||
154  {
155    echo "Docker binary cannot be found. Please install Docker to use this script."
156    exit 1
157  }
158
159if [ "$IMAGE_SOURCE" == "" ]; then
160  echo "Required argument missing: --source"
161  exit 1
162fi
163
164if [ "$DOCKER_REPOSITORY" == "" ]; then
165  echo "Required argument missing: --docker-repository"
166  exit 1
167fi
168
169if [ $SEEN_INSTALL_TARGET -eq 0 ]; then
170  echo "Please provide at least one --install-target"
171  exit 1
172fi
173
174SOURCE_DIR=$(dirname $0)
175if [ ! -d "$SOURCE_DIR/$IMAGE_SOURCE" ]; then
176  echo "No sources for '$IMAGE_SOURCE' were found in $SOURCE_DIR"
177  exit 1
178fi
179
180BUILD_DIR=$(mktemp -d)
181trap "rm -rf $BUILD_DIR" EXIT
182echo "Using a temporary directory for the build: $BUILD_DIR"
183
184cp -r "$SOURCE_DIR/$IMAGE_SOURCE" "$BUILD_DIR/$IMAGE_SOURCE"
185cp -r "$SOURCE_DIR/scripts" "$BUILD_DIR/scripts"
186
187mkdir "$BUILD_DIR/checksums"
188if [ "$CHECKSUMS_FILE" != "" ]; then
189  cp "$CHECKSUMS_FILE" "$BUILD_DIR/checksums/checksums.txt"
190fi
191
192if [ "$DOCKER_TAG" != "" ]; then
193  DOCKER_TAG=":$DOCKER_TAG"
194fi
195
196echo "Building ${DOCKER_REPOSITORY}${DOCKER_TAG} from $IMAGE_SOURCE"
197docker build -t "${DOCKER_REPOSITORY}${DOCKER_TAG}" \
198  --build-arg "checkout_args=$CHECKOUT_ARGS" \
199  --build-arg "buildscript_args=$BUILDSCRIPT_ARGS" \
200  -f "$BUILD_DIR/$IMAGE_SOURCE/Dockerfile" \
201  "$BUILD_DIR"
202echo "Done"
203