| #!/bin/bash |
| # Copyright 2017 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. |
| |
| #### CATEGORY=Build |
| ### Run Ninja to build Fuchsia |
| |
| ## usage: fx build [--log FILENAME] [-SWITCH...] | TARGET ...] |
| ## |
| ## This runs Ninja after performing a few correctness checks for the Fuchsia build. |
| ## |
| ## optional arguments: |
| ## --log LOGFILE Print debug information to LOGFILE. Please attach |
| ## the resulting file when reporting bugs. |
| ## --fint-params-path PATH Path to a fint params file used by an infra |
| ## builder. This is useful for reproducing the exact |
| ## set of targets built by the infrastructure. |
| ## |
| ## Other arguments are passed through to Ninja. |
| ## Run `fx build -h` to see Ninja argument details. |
| |
| source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh || exit $? |
| fx-config-read |
| |
| function main { |
| local switches=() fuchsia_targets=() |
| local log_file is_logging fint_params_path |
| is_logging=false |
| while [[ $# -gt 0 ]]; do |
| case "$1" in |
| --log) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| log_file="$2" |
| if [[ -f "${log_file}" ]]; then |
| fx-error "File \"${log_file}\" exists." |
| return 1 |
| fi |
| # if ! touch "${log_file}"; then |
| # fx-error "Cannot create logfile \"${log_file}\"" |
| # return 1 |
| # fi |
| is_logging=true |
| shift |
| ;; |
| --fint-params-path) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| fint_params_path="$2" |
| shift |
| ;; |
| # These Ninja switches take an argument. |
| -[Cfjkldtw]) |
| switches+=("$1" "$2") |
| shift |
| ;; |
| -*) |
| switches+=("$1") |
| ;; |
| *) |
| fuchsia_targets+=("$1") |
| ;; |
| esac |
| shift |
| done |
| |
| if [ -n "${fint_params_path}" ]; then |
| if [ ${#switches[@]} -gt 0 ]; then |
| fx-error "It's invalid to specify extra Ninja flags along with --fint-params-path." |
| exit 1 |
| elif [ ${#fuchsia_targets[@]} -gt 0 ]; then |
| fx-error "It's invalid to specify targets along with --fint-params-path." |
| exit 1 |
| fi |
| fi |
| |
| if [[ "${is_logging}" = true ]]; then |
| # log file header with relevant environment information |
| { |
| TIMESTAMP="$(date +%Y%m%d_%H%M%S)" |
| echo "Build initiated at ${TIMESTAMP}" |
| echo |
| echo "------ GIT QUICK INFO ------" |
| echo "$ git status" |
| git --no-optional-locks --git-dir="${FUCHSIA_DIR}/.git" status |
| echo |
| echo "$ git rev-parse JIRI_HEAD" |
| git --no-optional-locks --git-dir="${FUCHSIA_DIR}/.git" rev-parse JIRI_HEAD |
| echo |
| echo "------ CONTENTS OF args.gn ------" |
| echo "$ cat ${FUCHSIA_BUILD_DIR}/args.gn" |
| echo |
| cat "${FUCHSIA_BUILD_DIR}/args.gn" |
| echo |
| } >> "${log_file}" 2>&1 |
| |
| # tee stdout and stderr to log_file |
| exec > >(tee -a "${log_file}") 2>&1 |
| fi |
| |
| # A change to any of these might mean things are now done differently enough |
| # that ninja's automatic re-gen rule might not be triggered or might not work |
| # properly if it is triggered. So preemptively force a re-gen if that seems |
| # like a plausible possibility. |
| local -r landmines=("$PREBUILT_GN" |
| "$FUCHSIA_DIR/tools/devshell/build" |
| "$FUCHSIA_DIR/tools/devshell/lib/vars.sh" |
| ) |
| local mine |
| for mine in "${landmines[@]}"; do |
| if [[ "$mine" -nt "${FUCHSIA_BUILD_DIR}/build.ninja" ]]; then |
| if [[ "${is_logging}" = true ]]; then |
| echo -e "\\n------ RUNNING gn gen ------" |
| fi |
| echo >&2 "Re-running gn gen first ($mine changed)" |
| fx-gen || return |
| break |
| fi |
| done |
| |
| if [[ ! -d "$FUCHSIA_BUILD_DIR" ]]; then |
| if [[ "${is_logging}" = true ]]; then |
| echo -e "\\n------ RUNNING gn gen ------" |
| fi |
| echo >&2 "Re-running gn gen first (missing $FUCHSIA_BUILD_DIR)" |
| fx-gen || return |
| else |
| # We have a build directory, execute force clean checker, usually a no-op |
| "$FUCHSIA_DIR/scripts/fuchsia-vendored-python3.8" \ |
| "$FUCHSIA_DIR/build/force_clean/force_clean_if_needed.py" \ |
| --gn-bin "$PREBUILT_GN" \ |
| --checkout-dir "$FUCHSIA_DIR" \ |
| --build-dir "$FUCHSIA_BUILD_DIR" |
| fi |
| |
| local status |
| |
| if [[ "${is_logging}" = true ]]; then |
| local tool="ninja" |
| if [ -n "${fint_params_path}" ]; then |
| tool="fint build" |
| fi |
| echo -e "\\n------ RUNNING ${tool} ------" |
| fi |
| |
| if [ -n "${fint_params_path}" ]; then |
| readonly fint="${FX_CACHE_DIR}/fint" |
| "$FUCHSIA_DIR/tools/integration/bootstrap.sh" -o "$fint" || exit $? |
| # It's not ideal that we resort to constructing the textproto file as a |
| # string, but it's easier than writing a Go tool solely for the purpose of |
| # constructing a protobuf with a couple top-level string fields set. |
| local rbe_wrapper=() |
| if fx-rbe-enabled; then rbe_wrapper=("${RBE_WRAPPER[@]}"); fi |
| "${rbe_wrapper[@]}" "$fint" -log-level=error build -static="${fint_params_path}" -context=<(echo " |
| checkout_dir: \"${FUCHSIA_DIR}\" |
| build_dir: \"${FUCHSIA_BUILD_DIR}\" |
| ") |
| else |
| (fx-run-ninja "${is_logging}" "$PREBUILT_NINJA" -C "${FUCHSIA_BUILD_DIR}" \ |
| "${switches[@]}" "${fuchsia_targets[@]}") |
| fi |
| |
| status=$? |
| if [[ "${status}" -ne 0 ]]; then |
| goma-check |
| fi |
| |
| exit-with-message |
| } |
| |
| function goma-check { |
| if grep -q "^ *use_goma = true" "${FUCHSIA_BUILD_DIR}/args.gn"; then |
| if ! fx-command-run goma_ctl status >/dev/null 2>&1; then |
| fx-error "Goma is enabled but not started. Please run 'fx goma' first." |
| fi |
| fi |
| } |
| |
| function exit-with-message { |
| if [[ "${is_logging}" = true ]]; then |
| fx-warn "Debug log saved to ${log_file}. Please attach this file when reporting a bug" |
| elif [[ "${status}" -ne 0 ]]; then |
| echo >&2 "Hint: run \`fx build\` with the option \`--log LOGFILE\` to generate a debug log if you are reporting a bug." |
| fi |
| exit "${status}" |
| } |
| |
| main "$@" |