1#!/usr/bin/env bash
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# This script will check out llvm and clang into third_party/llvm and build it.
7
8# Do NOT CHANGE this if you don't know what you're doing -- see
9# https://code.google.com/p/chromium/wiki/UpdatingClang
10# Reverting problematic clang rolls is safe, though.
11CLANG_REVISION=186332
12
13THIS_DIR="$(dirname "${0}")"
14LLVM_DIR="${THIS_DIR}/../../../third_party/llvm"
15LLVM_BUILD_DIR="${LLVM_DIR}/../llvm-build"
16LLVM_BOOTSTRAP_DIR="${LLVM_DIR}/../llvm-bootstrap"
17CLANG_DIR="${LLVM_DIR}/tools/clang"
18CLANG_TOOLS_EXTRA_DIR="${CLANG_DIR}/tools/extra"
19COMPILER_RT_DIR="${LLVM_DIR}/projects/compiler-rt"
20ANDROID_NDK_DIR="${LLVM_DIR}/../android_tools/ndk"
21STAMP_FILE="${LLVM_BUILD_DIR}/cr_build_revision"
22
23# ${A:-a} returns $A if it's set, a else.
24LLVM_REPO_URL=${LLVM_URL:-https://llvm.org/svn/llvm-project}
25
26# Die if any command dies.
27set -e
28
29OS="$(uname -s)"
30
31# Parse command line options.
32force_local_build=
33mac_only=
34run_tests=
35bootstrap=
36with_android=yes
37chrome_tools="plugins"
38
39if [[ "${OS}" = "Darwin" ]]; then
40  with_android=
41fi
42
43while [[ $# > 0 ]]; do
44  case $1 in
45    --bootstrap)
46      bootstrap=yes
47      ;;
48    --force-local-build)
49      force_local_build=yes
50      ;;
51    --mac-only)
52      mac_only=yes
53      ;;
54    --run-tests)
55      run_tests=yes
56      ;;
57    --without-android)
58      with_android=
59      ;;
60    --with-chrome-tools)
61      shift
62      if [[ $# == 0 ]]; then
63        echo "--with-chrome-tools requires an argument."
64        exit 1
65      fi
66      chrome_tools=$1
67      ;;
68    --help)
69      echo "usage: $0 [--force-local-build] [--mac-only] [--run-tests] "
70      echo "--bootstrap: First build clang with CC, then with itself."
71      echo "--force-local-build: Don't try to download prebuilt binaries."
72      echo "--mac-only: Do initial download only on Mac systems."
73      echo "--run-tests: Run tests after building. Only for local builds."
74      echo "--without-android: Don't build ASan Android runtime library."
75      echo "--with-chrome-tools: Select which chrome tools to build." \
76           "Defaults to plugins."
77      echo "    Example: --with-chrome-tools 'plugins empty-string'"
78      echo
79      exit 1
80      ;;
81  esac
82  shift
83done
84
85# --mac-only prevents the initial download on non-mac systems, but if clang has
86# already been downloaded in the past, this script keeps it up to date even if
87# --mac-only is passed in and the system isn't a mac. People who don't like this
88# can just delete their third_party/llvm-build directory.
89if [[ -n "$mac_only" ]] && [[ "${OS}" != "Darwin" ]] &&
90    [[ ! ( "$GYP_DEFINES" =~ .*(clang|tsan|asan)=1.* ) ]] &&
91    ! [[ -d "${LLVM_BUILD_DIR}" ]]; then
92  exit 0
93fi
94
95# Xcode and clang don't get along when predictive compilation is enabled.
96# http://crbug.com/96315
97if [[ "${OS}" = "Darwin" ]] && xcodebuild -version | grep -q 'Xcode 3.2' ; then
98  XCONF=com.apple.Xcode
99  if [[ "${GYP_GENERATORS}" != "make" ]] && \
100     [ "$(defaults read "${XCONF}" EnablePredictiveCompilation)" != "0" ]; then
101    echo
102    echo "          HEARKEN!"
103    echo "You're using Xcode3 and you have 'Predictive Compilation' enabled."
104    echo "This does not work well with clang (http://crbug.com/96315)."
105    echo "Disable it in Preferences->Building (lower right), or run"
106    echo "    defaults write ${XCONF} EnablePredictiveCompilation -boolean NO"
107    echo "while Xcode is not running."
108    echo
109  fi
110
111  SUB_VERSION=$(xcodebuild -version | sed -Ene 's/Xcode 3\.2\.([0-9]+)/\1/p')
112  if [[ "${SUB_VERSION}" < 6 ]]; then
113    echo
114    echo "          YOUR LD IS BUGGY!"
115    echo "Please upgrade Xcode to at least 3.2.6."
116    echo
117  fi
118fi
119
120
121# Check if there's anything to be done, exit early if not.
122if [[ -f "${STAMP_FILE}" ]]; then
123  PREVIOUSLY_BUILT_REVISON=$(cat "${STAMP_FILE}")
124  if [[ -z "$force_local_build" ]] && \
125       [[ "${PREVIOUSLY_BUILT_REVISON}" = "${CLANG_REVISION}" ]]; then
126    echo "Clang already at ${CLANG_REVISION}"
127    exit 0
128  fi
129fi
130# To always force a new build if someone interrupts their build half way.
131rm -f "${STAMP_FILE}"
132
133# Clobber pch files, since they only work with the compiler version that
134# created them. Also clobber .o files, to make sure everything will be built
135# with the new compiler.
136if [[ "${OS}" = "Darwin" ]]; then
137  XCODEBUILD_DIR="${THIS_DIR}/../../../xcodebuild"
138
139  # Xcode groups .o files by project first, configuration second.
140  if [[ -d "${XCODEBUILD_DIR}" ]]; then
141    echo "Clobbering .o files for Xcode build"
142    find "${XCODEBUILD_DIR}" -name '*.o' -exec rm {} +
143  fi
144fi
145
146MAKE_DIR="${THIS_DIR}/../../../out"
147
148for CONFIG in Debug Release; do
149  if [[ -d "${MAKE_DIR}/${CONFIG}/obj.target" ||
150        -d "${MAKE_DIR}/${CONFIG}/obj.host" ]]; then
151    echo "Clobbering ${CONFIG} PCH and .o files for make build"
152    if [[ -d "${MAKE_DIR}/${CONFIG}/obj.target" ]]; then
153      find "${MAKE_DIR}/${CONFIG}/obj.target" -name '*.gch' -exec rm {} +
154      find "${MAKE_DIR}/${CONFIG}/obj.target" -name '*.o' -exec rm {} +
155    fi
156    if [[ -d "${MAKE_DIR}/${CONFIG}/obj.host" ]]; then
157      find "${MAKE_DIR}/${CONFIG}/obj.host" -name '*.o' -exec rm {} +
158    fi
159  fi
160
161  # ninja puts its output below ${MAKE_DIR} as well.
162  if [[ -d "${MAKE_DIR}/${CONFIG}/obj" ]]; then
163    echo "Clobbering ${CONFIG} PCH and .o files for ninja build"
164    find "${MAKE_DIR}/${CONFIG}/obj" -name '*.gch' -exec rm {} +
165    find "${MAKE_DIR}/${CONFIG}/obj" -name '*.o' -exec rm {} +
166    find "${MAKE_DIR}/${CONFIG}/obj" -name '*.o.d' -exec rm {} +
167  fi
168
169  if [[ "${OS}" = "Darwin" ]]; then
170    if [[ -d "${XCODEBUILD_DIR}/${CONFIG}/SharedPrecompiledHeaders" ]]; then
171      echo "Clobbering ${CONFIG} PCH files for Xcode build"
172      rm -rf "${XCODEBUILD_DIR}/${CONFIG}/SharedPrecompiledHeaders"
173    fi
174  fi
175done
176
177# Clobber NaCl toolchain stamp files, see http://crbug.com/159793
178if [[ -d "${MAKE_DIR}" ]]; then
179  find "${MAKE_DIR}" -name 'stamp.untar' -exec rm {} +
180fi
181if [[ "${OS}" = "Darwin" ]]; then
182  if [[ -d "${XCODEBUILD_DIR}" ]]; then
183    find "${XCODEBUILD_DIR}" -name 'stamp.untar' -exec rm {} +
184  fi
185fi
186
187if [[ -z "$force_local_build" ]]; then
188  # Check if there's a prebuilt binary and if so just fetch that. That's faster,
189  # and goma relies on having matching binary hashes on client and server too.
190  CDS_URL=https://commondatastorage.googleapis.com/chromium-browser-clang
191  CDS_FILE="clang-${CLANG_REVISION}.tgz"
192  CDS_OUT_DIR=$(mktemp -d -t clang_download.XXXXXX)
193  CDS_OUTPUT="${CDS_OUT_DIR}/${CDS_FILE}"
194  if [ "${OS}" = "Linux" ]; then
195    CDS_FULL_URL="${CDS_URL}/Linux_x64/${CDS_FILE}"
196  elif [ "${OS}" = "Darwin" ]; then
197    CDS_FULL_URL="${CDS_URL}/Mac/${CDS_FILE}"
198  fi
199  echo Trying to download prebuilt clang
200  if which curl > /dev/null; then
201    curl -L --fail "${CDS_FULL_URL}" -o "${CDS_OUTPUT}" || \
202        rm -rf "${CDS_OUT_DIR}"
203  elif which wget > /dev/null; then
204    wget "${CDS_FULL_URL}" -O "${CDS_OUTPUT}" || rm -rf "${CDS_OUT_DIR}"
205  else
206    echo "Neither curl nor wget found. Please install one of these."
207    exit 1
208  fi
209  if [ -f "${CDS_OUTPUT}" ]; then
210    rm -rf "${LLVM_BUILD_DIR}/Release+Asserts"
211    mkdir -p "${LLVM_BUILD_DIR}/Release+Asserts"
212    tar -xzf "${CDS_OUTPUT}" -C "${LLVM_BUILD_DIR}/Release+Asserts"
213    echo clang "${CLANG_REVISION}" unpacked
214    echo "${CLANG_REVISION}" > "${STAMP_FILE}"
215    rm -rf "${CDS_OUT_DIR}"
216    exit 0
217  else
218    echo Did not find prebuilt clang at r"${CLANG_REVISION}", building
219  fi
220fi
221
222if [[ -n "${with_android}" ]] && ! [[ -d "${ANDROID_NDK_DIR}" ]]; then
223  echo "Android NDK not found at ${ANDROID_NDK_DIR}"
224  echo "The Android NDK is needed to build a Clang whose -fsanitize=address"
225  echo "works on Android. See "
226  echo "http://code.google.com/p/chromium/wiki/AndroidBuildInstructions for how"
227  echo "to install the NDK, or pass --without-android."
228  exit 1
229fi
230
231echo Getting LLVM r"${CLANG_REVISION}" in "${LLVM_DIR}"
232if ! svn co --force "${LLVM_REPO_URL}/llvm/trunk@${CLANG_REVISION}" \
233                    "${LLVM_DIR}"; then
234  echo Checkout failed, retrying
235  rm -rf "${LLVM_DIR}"
236  svn co --force "${LLVM_REPO_URL}/llvm/trunk@${CLANG_REVISION}" "${LLVM_DIR}"
237fi
238
239echo Getting clang r"${CLANG_REVISION}" in "${CLANG_DIR}"
240svn co --force "${LLVM_REPO_URL}/cfe/trunk@${CLANG_REVISION}" "${CLANG_DIR}"
241
242echo Getting compiler-rt r"${CLANG_REVISION}" in "${COMPILER_RT_DIR}"
243svn co --force "${LLVM_REPO_URL}/compiler-rt/trunk@${CLANG_REVISION}" \
244               "${COMPILER_RT_DIR}"
245
246# Echo all commands.
247set -x
248
249NUM_JOBS=3
250if [[ "${OS}" = "Linux" ]]; then
251  NUM_JOBS="$(grep -c "^processor" /proc/cpuinfo)"
252elif [ "${OS}" = "Darwin" ]; then
253  NUM_JOBS="$(sysctl -n hw.ncpu)"
254fi
255
256# Build bootstrap clang if requested.
257if [[ -n "${bootstrap}" ]]; then
258  echo "Building bootstrap compiler"
259  mkdir -p "${LLVM_BOOTSTRAP_DIR}"
260  cd "${LLVM_BOOTSTRAP_DIR}"
261  if [[ ! -f ./config.status ]]; then
262    # The bootstrap compiler only needs to be able to build the real compiler,
263    # so it needs no cross-compiler output support. In general, the host
264    # compiler should be as similar to the final compiler as possible, so do
265    # keep --disable-threads & co.
266    ../llvm/configure \
267        --enable-optimized \
268        --enable-targets=host-only \
269        --disable-threads \
270        --disable-pthreads \
271        --without-llvmgcc \
272        --without-llvmgxx
273  fi
274  MACOSX_DEPLOYMENT_TARGET=10.5 make -j"${NUM_JOBS}"
275  if [[ -n "${run_tests}" ]]; then
276    make check-all
277  fi
278  cd -
279  export CC="${PWD}/${LLVM_BOOTSTRAP_DIR}/Release+Asserts/bin/clang"
280  export CXX="${PWD}/${LLVM_BOOTSTRAP_DIR}/Release+Asserts/bin/clang++"
281  echo "Building final compiler"
282fi
283
284# Build clang (in a separate directory).
285# The clang bots have this path hardcoded in built/scripts/slave/compile.py,
286# so if you change it you also need to change these links.
287mkdir -p "${LLVM_BUILD_DIR}"
288cd "${LLVM_BUILD_DIR}"
289if [[ ! -f ./config.status ]]; then
290  ../llvm/configure \
291      --enable-optimized \
292      --disable-threads \
293      --disable-pthreads \
294      --without-llvmgcc \
295      --without-llvmgxx
296fi
297
298MACOSX_DEPLOYMENT_TARGET=10.5 make -j"${NUM_JOBS}"
299STRIP_FLAGS=
300if [ "${OS}" = "Darwin" ]; then
301  # See http://crbug.com/256342
302  STRIP_FLAGS=-x
303fi
304strip ${STRIP_FLAGS} Release+Asserts/bin/clang
305cd -
306
307if [[ -n "${with_android}" ]]; then
308  # Make a standalone Android toolchain.
309  ${ANDROID_NDK_DIR}/build/tools/make-standalone-toolchain.sh \
310      --platform=android-14 \
311      --install-dir="${LLVM_BUILD_DIR}/android-toolchain" \
312      --system=linux-x86_64 \
313      --stl=stlport
314
315  # Build ASan runtime for Android.
316  # Note: LLVM_ANDROID_TOOLCHAIN_DIR is not relative to PWD, but to where we
317  # build the runtime, i.e. third_party/llvm/projects/compiler-rt.
318  cd "${LLVM_BUILD_DIR}"
319  make -C tools/clang/runtime/ \
320    LLVM_ANDROID_TOOLCHAIN_DIR="../../../llvm-build/android-toolchain"
321  cd -
322fi
323
324# Build Chrome-specific clang tools. Paths in this list should be relative to
325# tools/clang.
326# For each tool directory, copy it into the clang tree and use clang's build
327# system to compile it.
328for CHROME_TOOL_DIR in ${chrome_tools}; do
329  TOOL_SRC_DIR="${THIS_DIR}/../${CHROME_TOOL_DIR}"
330  TOOL_DST_DIR="${LLVM_DIR}/tools/clang/tools/chrome-${CHROME_TOOL_DIR}"
331  TOOL_BUILD_DIR="${LLVM_BUILD_DIR}/tools/clang/tools/chrome-${CHROME_TOOL_DIR}"
332  rm -rf "${TOOL_DST_DIR}"
333  cp -R "${TOOL_SRC_DIR}" "${TOOL_DST_DIR}"
334  rm -rf "${TOOL_BUILD_DIR}"
335  mkdir -p "${TOOL_BUILD_DIR}"
336  cp "${TOOL_SRC_DIR}/Makefile" "${TOOL_BUILD_DIR}"
337  MACOSX_DEPLOYMENT_TARGET=10.5 make -j"${NUM_JOBS}" -C "${TOOL_BUILD_DIR}"
338done
339
340if [[ -n "$run_tests" ]]; then
341  # Run a few tests.
342  PLUGIN_SRC_DIR="${THIS_DIR}/../plugins"
343  "${PLUGIN_SRC_DIR}/tests/test.sh" "${LLVM_BUILD_DIR}/Release+Asserts"
344  cd "${LLVM_BUILD_DIR}"
345  make check-all
346  cd -
347fi
348
349# After everything is done, log success for this revision.
350echo "${CLANG_REVISION}" > "${STAMP_FILE}"
351