blob: 580c2bd09a89a19cf35e007e44775a809e79fca1 [file]
#!/usr/bin/env bash
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# A script to rebuild Bazel from sources for Fuchsia, see --help for details.
set -euo pipefail
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
readonly SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Detect the 'pv' program in the environment. This will be useful to
# print a timer in non-verbose mode during the different build steps.
PV="$(which pv 2>/dev/null || true)"
# Detect whether stderr is a terminal, if this is the case and 'pv' is available
# the it will be used to print a timer + progress updates during the build in
# non-verbose mode.
IS_TERMINAL=
if [[ -t 2 ]]; then
IS_TERMINAL=true
fi
VERBOSE=0
if [[ -z "$IS_TERMINAL" ]]; then
# When not in terminal mode, force verbose mode.
VERBOSE=1
fi
function run_internal() {
if [[ "$VERBOSE" -ge 1 ]]; then
echo "CMD: $*"
fi
"$@" 2>&1
}
function run_log_internal() {
if [[ -n "${LOG_FILE}" ]]; then
run_internal "$@" | tee --append "${LOG_FILE}"
else
run_internal "$@"
fi
}
# Log file path for non-verbose mode.
LOG_FILE=
# Run a command and log its output if necessary.
# If the 'pv' program is installed, use it to print progress.
# $1: Command description for 'pv' timer.
# $2+: The command to run.
function run_step() {
local description="$1"
shift
if [[ "${VERBOSE}" -eq 0 && -n "${IS_TERMINAL}" && -n "${PV}" ]]; then
run_log_internal "$@" | "${PV}" -tpl -N" ${description}" -X
else
run_log_internal "$@"
fi
}
# Print error message then exit script with error status.
function die() {
echo >&2 "ERROR: $*"
exit 1
}
# Make a file path absolute
# $1: file path
# Output: absolute file path.
function make_absolute() {
case "$1" in
/*)
echo "$1"
;;
*)
echo "${PWD}/$1"
;;
esac
}
# Generate C++ toolchain wrapper scripts
# $1: wrapper_dir path
# $2: clang_bindir value, or empty string.
# $3: sysroot_dir value, or empty string.
function generate_toolchain_wrappers() {
local wrapper_dir="$1"
local clang_bindir="$2"
local sysroot_dir="$3"
local clang_prefix=""
if [[ -n "${clang_bindir}" ]]; then
clang_prefix="${clang_bindir}/"
fi
local sysroot_args=()
if [[ -n "${sysroot_dir}" ]]; then
sysroot_dir="$(cd "${sysroot_dir}" && pwd)"
sysroot_args=(--sysroot="${sysroot_dir}")
fi
local tool tool_script
mkdir -p "${wrapper_dir}"
rm -rf "${wrapper_dir:?}"/*
for tool in clang clang++ lld; do
tool_script="${wrapper_dir}/${tool}"
cat > "${tool_script}" <<EOF
#!/bin/bash
exec "${clang_prefix}${tool}" "${sysroot_args[@]}" "\$@"
EOF
chmod a+x "${tool_script}"
done
}
# Extract the Bazel version from a source or distribution directory.
# $1: Bazel source or distribution directory.
function extract_bazel_version_from_dir() {
# Parse the top-level MODULE.bazel file, which must starts with something like:
#
# module(
# name = "bazel",
# version = "8.8.0",
# repo_name = "io_bazel",
# )
local module_path="$1/MODULE.bazel"
[[ -f "${module_path}" ]] || die "Missing input file: ${module_path}"
awk '$1 == "version" && $2 == "=" { print $3 }' "${module_path}" | head -n1 | tr -d '",'
}
# Parse command-line
function help_requirements() {
cat <<EOF
Building Bazel from sources is a very long process that
requires:
- A directory pointing to the Bazel git sources,
or to an expanded Bazel distribution archive, or the
path to a Bazel distribution zip archive.
Use one of --bazel-src-dir, --bazel-dist-dir and
--bazel-dist-archive to indicate which one.
- A previous version of Bazel to build the new sources.
Note that Bazel X.Y.Z often requires Bazel X.(Y-1) or
Bazel (X-1).* to build properly.
Use --boot-bazel to indicate its path.
- A local JDK, preferably selected through the JAVA_HOME
environment variable.
- A C++ compiler to build various host tools embedded
in the final 'bazel' binary. Using the Fuchsia
toolchain is highly recommended.
- Network access during the build, as this will download
over 4 GiB of artifacts from the Internet (with
content hashes locked to fixed values from the source
Bazel directory).
EOF
exit 0
}
function usage() {
cat <<EOF
Usage: ${SCRIPT_NAME} [options]
Build Bazel binary from source for Fuchsia.
Read --help-requirements for requirements.
This takes several minutes on a very powerful machine
and installs the final binary into a directory with
the following layout:
\$INSTALL_DIR/
bazel
bazel-real
install_base/
README.fuchsia
LICENSE
Valid options:
--help
Print this message
--help-requirements
Description of the requirements for building Bazel
from sources with this script.
--help-steps
Detailed description of the build steps performed by
this script. Mostly useful if things go wrong of if
one needs to hack on this script.
--install-dir=DIR
Path to the installation directory that will
receive the final files.
--boot-bazel=PROGRAM
Path to the Bazel binary used to bootstrap this build.
Defaults to the value of the BAZEL environment variable,
otherwise to 'bazel' in your PATH.
--build-dir=BUILD_DIR
Path to a build directory. If not provided, a temporary
directory will be used (and cleaned up on exit).
--bazel-src-dir=DIR
--bazel-dist-dir=DIR
--bazel-dist-archive=ARCHIVE
One of these options must be provided to locate the Bazel
sources or a pre-existing distribution archive.
--bazel-src-dir points to a Bazel source repository.
--bazel-dist-dir points to an expanded Bazel distribution archive.
--bazel-dist-archive points to a Bazel distribution zip archive
that will be expanded into a temporary directory.
--bazel-version=VERSION
Bazel version (e.g. "8.1.1"). Defaults to auto-detection from
the content of the source or distribution directory, or the
name of the distribution archive.
NOTE: the final binary will use "VERSION-fuchsia" as its
version label, to distinguish it from official release binaries.
--clang-bindir=CLANG_BINDIR
Optional. Use specific Clang installation to build C++ binaries.
--sysroot-dir=SYSROOT_DIR
Optional. Use specific sysroot to build C++ binaries.
--fuchsia-dir=FUCHSIA_DIR
Use the Fuchsia Clang toolchain and Linux sysroot to build C++ binaries.
This implies the following flags, unless specified manually:
--clang-dir=\$FUCHSIA_DIR/prebuilt/third_party/clang/linux-x64/bin
--sysroot-dir=\$FUCHSIA_DIR/prebuilt/third_party/sysroot/linux
--boot-bazel=\$FUCHSIA_DIR/prebuilt/third_party/bazel/linux-x64
FUCHSIA_DIR should point to the root of a Fuchsia source directory.
--skip-*
These flags are only used when debugging or changing this script.
See --help-steps for details.
EOF
exit 0
}
function help_steps() {
cat <<EOF
Building Bazel from sources is a very long process which consists in
several steps:
- STEP 1: Distribution archive creation.
This only happens when --bazel-src-dir=DIR is used. This creates
a new distribution archive from the git sources, an operation that
downloads over 4 GiB of prebuilts from the internet, and packs
the sources and downloaded artifacts into a large zip archive.
It also compiles a few
This requires a local JDK and a boot Bazel binary (the latter
will *not* be used by other steps).
- STEP 2: Distribution archive extraction.
This does not happen if --bazel-dist-dir=DIR is used. Otherwise
extract the distribution archive to a temporary directory. This
only requires the 'unzip' program.
- STEP 3: Producing a stage 1 Bazel binary
This builds a first 'bazel' binary that doesn't embed any JDK
from scratch. This only requires a local JDK and this build
should not download anything from the internet, as it will
only use artifacts from the distribution archive.
- STEP 4: Producing the stage 2 Bazel binary
The stage 1 'bazel' program is launched to build the final
version of the program, which will contain an embedded JDK
that matches official Bazel releases.
- STEP 5: Installation to Fuchsia-specific directory layout
The stage 2 binary is copied to \$INSTALL_DIR as 'bazel-real'
while a wrapper 'bazel' script, a LICENSE file, and a
README.fuchsia files are added to. In addition, and
'install_base' directory is created contained the
expanded content of 'bazel-real', to reduce startup
overhead and disk usage during the build.
Recommendations
Use the --fuchsia-dir=DIR option to use the Fuchsia C++
toolchain and Linux sysroot, they will produce optimized
binaries that can run on older Linux images such as
Ubuntu 18.04, as required for Fuchsia development.
Development tips:
Use the --build-dir=DIR option if you need to work on this
script (e.g. debugging build problems with newer Bazel
sources).
When using --build-dir, the following extra flags can be
used during incremental builds to skip steps already
performed in the previous call:
--skip-dist
Skip step 1 (creation of the distribution archive), and reuse
the previous one. Ignored if --bazel-src-dir is not used.
--skip-extract
Skip step 2 (extraction of the distribution archive), and
reuse the previous extracted directory. Ignored if
--baazel-dist-dir is used.
--skip-stage1
Skip step 3 (building the stage 1 binary) and reuse
the previous version.
--skip-stage2
Skip step 4 (building the stage 2 binary) and reuse the
previous version for final installation.
EOF
exit 0
}
BOOT_BAZEL=
BAZEL_SRC_DIR=
BAZEL_DIST_ARCHIVE=
BAZEL_DIST_DIR=
BAZEL_VERSION=
BUILD_DIR=
CLANG_BINPREFIX=
INSTALL_DIR=
LOG_FILE=
CLANG_BINDIR=
SYSROOT_DIR=
SKIP_DIST=
SKIP_EXTRACT=
SKIP_STAGE1=
SKIP_STAGE2=
JAVA_HOME="${JAVA_HOME:-}"
for OPT; do
OPTARG="${OPT##--*=}"
case "${OPT}" in
--boot-bazel=*)
BOOT_BAZEL="${OPTARG}"
;;
--bazel-src-dir=*)
BAZEL_SRC_DIR="${OPTARG}"
;;
--bazel-dist-archive=*)
BAZEL_DIST_ARCHIVE="${OPTARG}"
;;
--bazel-dist-dir=*)
BAZEL_DIST_DIR="${OPTARG}"
;;
--bazel-version=*)
BAZEL_VERSION="${OPTARG}"
;;
--build-dir=*)
BUILD_DIR="${OPTARG}"
;;
--log-file=*)
LOG_FILE="${OPTARG}"
;;
--sysroot-dir=*)
SYSROOT_DIR="${OPTARG}"
;;
--clang-bindir=*)
CLANG_BINDIR="${OPTARG}"
;;
--fuchsia-dir=*)
CLANG_BINDIR="${OPTARG}/prebuilt/third_party/clang/linux-x64/bin"
SYSROOT_DIR="${OPTARG}/prebuilt/third_party/sysroot/linux"
if [[ -z "${BOOT_BAZEL}" ]]; then
BOOT_BAZEL="${OPTARG}/prebuilt/third_party/bazel/linux-x64/bazel"
fi
;;
--help)
usage
;;
--help-steps)
help_steps
;;
--install-dir=*)
INSTALL_DIR="${OPTARG}"
;;
--skip-dist)
SKIP_DIST=true
;;
--skip-extract)
SKIP_DIST=true
SKIP_EXTRACT=true
;;
--skip-stage1)
SKIP_DIST=true
SKIP_EXTRACT=true
SKIP_STAGE1=true
;;
-v|--verbose)
VERBOSE=$(( VERBOSE + 1 ))
;;
-vv*)
VERBOSE=$(( VERBOSE + 2 ))
;;
-*)
die "Invalid option, see --help."
;;
*)
die "This script doesn't take arguments, see --help."
esac
done
[[ -n "${INSTALL_DIR}" ]] || die "Missing --install-dir=DIR argument, see --help."
if [[ -n "${BAZEL_SRC_DIR}" ]]; then
[[ -z "${BAZEL_DIST_DIR}" && -z "${BAZEL_DIST_ARCHIVE}" ]] || die "Cannot use --bazel-dist-{dir,archive} with --bazel-src-dir."
[[ -d "${BAZEL_SRC_DIR}" ]] || die "Not a directory: ${BAZEL_SRC_DIR}"
elif [[ -n "${BAZEL_DIST_DIR}" ]]; then
[[ -d "${BAZEL_DIST_DIR}" ]] || die "Not a directory: ${BAZEL_DIST_DIR}"
[[ -z "${BAZEL_DIST_ARCHIVE}" ]] || die "Do not set both --bazel-dist-dir and --bazel-dist-archive"
else
[[ -n "${BAZEL_DIST_ARCHIVE}" ]] || die "One of --bazel-src-dir, --bazel-dir-dir or --bazel-dist-archive is required"
[[ -f "${BAZEL_DIST_ARCHIVE}" ]] || die "Missing Bazel dist archive: ${BAZEL_DIST_ARCHIVE}"
fi
if [[ -n "${SYSROOT_DIR}" ]]; then
[[ -d "${SYSROOT_DIR}" ]] || die "Not a directory: ${SYSROOT_DIR}"
[[ -d "${SYSROOT_DIR}/usr/include" ]] || die "Not a sysroot directory: ${SYSROOT_DIR}"
fi
if [[ -n "${CLANG_BINDIR}" ]]; then
[[ -f "${CLANG_BINDIR}/clang" ]] || die "Missing Clang binary: ${CLANG_BINDIR}/clang"
fi
TEMP_BUILD_DIR=
function cleanup_temp_build_dir {
if [[ -n "$TEMP_BUILD_DIR" ]]; then
# Print a newline first, since this can be called in case of Ctrl-C
printf "\nCleaning up build directory %s\n" "${TEMP_BUILD_DIR}" >&2
# Bazel generates read-only files in its output_base directory
# which prevent `rm -rf` from working. Deal with that now.
if [[ -d "${TEMP_BUILD_DIR}/output_base" ]]; then
chmod -R +w "${TEMP_BUILD_DIR}/output_base"
rm -rf "${TEMP_BUILD_DIR}"
fi
TEMP_BUILD_DIR=
fi
}
declare -i START_TIME=${SECONDS}
if [[ -z "${BUILD_DIR}" ]]; then
TEMP_BUILD_DIR=/tmp/bazel-build-dir-$$
mkdir -p "${TEMP_BUILD_DIR}"
rm -rf "${TEMP_BUILD_DIR:?}"/*
trap cleanup_temp_build_dir EXIT
BUILD_DIR="${TEMP_BUILD_DIR}"
else
mkdir -p "${BUILD_DIR}"
BUILD_DIR="$(cd "${BUILD_DIR}" && pwd 2>/dev/null)"
fi
if [[ "$VERBOSE" -eq 0 ]]; then
# Setup a default log file in non-verbose mode.
LOG_FILE="${LOG_FILE:-"${BUILD_DIR}/build-log.txt"}"
fi
# Generate toolchain wrapper scripts is --clang-dir or --sysroot-dir are used.
# Adding them to the PATH ensures Bazel will use the right compiler and/or sysroot.
if [[ -n "${SYSROOT_DIR}" || -n "${CLANG_BINPREFIX}" ]]; then
TOOLCHAIN_WRAPPER_DIR="${BUILD_DIR}/toolchain-wrappers"
generate_toolchain_wrappers "${TOOLCHAIN_WRAPPER_DIR}" "${CLANG_BINDIR}" "${SYSROOT_DIR}"
export PATH="${TOOLCHAIN_WRAPPER_DIR}:${PATH}"
export CXX="clang++"
export CC="clang"
export LD="lld"
fi
if [[ -n "${JAVA_HOME}" ]]; then
JAVA="${JAVA_HOME}/bin/java"
else
JAVA="java"
fi
# Extract major Java version.
# Expected format of first line of `java --version` output:
# <vendor> <major>.<minor>.<patch> <other...>
JAVA_VERSION="$("${JAVA}" --version | head -n1 | awk '{print $2}' | cut -d. -f1)"
if [[ -z "${BAZEL_VERSION}" ]]; then
if [[ -n "${BAZEL_SRC_DIR}" ]]; then
BAZEL_VERSION="$(extract_bazel_version_from_dir "${BAZEL_SRC_DIR}")"
elif [[ -n "${BAZEL_DIST_DIR}" ]]; then
BAZEL_VERSION="$(extract_bazel_version_from_dir "${BAZEL_DIST_DIR}")"
else
BAZEL_DIST_NAME=$(basename "${BAZEL_DIST_ARCHIVE}")
case "${BAZEL_DIST_NAME}" in
bazel-*-dist.zip)
BAZEL_VERSION="${BAZEL_DIST_NAME#bazel-}"
BAZEL_VERSION="${BAZEL_VERSION%-dist.zip}"
;;
*)
die "Could not extract Bazel version from ${BAZEL_DIST_NAME}, use --bazel-version!"
;;
esac
fi
fi
BOOT_BAZEL_ARGS=(
--output_base="${BUILD_DIR}"/output_base
--output_user_root="${BUILD_DIR}"/output_user_root
# Ensure Bazel doesn't create read-only artifacts in the output base
# --experimental_writable_outputs
)
[[ -n "${BOOT_BAZEL}" ]] || {
BOOT_BAZEL="${BAZEL:-bazel}"
}
BOOT_BAZEL_VERSION="$("${BOOT_BAZEL}" version 2>&1 | awk '$1 == "Build" && $2 == "label:" { print $3 }' || true)"
cat <<EOF
Preparing to build Bazel from sources:
BAZEL_VERSION: ${BAZEL_VERSION}
BAZEL_SRC_DIR: ${BAZEL_SRC_DIR}
BAZEL_DIST_ARCHIVE: ${BAZEL_DIST_ARCHIVE}
BAZEL_DIST_DIR: ${BAZEL_DIST_DIR}
INSTALL_DIR: ${INSTALL_DIR}
BUILD_DIR: ${BUILD_DIR}
JAVA_HOME: ${JAVA_HOME}
JAVA_VERSION: ${JAVA_VERSION}
BOOT_BAZEL ${BOOT_BAZEL}
BOOT_BAZEL_VERSION ${BOOT_BAZEL_VERSION}
BOOT_BAZEL_ARGS ${BOOT_BAZEL_ARGS[*]}
CLANG_BINDIR: ${CLANG_BINDIR}
SYSROOT_DIR: ${SYSROOT_DIR}
EOF
if [[ -n "$LOG_FILE" ]]; then
echo "Follow build with: tail -f $LOG_FILE"
fi
if [[ -n "$IS_TERMINAL" && -z "${PV}" ]]; then
echo "ProTip: Install 'pv' program for terminal progress output during the build."
fi
# Ensure the build stores all artifacts in the build directory
# instead of trying to put them under $HOME/.cache/bazel/
_BAZEL_OUTPUT_USER_ROOT="${BUILD_DIR}/bazel_output_user_root"
if [[ -n "${BAZEL_SRC_DIR}" ]]; then
DIST_ARCHIVE="${BUILD_DIR}/bazel-${BAZEL_VERSION}.zip"
if [[ -n "$SKIP_DIST" ]]; then
[[ -f "${DIST_ARCHIVE}" ]] || die "--skip-dist used but archive missing: ${DIST_ARCHIVE}"
echo "Skipping dist archive creation."
else
echo "Creating distribution archive from source directory."
(
cd "${BAZEL_SRC_DIR}"
run_step "Creating distribution archive" "${BOOT_BAZEL}" "${BOOT_BAZEL_ARGS[@]}" build --compiler=clang --compilation_mode=opt --strip=always //:bazel-distfile
cp -f bazel-bin/bazel-distfile.zip "${DIST_ARCHIVE}"
# Bazel creates a read-only archive by default. Make it writable
# after the copy.
chmod ug+w "${DIST_ARCHIVE}"
)
fi
BAZEL_DIST_ARCHIVE="${DIST_ARCHIVE}"
BAZEL_SRC_DIR=
fi
if [[ -n "${BAZEL_DIST_ARCHIVE}" ]]; then
DIST_DIR="${BUILD_DIR}/bazel-extracted-dist"
if [[ -n "$SKIP_EXTRACT" ]]; then
[[ -d "${DIST_DIR}" ]] || die "--skip-extract used, but dist dir missing: ${DIST_DIR}"
echo "Skipping archive extraction"
else
rm -rf "${DIST_DIR:?}"/* && mkdir -p "${BUILD_DIR}"
echo "Extracting archive to $DIST_DIR"
run_step "Extracting distribution archive" unzip -q -o -d "${DIST_DIR}" "${BAZEL_DIST_ARCHIVE}"
fi
else
DIST_DIR="${BAZEL_DIST_DIR}"
fi
BAZEL_JAVAC_OPTS=()
BAZEL_JAVA_ARGS=(
# Use the local JDK (pointed to by JAVA_HOME) to build Bazel Java artifacts.
--tool_java_runtime_version=local_jdk
# Use the local JDK to run Bazel
--java_runtime_version=local_jdk
)
BAZEL_CC_ARGS=(
# Optimize and strip embedded C++ binaries
--compilation_mode=opt
--compiler=clang
--strip=always
)
if [[ "$JAVA_VERSION" -ge 23 ]]; then
# Bazel JDK 23 changed the default for annotations processing from "enabled"
# to "disabled" which breaks the Bazel build. The following is required to
# pass an extra options to all javac invocations to solve this issue.
BAZEL_JAVA_ARGS+=(--javacopt=-proc:full --host_javacopt=-proc:full)
# The following variable is used by the direct javac invocations performed
# by the "Building Bazel from scratch..." step.
BAZEL_JAVAC_OPTS=(-proc:full)
fi
EMBED_LABEL="${BAZEL_VERSION}-fuchsia"
# Generate a first version minimalistic of Bazel from the sources using
# the boot Bazel program.
BAZEL_STAGE1="${BUILD_DIR}/bazel-${BAZEL_VERSION}-stage1"
if [[ -n "${SKIP_STAGE1}" ]]; then
[[ -f "${BAZEL_STAGE1}" ]] || die "--skip-stage1 used but binary missing: ${BAZEL_STAGE1}"
echo "Skipping building stage 1 Bazel program."
else
echo "Building stage 1 Bazel program."
(
cd "${DIST_DIR}"
run_step "Building stage 1" env BAZEL_JAVAC_OPTS="${BAZEL_JAVAC_OPTS[*]}" EXTRA_BAZEL_ARGS="${BAZEL_JAVA_ARGS[*]} ${BAZEL_CC_ARGS[*]}" EMBED_LABEL="${EMBED_LABEL}" bash ./compile.sh
cp -rpf output/bazel "${BAZEL_STAGE1}"
)
fi
STAGE1_BAZEL_ARGS=(
# Reuse the same output base to save time.
--output_base="${BUILD_DIR}"/output_base
--output_user_root="${BUILD_DIR}"/output_user_root
)
# Now use the stage1 binary to rebuild the full Bazel binary which
# includes the embedded JDK. Trying to do that directly with the
# boot Bazel program can often fail. Note that this will download
# prebuilt Azul JDK images from the internet, as these are not
# included in the distribution image due to their large sizes.
# See $BAZEL_SRC/repositories.bzl for details.
BAZEL_STAGE2="${BUILD_DIR}/bazel-${BAZEL_VERSION}-fuchsia"
if [[ "$SKIP_STAGE2" ]]; then
[[ -f "${BAZEL_STAGE2}" ]] || die "--skip-stage2 used, but binary missing: ${BAZEL_STAGE2}"
echo "Skipping building stage 2 Bazel program."
else
echo "Building stage 2 Bazel program."
(
cd "${DIST_DIR}"
run_step "Building stage 2" "${BAZEL_STAGE1}" "${STAGE1_BAZEL_ARGS[@]}" build "${BAZEL_CC_ARGS[@]}" --stamp --embed_label "${EMBED_LABEL}" //src:bazel_jdk_minimal
cp -rpf bazel-bin/src/bazel_jdk_minimal "${BAZEL_STAGE2}"
)
fi
echo "Installing new binary to: ${INSTALL_DIR}"
# The Bazel binary is also a self-extracting ZIP archive. To speed
# up invocations, unpack it directly into an 'install_base' directory
# and generate a wrapper script that ensures the real Bazel binary
# is invoked with --install_base to point to it.
INSTALL_BASE="${INSTALL_DIR}/install_base"
mkdir -p "${INSTALL_BASE}"
unzip -q -o -d "${INSTALL_BASE}" "${BAZEL_STAGE2}"
# Bazel unpacks all files with mode 750, so enforce that here too.
chmod -R 0750 "${INSTALL_BASE}"
cp -f "${BAZEL_STAGE2}" "${INSTALL_DIR}/bazel-real"
# Bazel requires all timestamps in the install_base to be 10 years in
# the future (this is a cheap way to check for integrity). However timestamps
# are not preserved in the CIPD archive uploaded by the recipe (or maybe
# by CIPD during extraction?), so do not try to adjust them here, this
# will be handled by the wrapper script.
# Copy the wrapper script, which expects the real Bazel binary to be
# named `bazel-real` (this matches Linux Debian), and the install_base
# directory to be named `install_base`.
cp -f "${SCRIPT_DIR}"/bazel_wrapper_script.bash "${INSTALL_DIR}/bazel"
chmod a+x "${INSTALL_DIR}/bazel-real" "${INSTALL_DIR}/bazel"
cp -f "${DIST_DIR}/LICENSE" "${INSTALL_DIR}/LICENSE"
# Generate README.fuchsia while injecting the right version.
sed -e 's|@BAZEL_VERSION@|'"${BAZEL_VERSION}"'|g' \
"${SCRIPT_DIR}"/README.fuchsia.template > "${INSTALL_DIR}/README.fuchsia"
cleanup_temp_build_dir
declare -i DURATION=$(( SECONDS - START_TIME ))
declare -i MINUTES=$(( DURATION / 60 ))
declare -i SECS=$(( DURATION % 60 ))
echo "Done. Build took ${MINUTES}m${SECS}s."