| #!/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. |
| |
| ### set up a build directory |
| |
| ## usage: fx oldset TARGET [OUTDIR] |
| ## [--board NAME|PATH] |
| ## [--product NAME|PATH] |
| ## [--monolith PATH] |
| ## [--preinstall PATH] |
| ## [--available PATH] |
| ## [--netboot] |
| ## [--args ARG] [--help-args [ARG]] [--variant VARIANT] |
| ## [--goma|--no-goma] [--no-ensure-goma] |
| ## [--goma-dir DIR] |
| ## [--ccache|--no-ccache] |
| ## [--release] |
| ## [--zircon-arg ARG] |
| ## |
| ## where TARGET is x64 or arm64 |
| ## |
| ## OUTDIR is the directory where the build output goes. |
| ## If it begins with `//` or `out/` then it's taken as relative to FUCHSIA_DIR. |
| ## Otherwise it should be an absolute path or a path relative to the current |
| ## working directory that winds up in `FUCHSIA_DIR/out`. |
| ## It defaults to `out/TARGET`. |
| ## |
| ## This is a wrapper around running `gn gen --check OUTDIR --args ...`. |
| ## If GN fails with an error, `fx oldset` does not change anything. |
| ## If GN succeeds, this also points subsequent `fx` commands at OUTDIR, |
| ## just as `fx use` does and ensures Goma is ready (if enabled). |
| ## |
| ## NAME|PATH can be provided as arguments to --board and --product. In the |
| ## case of NAME the name is searched for in //layer/board/NAME.gni, otherwise it |
| ## is treated as a PATH. |
| ## |
| ## optional arguments: |
| ## --board Use the given board target definition. Board |
| ## configurations are used to modulate hardware specific |
| ## behavior, such as configuring the set of drivers |
| ## included, or adding peripheral specific configurations. |
| ## If no board is given, a default board for the architecture |
| ## is selected from the current layer, e.g. |
| ## garnet/boards/x64.gni. |
| ## --product Include the given product in the build. Defaults to |
| ## the default product for the current layer (e.g., |
| ## "garnet/products/default.gni" for the Garnet layer). |
| ## Product configurations define a set of packages to be |
| ## included in the monolith, preinstall and available |
| ## package sets, as well as product oriented configurations. |
| ## --monolith Additional packages to be built and included in the |
| ## monolithic system image. Monolith is the set of packages |
| ## that make up an OTA image. |
| ## If the --monolith argument is given multiple times, |
| ## all the specified packages are included in this set. |
| ## These packages are added to the available set defined |
| ## by the board and product specifications. |
| ## --preinstall Additional packages to be built and included in the |
| ## system image alongside the monolithic system image. |
| ## Packages in preinstall are not part of OTA updates, |
| ## instead they are updated dynamically. |
| ## If the --preinstall argument is given multiple times, |
| ## all the specified packages are included in this set. |
| ## These packages are added to the available set defined |
| ## by the board and product specifications. |
| ## --available Additional packages to be built and included in the |
| ## set of packages available for pushing dynamically. |
| ## If the --available argument is given multiple times, |
| ## all the specified available are included in this set. |
| ## These packages are added to the available set defined |
| ## by the board and product specifications. |
| ## --netboot Ensure that a network ramboot image is always built. |
| ## --variant Pass a `select_variant=[VARIANT*,...]` GN build argument |
| ## collecting all the --variant arguments in order. |
| ## --fuzz-with Pass a sanitizer name, e.g. "--fuzz-with asan" to |
| ## enable ALL supporting fuzzers. Use --variant for |
| ## individual fuzzers, e.g. "--variant asan-fuzzer/foo". |
| ## --args Additional argument to pass to gn. If the --args |
| ## argument is given multiple times, all the specified |
| ## arguments are passed to gn. |
| ## N.B. Arguments must be expressed using GN's syntax. |
| ## In particular this means that for strings they must |
| ## be quoted with double-quotes, and the quoting must |
| ## survive, for example, the shell. Thus when passing |
| ## an argument that takes a string, pass it with |
| ## something like --args=foo='"bar"'. E.g., |
| ## bash$ fx oldset x64 --args=foo='"bar"' |
| ## More complicated arguments, e.g., lists, require |
| ## their own special syntax. See GN documentation |
| ## for the syntax of each kind of argument. |
| ## --help-args Display GN arguments documentation. If --help-args |
| ## is followed by a GN build argument identifier, just |
| ## that argument's documentation is displayed. |
| ## If --help-args is used alone, all GN build arguments |
| ## are displayed (lots of output). |
| ## This option requires an existing build directory. |
| ## --goma|--no-goma Whether to use the goma service during the build. Goma |
| ## attempts to make builds faster using remote build |
| ## servers. Defaults to detecting whether goma is installed |
| ## on your machine. |
| ## --no-ensure-goma Skip ensuring that goma is started when using goma. |
| ## --goma-dir The directory where goma is installed. Defaults to |
| ## ~/goma. |
| ## --ccache|--no-ccache Whether to use ccache during the build. Ccache attempts |
| ## to make builds faster by caching build artifacts. |
| ## Defaults to detecting whether the CCACHE_DIR environment |
| ## variable is set to a directory. |
| ## --ide Pass --ide=VALUE to gn when generating to create project |
| ## files usable with that IDE. Useful values include "vs" |
| ## for Visual Studio or "xcode" for Xcode. |
| ## --release an alias for "--args=is_debug=false" |
| ## |
| ## Deprecated flags: |
| ## |
| ## --zircon-arg ARG Additional arguments to pass to build-zircon.sh. |
| ## Can be given multiple times. |
| ## |
| ## Example: |
| ## |
| ## $ fx oldset x64 kitchensink --product ermine --available topaz/packages/kitchen_sink |
| ## -> architecture: x64 |
| ## build directory: out/kitchensink |
| ## board: topaz/boards/x64.gni |
| ## product: products/ermine.gni |
| ## available: topaz/packages/kitchen_sink (all other packages) |
| |
| source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh || exit $? |
| |
| function guess_config_location { |
| local config_type="$1" |
| local config_name="$2" |
| local __resultvar="$3" |
| |
| # If there is a vendor repository checked out, look there. |
| local vendor_repo |
| vendor_repo="$(${FUCHSIA_DIR}/build/gn/find_vendor_repo.py)" || return 1 |
| readonly vendor_repo |
| |
| if [[ -n "${vendor_repo}" ]]; then |
| guessed_config="${vendor_repo}/${config_type}/${config_name}.gni" |
| if [[ -a "${FUCHSIA_DIR}/${guessed_config}" ]]; then |
| eval "${__resultvar}"="${guessed_config}" |
| return |
| fi |
| fi |
| |
| # Otherwise look at the top level location |
| # Check if the configuration is in the top-level location |
| guessed_config="${config_type}/${config_name}.gni" |
| if [[ -a "${FUCHSIA_DIR}/${guessed_config}" ]]; then |
| eval "${__resultvar}"="${guessed_config}" |
| return |
| fi |
| |
| fx-error "Could not guess a ${config_type} configuration matching \"${config_name}\"" |
| fx-error "Please specify the full path from the root of the checkout such as" |
| fx-error "${config_type}/core.gni" |
| exit 1 |
| } |
| |
| |
| function main { |
| fx-standard-switches "$@" |
| set -- "${FX_ARGV[@]}" |
| |
| if [[ $# -lt 1 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| |
| local arch= |
| case $1 in |
| x64 | x86 | x64-64) |
| arch=x64 |
| ;; |
| arm64 | aarch64) |
| arch=arm64 |
| ;; |
| *) |
| # TODO(alainv): Add support for extracting arch from board configs. |
| fx-error Unknown target \"$1\" |
| fx-command-help |
| return 1 |
| ;; |
| esac |
| shift |
| |
| cd "${FUCHSIA_DIR}" |
| |
| local gn_cmd='gen' |
| local -a gn_switches=(--check) |
| local gn_args="target_cpu=\"${arch}\"" |
| local gn_after_args="" |
| local boards=() |
| local products=() |
| local available=() |
| local preinstall=() |
| local monolith=() |
| local zircon_args=(-v -g -t "$arch") |
| local build_dir= |
| local variant= |
| local use_goma |
| local goma_dir |
| local ensure_goma=1 |
| local ccache |
| while [[ $# -ne 0 ]]; do |
| case "$1" in |
| --board) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| boards+=("$2") |
| shift |
| ;; |
| --product) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| products+=("$2") |
| shift |
| ;; |
| --available) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| IFS=, available+=("$2") |
| shift |
| ;; |
| --preinstall) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| IFS=, preinstall+=("$2") |
| shift |
| ;; |
| --monolith) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| IFS=, monolith+=("$2") |
| shift |
| ;; |
| --zircon-arg) |
| fx-warn "--zircon-arg is deprecated, common use case is no longer required" |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| zircon_args+=("$2") |
| shift |
| ;; |
| --netboot) |
| gn_after_args+=" enable_netboot=true" |
| ;; |
| --goma) |
| use_goma=1 |
| ;; |
| --no-goma) |
| use_goma=0 |
| ;; |
| --no-ensure-goma) |
| ensure_goma=0 |
| ;; |
| --goma-dir) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| goma_dir=$2 |
| if [[ ! -d "${goma_dir}" ]]; then |
| fx-error "GOMA directory does not exist: "${goma_dir}"" |
| return 1 |
| fi |
| shift |
| ;; |
| --release) |
| gn_args+=" is_debug=false" |
| ;; |
| --variant) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| variant+="\"$2\"," |
| shift |
| ;; |
| --fuzz-with) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| variant+="{variant=\"$2-fuzzer\" target_type=[\"fuzzed_executable\"]}," |
| shift |
| ;; |
| --args) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| gn_args+=" $2" |
| shift |
| ;; |
| --help-args) |
| gn_cmd=args |
| if [[ $# -ge 2 ]] && [[ "$2" != '--*' ]]; then |
| gn_switches+=("--list=$2") |
| shift |
| else |
| gn_switches+=(--list) |
| fi |
| ;; |
| --ccache) |
| ccache=1 |
| ;; |
| --no-ccache) |
| ccache=0 |
| ;; |
| --ide) |
| if [[ $# -lt 2 ]]; then |
| fx-command-help |
| return 1 |
| fi |
| gn_switches+=("--ide=$2") |
| shift |
| ;; |
| --*) |
| fx-command-help |
| return 1 |
| ;; |
| *) |
| # A non-option argument is the build_dir, but there can be only one. |
| if [[ -n "$build_dir" ]]; then |
| fx-command-help |
| return 1 |
| fi |
| build_dir="$1" |
| ;; |
| esac |
| shift |
| done |
| |
| if [[ -z "${products}" ]]; then |
| # This is the default logic GN would use, but if a user specified --netboot |
| # we would short-circuit the logic, so repeat it here. |
| local vendor_repo |
| vendor_repo="$(${FUCHSIA_DIR}/build/gn/find_vendor_repo.py)" || return 1 |
| readonly vendor_repo |
| if [[ -n "${vendor_repo}" ]]; then |
| products+="${vendor_repo}/products/default.gni" |
| else |
| products+="products/core.gni" |
| fi |
| fi |
| |
| if [[ -z "${boards}" ]]; then |
| boards="boards/$arch.gni" |
| fi |
| |
| # Remove any trailing slash from build directory name. |
| build_dir="${build_dir%/}" |
| |
| local config_build_dir |
| case "$build_dir" in |
| '') |
| # Default is "//out/$target_cpu". Store it as relative. |
| config_build_dir="out/${arch}" |
| build_dir="${FUCHSIA_DIR}/${config_build_dir}" |
| ;; |
| //*|out/*) |
| # GN-style "source-relative" path or relative out/something. |
| config_build_dir="${build_dir#//}" |
| build_dir="${FUCHSIA_DIR}/${config_build_dir}" |
| ;; |
| *) |
| # Absolute or relative path. Canonicalize it to source-relative. |
| local abs_build_dir |
| abs_build_dir="$(cd "${build_dir%/*}" >/dev/null 2>&1; pwd)/${build_dir##*/}" || { |
| fx-error "Missing parent directories for ${build_dir}" |
| return 1 |
| } |
| if [[ "$abs_build_dir" == "${FUCHSIA_DIR}"/out/* ]]; then |
| config_build_dir="${abs_build_dir#${FUCHSIA_DIR}/}" |
| else |
| fx-warn "${abs_build_dir} is not a subdirectory of ${FUCHSIA_DIR}/out" |
| config_build_dir="$abs_build_dir" |
| fi |
| ;; |
| esac |
| |
| # If a goma directory wasn't specified explicitly then default to "~/goma". |
| if [[ -z "${goma_dir}" ]]; then |
| goma_dir="$HOME/goma" |
| fi |
| |
| # Automatically detect goma and ccache if not specified explicitly. |
| if [[ -z "${use_goma}" ]] && [[ -z "${ccache}" ]]; then |
| if [[ -d "${goma_dir}" ]]; then |
| use_goma=1 |
| elif [[ -n "${CCACHE_DIR}" ]] && [[ -d "${CCACHE_DIR}" ]]; then |
| ccache=1 |
| fi |
| fi |
| |
| if [[ -z "${boards}" ]]; then |
| guess_config_within_layer "boards" "${arch}" boards |
| fi |
| |
| for board in ${boards[@]}; do |
| if [[ ! -f "${FUCHSIA_DIR}/${board}" ]]; then |
| local guessed_board="" |
| guess_config_location "boards" "${board}" guessed_board |
| board="${guessed_board}" |
| fi |
| gn_args+=" import(\"//${board}\")" |
| done |
| |
| # Add goma or ccache settings as appropriate. |
| if [[ "${use_goma}" -eq 1 ]]; then |
| gn_args+=" use_goma=true goma_dir=\"${goma_dir}\"" |
| zircon_args+=(use_goma=true "goma_dir=\"${goma_dir}\"") |
| elif [[ "${ccache}" -eq 1 ]]; then |
| gn_args+=" use_ccache=true" |
| fi |
| |
| for product in ${products[@]}; do |
| if [[ ! -a "${FUCHSIA_DIR}/${product}" ]]; then |
| local guessed_product="" |
| guess_config_location "products" "${product}" guessed_product |
| product="${guessed_product}" |
| fi |
| gn_args+=" import(\"//${product}\")" |
| done |
| |
| gn_args+=" if (!defined(available)) { available = [] }" |
| gn_args+=" available+=[" |
| for package in ${available[@]}; do |
| gn_args+="\"${package}\"," |
| done |
| gn_args+="]" |
| |
| gn_args+=" if (!defined(preinstall)) { preinstall = [] }" |
| gn_args+=" preinstall+=[" |
| for package in ${preinstall[@]}; do |
| gn_args+="\"${package}\"," |
| done |
| gn_args+="]" |
| gn_args+=" if (!defined(monolith)) { monolith = [] }" |
| gn_args+=" monolith+=[" |
| for package in ${monolith[@]}; do |
| gn_args+="\"${package}\"," |
| done |
| gn_args+="]" |
| |
| if [[ -n "${variant}" ]]; then |
| gn_args+=" select_variant=[${variant}]" |
| fi |
| |
| gn_args+="${gn_after_args}" |
| |
| # Using a subshell with -x prints out the gn command precisely with shell |
| # quoting so a cut&paste to the command line works. Always show the real |
| # meaning of what this script does so everyone learns how GN works. |
| ( |
| set -x -e |
| # Zircon's `gn gen` phase has to be done before Fuchsia's `gn gen`. |
| # The former produces the legacy-$cpu.json file consumed by the latter. |
| "${FUCHSIA_DIR}/scripts/build-zircon.sh" "${zircon_args[@]}" |
| "${FUCHSIA_DIR}/buildtools/gn" ${gn_cmd} "${build_dir}" \ |
| "${gn_switches[@]}" --args="${gn_args}" "$@" |
| # If GN failed, don't update .config. |
| ) || return |
| |
| fx-config-write "${config_build_dir}" |
| |
| if [[ "${use_goma}" -eq 1 ]] && [[ "${ensure_goma}" -eq 1 ]]; then |
| if ! [[ $("${goma_dir}/gomacc" port) =~ ^[0-9]+$ ]]; then |
| "${goma_dir}/goma_ctl.py" ensure_start || return $? |
| fi |
| fi |
| } |
| |
| main "$@" |