|  | 
| 1 |  | -#!/bin/bash | 
|  | 1 | +#!/bin/sh | 
| 2 | 2 | # | 
| 3 | 3 | # Copyright 2021 The Bazel Authors. All rights reserved. | 
| 4 | 4 | # | 
|  | 
| 14 | 14 | # See the License for the specific language governing permissions and | 
| 15 | 15 | # limitations under the License. | 
| 16 | 16 | 
 | 
| 17 |  | -# shellcheck disable=SC1083 | 
|  | 17 | +SCRIPT_DIR=$(dirname "$0") | 
| 18 | 18 | 
 | 
| 19 |  | -set -euo pipefail | 
|  | 19 | +# Search for `bash` on the system, and then execute cc_wrapper_inner.sh with | 
|  | 20 | +# it. | 
| 20 | 21 | 
 | 
| 21 |  | -CLEANUP_FILES=() | 
|  | 22 | +# Attempt #1: /bin/bash -- present on FHS-compliant systems, but notably absent | 
|  | 23 | +# on others, including NixOS. | 
|  | 24 | +test -e /bin/bash && exec /bin/bash "${SCRIPT_DIR}"/cc_wrapper_inner.sh "$@" | 
| 22 | 25 | 
 | 
| 23 |  | -function cleanup() { | 
| 24 |  | -  if [[ ${#CLEANUP_FILES[@]} -gt 0 ]]; then | 
| 25 |  | -    rm -f "${CLEANUP_FILES[@]}" | 
| 26 |  | -  fi | 
| 27 |  | -} | 
|  | 26 | +# Attempt #2: /usr/bin/env bash -- /usr/bin/env is required by POSIX, but some | 
|  | 27 | +# callers to the LLVM toolchain, such as rules_rust, clear $PATH and leave | 
|  | 28 | +# nothing for /usr/bin/env to search for. | 
|  | 29 | +test -e /usr/bin/env && test /usr/bin/env bash true && | 
|  | 30 | +  exec /usr/bin/env bash "${SCRIPT_DIR}"/cc_wrapper_inner.sh "$@" | 
| 28 | 31 | 
 | 
| 29 |  | -trap cleanup EXIT | 
|  | 32 | +# Attempt #3: Try `command -v`. | 
|  | 33 | +CMD=$(command -v bash) | 
|  | 34 | +$? && exec "${CMD}" "${SCRIPT_DIR}"/cc_wrapper_inner.sh "$@" | 
| 30 | 35 | 
 | 
| 31 |  | -# See note in toolchain/internal/configure.bzl where we define | 
| 32 |  | -# `wrapper_bin_prefix` for why this wrapper is needed. | 
| 33 |  | - | 
| 34 |  | -# this script is located at either | 
| 35 |  | -# - <execroot>/external/<repo_name>/bin/cc_wrapper.sh | 
| 36 |  | -# - <runfiles>/<repo_name>/bin/cc_wrapper.sh | 
| 37 |  | -# The clang is located at | 
| 38 |  | -# - <execroot>/external/<repo_name2>/bin/clang | 
| 39 |  | -# - <runfiles>/<repo_name2>/bin/clang | 
| 40 |  | -# | 
| 41 |  | -# In both cases, getting to clang can be done via | 
| 42 |  | -# Finding the current dir of this script, | 
| 43 |  | -# - <execroot>/external/<repo_name>/bin/ | 
| 44 |  | -# - <runfiles>/<repo_name>/bin/ | 
| 45 |  | -# going back 2 directories | 
| 46 |  | -# - <execroot>/external | 
| 47 |  | -# - <runfiles> | 
| 48 |  | -# | 
| 49 |  | -# Going into %{toolchain_path_prefix} without the `external/` prefix + `bin/clang` | 
| 50 |  | -# | 
| 51 |  | - | 
| 52 |  | -dirname_shim() { | 
| 53 |  | -  local path="$1" | 
| 54 |  | - | 
| 55 |  | -  # Remove trailing slashes | 
| 56 |  | -  path="${path%/}" | 
| 57 |  | - | 
| 58 |  | -  # If there's no slash, return "." | 
| 59 |  | -  if [[ "${path}" != */* ]]; then | 
| 60 |  | -    echo "." | 
| 61 |  | -    return | 
| 62 |  | -  fi | 
| 63 |  | - | 
| 64 |  | -  # Remove the last component after the final slash | 
| 65 |  | -  path="${path%/*}" | 
| 66 |  | - | 
| 67 |  | -  # If it becomes empty, it means root "/" | 
| 68 |  | -  echo "${path:-/}" | 
| 69 |  | -} | 
| 70 |  | - | 
| 71 |  | -if [[ "${BASH_SOURCE[0]}" == "/"* ]]; then | 
| 72 |  | -  bash_source_abs="$(realpath "${BASH_SOURCE[0]}")" | 
| 73 |  | -  pwd_abs="$(realpath ".")" | 
| 74 |  | -  bash_source_rel=${bash_source_abs#"${pwd_abs}/"} | 
| 75 |  | -else | 
| 76 |  | -  bash_source_rel="${BASH_SOURCE[0]}" | 
| 77 |  | -fi | 
| 78 |  | -script_dir=$(dirname_shim "${bash_source_rel}") | 
| 79 |  | -toolchain_path_prefix="%{toolchain_path_prefix}" | 
| 80 |  | - | 
| 81 |  | -# Sometimes this path may be an absolute path in which case we dont do anything because | 
| 82 |  | -# This is using the host toolchain to build. | 
| 83 |  | -if [[ ${toolchain_path_prefix} != /* ]]; then | 
| 84 |  | -  # shellcheck disable=SC2312 | 
| 85 |  | -  toolchain_path_prefix="$(dirname_shim "$(dirname_shim "${script_dir}")")/${toolchain_path_prefix#external/}" | 
| 86 |  | -fi | 
| 87 |  | - | 
| 88 |  | -if [[ ! -f ${toolchain_path_prefix}bin/clang ]]; then | 
| 89 |  | -  echo >&2 "ERROR: could not find clang; PWD=\"${PWD}\"; PATH=\"${PATH}\"; toolchain_path_prefix=${toolchain_path_prefix}." | 
| 90 |  | -  exit 5 | 
| 91 |  | -fi | 
| 92 |  | - | 
| 93 |  | -OUTPUT= | 
| 94 |  | - | 
| 95 |  | -function parse_option() { | 
| 96 |  | -  local -r opt="$1" | 
| 97 |  | -  if [[ "${OUTPUT}" = "1" ]]; then | 
| 98 |  | -    OUTPUT=${opt} | 
| 99 |  | -  elif [[ "${opt}" = "-o" ]]; then | 
| 100 |  | -    # output is coming | 
| 101 |  | -    OUTPUT=1 | 
| 102 |  | -  fi | 
| 103 |  | -} | 
| 104 |  | - | 
| 105 |  | -function sanitize_option() { | 
| 106 |  | -  local -r opt=$1 | 
| 107 |  | -  if [[ ${opt} == */cc_wrapper.sh ]]; then | 
| 108 |  | -    printf "%s" "${toolchain_path_prefix}bin/clang" | 
| 109 |  | -  elif [[ ${opt} =~ ^-fsanitize-(ignore|black)list=[^/] ]] && [[ ${script_dir} == /* ]]; then | 
| 110 |  | -    # shellcheck disable=SC2206 | 
| 111 |  | -    parts=(${opt/=/ }) # Split flag name and value into array. | 
| 112 |  | -    # shellcheck disable=SC2312 | 
| 113 |  | -    printf "%s" "${parts[0]}=$(dirname_shim "$(dirname_shim "$(dirname_shim "${script_dir}")")")/${parts[1]}" | 
| 114 |  | -  else | 
| 115 |  | -    printf "%s" "${opt}" | 
| 116 |  | -  fi | 
| 117 |  | -} | 
| 118 |  | - | 
| 119 |  | -cmd=() | 
| 120 |  | -for ((i = 0; i <= $#; i++)); do | 
| 121 |  | -  if [[ ${!i} == @* && -r "${i:1}" ]]; then | 
| 122 |  | -    # Create a new, sanitized file. | 
| 123 |  | -    tmpfile=$(mktemp) | 
| 124 |  | -    CLEANUP_FILES+=("${tmpfile}") | 
| 125 |  | -    while IFS= read -r opt; do | 
| 126 |  | -      opt="$( | 
| 127 |  | -        set -e | 
| 128 |  | -        sanitize_option "${opt}" | 
| 129 |  | -      )" | 
| 130 |  | -      parse_option "${opt}" | 
| 131 |  | -      echo "${opt}" >>"${tmpfile}" | 
| 132 |  | -    done <"${!i:1}" | 
| 133 |  | -    cmd+=("@${tmpfile}") | 
| 134 |  | -  else | 
| 135 |  | -    opt="$( | 
| 136 |  | -      set -e | 
| 137 |  | -      sanitize_option "${!i}" | 
| 138 |  | -    )" | 
| 139 |  | -    parse_option "${opt}" | 
| 140 |  | -    cmd+=("${opt}") | 
| 141 |  | -  fi | 
| 142 |  | -done | 
| 143 |  | - | 
| 144 |  | -# Call the C++ compiler. | 
| 145 |  | -"${cmd[@]}" | 
| 146 |  | - | 
| 147 |  | -# Generate an empty file if header processing succeeded. | 
| 148 |  | -if [[ "${OUTPUT}" == *.h.processed ]]; then | 
| 149 |  | -  echo -n >"${OUTPUT}" | 
| 150 |  | -fi | 
|  | 36 | +echo >&2 'Failed to find bash at /bin/bash or in PATH.' | 
|  | 37 | +exit 1 | 
0 commit comments