|  | #!/bin/bash | 
|  | # Copyright lowRISC contributors. | 
|  | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | set -o errexit | 
|  | set -o pipefail | 
|  | set -o nounset | 
|  |  | 
|  | # meson_init.sh configures OpenTitan's Meson build system. Rather than calling | 
|  | # Meson directly, this script should be used instead, since it handles things | 
|  | # that Meson does not out of the box, such as: | 
|  | # - The RISC-V toolchain. | 
|  | # - Idempotence. | 
|  | # - Building for multiple device platforms. | 
|  | # | 
|  | # This script's semantics for creating build directories are as follows: | 
|  | # - By default, this script will create any missing build directories and | 
|  | #   configure them. It is idempotent: if there is no work to be done, nothing | 
|  | #   will change and this script will exit successfully. | 
|  | # - Passing -r will reconfigure existing build directories. This should be used | 
|  | #   when editing meson.build files. | 
|  | # - Passing -f will erase existing build directories. This should be used when | 
|  | #   existing configuration is completely broken, or a clean build is desired | 
|  | #   (neither of these should be necessary). | 
|  | # - Passing -A will explicitly disable idempotence, and cause the script to exit | 
|  | #   if a build directory already exists. This should be used only in CI, where | 
|  | #   such error-checking is desireable. | 
|  | # | 
|  | # Note that only the first option above is actually guaranteed to be idempotent. | 
|  |  | 
|  | . util/build_consts.sh | 
|  |  | 
|  | echo "Detected \$REPO_TOP at $REPO_TOP." | 
|  | echo "Object directory set at $OBJ_DIR." | 
|  | echo "Binary directory set at $BIN_DIR." | 
|  | echo "OpenTitan version: $OT_VERSION" | 
|  | echo | 
|  |  | 
|  | function usage() { | 
|  | cat << USAGE | 
|  | Configure Meson build targets. | 
|  |  | 
|  | Usage: $0 [-r|-f|-A|-K|-c] [-T PATH] [-t FILE] | 
|  |  | 
|  | -A: Assert that no build dirs exist when running this command. | 
|  | -c: Enable coverage (requires clang). | 
|  | -f: Force a reconfiguration by removing existing build dirs. | 
|  | -K: Keep include search paths as generated by Meson. | 
|  | -r: Reconfigure build dirs, if they exist. | 
|  | -t FILE: Configure Meson with toolchain configuration FILE | 
|  | -T PATH: Build tock from PATH rather than the remote repository. | 
|  |  | 
|  | USAGE | 
|  | } | 
|  |  | 
|  | readonly DEFAULT_RISCV_TOOLS=/tools/riscv | 
|  | TOOLCHAIN_PATH="${TOOLCHAIN_PATH:-$DEFAULT_RISCV_TOOLS}" | 
|  |  | 
|  | FLAGS_assert=false | 
|  | FLAGS_force=false | 
|  | FLAGS_reconfigure="" | 
|  | FLAGS_keep_includes=false | 
|  | FLAGS_specified_toolchain_file=false | 
|  | FLAGS_coverage=false | 
|  | ARG_toolchain_file="${TOOLCHAIN_PATH}/meson-riscv32-unknown-elf-clang.txt" | 
|  | ARG_tock_dir="" | 
|  | # `getopts` usage | 
|  | # - The initial colon in the optstring is to suppress the default error | 
|  | #   handling. | 
|  | # - The remaining options are specified in alphabetical order, and the case | 
|  | #   statement should match this order. | 
|  | # - Only options that take an argument should have a following colon. | 
|  | # - The case statement contains two additional cases: | 
|  | #   - when `$flag` = `?`, this is an unexpected option. | 
|  | #   - when `$flag` = `:`, this is the case that a flag which requires an | 
|  | #     argument is not provided one. In both cases, `$OPTARG` contains the | 
|  | #     relevant parsed option. | 
|  | # - After option parsing is finished, we `shift` by `$OPTIND - 1` so that the | 
|  | #   remaining (unprocessed) arguments are in `$@` (and $1, $2, $3 etc.). | 
|  | while getopts ':AcfKrt:T:' flag; do | 
|  | case "${flag}" in | 
|  | A) FLAGS_assert=true;; | 
|  | c) FLAGS_coverage=true;; | 
|  | f) FLAGS_force=true;; | 
|  | K) FLAGS_keep_includes=true;; | 
|  | r) FLAGS_reconfigure="--reconfigure";; | 
|  | t) FLAGS_specified_toolchain_file=true | 
|  | ARG_toolchain_file="${OPTARG}";; | 
|  | T) ARG_tock_dir="${OPTARG}";; | 
|  | \?) echo "Unexpected option: -${OPTARG}" >&2 | 
|  | usage | 
|  | exit 1 | 
|  | ;; | 
|  | :) echo "Option -${OPTARG} requires a path argument" >&2 | 
|  | usage | 
|  | exit 1 | 
|  | ;; | 
|  | *) echo "Internal Error: Unhandled option: -${flag}" >&2 | 
|  | exit 1 | 
|  | ;; | 
|  | esac | 
|  | done | 
|  | shift $((OPTIND - 1)) | 
|  |  | 
|  | # We do not accept additional arguments. | 
|  | if [[ "$#" -gt 0 ]]; then | 
|  | echo "Unexpected arguments:" "$@" >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if [[ ! -n "$(command -v meson)" ]]; then | 
|  | echo "Unable to find meson. Please install meson before running this command." >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if [[ ! -n "$(command -v ninja)" ]]; then | 
|  | echo "Unable to find ninja. Please install ninja before running this command." >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if [[ "${FLAGS_force}" == true ]]; then | 
|  | rm -rf "$OBJ_DIR" | 
|  | rm -rf "$BIN_DIR" | 
|  | fi | 
|  |  | 
|  | if [[ "${FLAGS_assert}" == true ]]; then | 
|  | if [[ -e "$OBJ_DIR" ]]; then | 
|  | echo "Object directory at $OBJ_DIR already exists. Aborting." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | if [[ -e "$BIN_DIR" ]]; then | 
|  | echo "Binary directory at $BIN_DIR already exists. Aborting." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | TOCK_LOCAL=false | 
|  | if [[ ! -z "${ARG_tock_dir}" ]]; then | 
|  | TOCK_LOCAL=true | 
|  |  | 
|  | if [[ ! -d "${ARG_tock_dir}" ]]; then | 
|  | echo "Referenced Tock directory ${ARG_tock_dir} doesn't exist. Aborting." >&2 | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | if [[ ! -f "${TOCK_SYMLINK}" || -L "${TOCK_SYMLINK}" ]]; then | 
|  | echo "Creating symlink to Tock project at ${ARG_tock_dir}." | 
|  | ln -sf "${ARG_tock_dir}" "${TOCK_SYMLINK}" | 
|  | elif [[ -d "${TOCK_SYMLINK}" ]]; then | 
|  | echo "Tock directory $TOCK_SYMLINK exists in place. Leaving as is." | 
|  | else | 
|  | echo "Placing Tock at ${TOCK_SYMLINK} would clobber something. Aborting." >&2 | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | reconf="${FLAGS_reconfigure}" | 
|  |  | 
|  | if [[ ! -d "$OBJ_DIR" ]]; then | 
|  | echo "Output directory does not exist at $OBJ_DIR; creating." >&2 | 
|  | mkdir -p "$OBJ_DIR" | 
|  | reconf="" | 
|  | elif [[ -z "$reconf" ]]; then | 
|  | echo "Output directory already exists at $OBJ_DIR; skipping." >&2 | 
|  | fi | 
|  |  | 
|  | if [[ -f "${ARG_toolchain_file}" ]]; then | 
|  | echo "Using meson toolchain file at $ARG_toolchain_file." >&2 | 
|  | else | 
|  | if [[ "${FLAGS_specified_toolchain_file}" == true ]]; then | 
|  | echo "Unable to find meson toolchain file at $ARG_toolchain_file. Aborting." >&2 | 
|  | exit 1 | 
|  | else | 
|  | cross_file="$OBJ_DIR/toolchain-configured.txt" | 
|  | cp toolchain.txt "$cross_file" | 
|  | perl -pi -e "s#$DEFAULT_RISCV_TOOLS#$TOOLCHAIN_PATH#g" "$cross_file" | 
|  | touch -r toolchain.txt "$cross_file" | 
|  | echo "Set up toolchain file at $cross_file." >&2 | 
|  | ARG_toolchain_file="${cross_file}" | 
|  | fi | 
|  | fi | 
|  |  | 
|  | mkdir -p "$BIN_DIR" | 
|  | set -x | 
|  | meson $reconf \ | 
|  | -Dot_version="$OT_VERSION" \ | 
|  | -Dbin_dir="$BIN_DIR" \ | 
|  | -Dtock_local="$TOCK_LOCAL" \ | 
|  | -Dkeep_includes="$FLAGS_keep_includes" \ | 
|  | -Dcoverage="$FLAGS_coverage" \ | 
|  | --cross-file="$ARG_toolchain_file" \ | 
|  | "$OBJ_DIR" |