|
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