|
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