summaryrefslogtreecommitdiff
path: root/wrappers/shadow-cc.sh
diff options
context:
space:
mode:
Diffstat (limited to 'wrappers/shadow-cc.sh')
-rwxr-xr-xwrappers/shadow-cc.sh345
1 files changed, 345 insertions, 0 deletions
diff --git a/wrappers/shadow-cc.sh b/wrappers/shadow-cc.sh
new file mode 100755
index 00000000..586c9d52
--- /dev/null
+++ b/wrappers/shadow-cc.sh
@@ -0,0 +1,345 @@
+#!/bin/bash
+
+set -euf -o pipefail
+
+top="#TOP#"
+shadow_top="#SHADOW_TOP#"
+
+orig_cc="#ORIG_TOOL#"
+shadow_cc="#SHADOW_TOOL#"
+
+errors=()
+warnings=()
+skips=()
+
+mode=()
+target=()
+opt_level=()
+lang=()
+stdin_input=()
+
+orig_out=()
+shadow_out=()
+orig_input=()
+shadow_input=()
+orig_opts=()
+shadow_opts=()
+
+dump_log ()
+{
+ (
+ set +u
+ IFS=";"
+ cat <<EOF
+errors=(${errors[@]})
+warnings=(${warnings[@]})
+skips=(${skips[@]})
+mode=(${mode[@]})
+target=(${target[@]})
+opt_level=(${opt_level[@]})
+lang=(${lang[@]})
+stdin_input=(${stdin_input[@]})
+orig_out=(${orig_out[@]})
+shadow_out=(${shadow_out[@]})
+orig_input=(${orig_input[@]})
+shadow_input=(${shadow_input[@]})
+orig_opts=($0 ${orig_opts[@]})
+shadow_opts=(${shadow_opts[@]})
+
+EOF
+ )
+}
+
+report_errors () {
+ res=$?
+ if [ $res != 0 ]; then
+ errors+=("wrapper failed with $res")
+ fi
+ if [ ${#errors[@]} != 0 ] \
+ || [ ${#warnings[@]} != 0 ] \
+ || [ ${#skips[@]} != 0 ]; then
+ (
+ /usr/bin/flock -e 9
+
+ if [ ${#errors[@]} != 0 ]; then
+ log=$shadow_top.errors
+ elif [ ${#warnings[@]} != 0 ]; then
+ log=$shadow_top.warnings
+ else
+ log=$shadow_top.skips
+ fi
+ dump_log >>$log
+ ) 9>>$shadow_top.lock
+ fi
+
+ # Log code-size
+ if [ ${#skips[@]} = 0 ] && [ -x "${orig_out[*]}" ]; then
+ if [ -x "${shadow_out[*]}" ]; then
+ text=$(/usr/bin/size "${shadow_out[*]}" | tail -n1 | awk '{ print $1 }')
+ else
+ text="-1"
+ fi
+ (
+ /usr/bin/flock -e 9
+ echo "${orig_out[*]},binary,$text" >> $shadow_top.size
+ ) 9>>$shadow_top.size
+ fi
+}
+
+trap report_errors EXIT
+
+while [ "$#" -gt 0 ]; do
+ opt="$1"
+ shift
+
+ orig_opts+=("$opt")
+
+ case "$opt" in
+ "-c"|"-S"|"-E") mode+=("$opt") ;;
+ "-o")
+ if [ "$#" -gt 0 ]; then
+ orig_out=("$1" "${orig_out[@]}")
+ orig_opts+=("$1")
+ shift
+ else
+ errors+=("$opt with no argument")
+ fi
+ ;;
+ "-O"*)
+ opt_level+=("$opt")
+ ;;
+ "-target")
+ if [ "$#" -gt 0 ]; then
+ target=("$1" "${target[@]}")
+ orig_opts+=("$1")
+ shift
+ else
+ errors+=("$opt with no argument")
+ fi
+ ;;
+ "-x")
+ if [ "$#" -gt 0 ]; then
+ lang+=("$1")
+ orig_opts+=("$1")
+ shift
+ else
+ errors+=("$opt with no argument")
+ fi
+ ;;
+ "-isystem"|"--sysroot"|"-MF"|"-MQ"|"-I"|"-include"|"-z"|"-D"|"-iquote")
+ if [ "$#" -gt 0 ]; then
+ orig_opts+=("$1")
+ shift
+ else
+ errors+=("$opt with no argument")
+ fi
+ ;;
+ "-")
+ orig_input+=("$opt")
+ stdin_input+=("$opt")
+ ;;
+ "-"*)
+ ;;
+ *)
+ orig_input+=("$opt")
+ ;;
+ esac
+done
+
+if [ ${#mode[@]} = 0 ]; then
+ # Link mode
+ mode=("-L")
+elif [ ${#mode[@]} != 1 ]; then
+ warnings+=("Several modes: ${mode[*]}")
+fi
+
+if [ ${#stdin_input[@]} = 1 ]; then
+ skips+=("Stdin input")
+ if [ x"${orig_input[*]}" != x"${stdin_input[*]}" ]; then
+ errors+=("Extra inputs in presence of stdin: ${orig_input[*]}")
+ fi
+ if [ x"${mode[*]}" != x"-E" ]; then
+ warnings+=("Stdin input with mode: ${mode[*]}")
+ fi
+elif [ ${#stdin_input[@]} -gt 1 ]; then
+ errors+=("Several stdin inputs")
+fi
+
+if [ ${#lang[@]} -gt 1 ]; then
+ warnings+=("Several -x LANG options: ${lang[*]}")
+fi
+
+if [ ${#opt_level[@]} -gt 1 ]; then
+ warnings+=("Several opt_levels: ${opt_level[*]}")
+fi
+
+if [ x"${mode[*]}" != x"-L" ]; then
+ if [ ${#orig_input[@]} != 1 ]; then
+ errors+=("Several inputs with mode ${mode[*]}: ${orig_input[*]}")
+ fi
+fi
+
+if [ ${#orig_out[@]} = 0 ]; then
+ skips+=("No orig_out")
+elif [ ${#orig_out[@]} != 1 ]; then
+ errors+=("Several orig_outs: ${orig_out[*]}")
+fi
+
+if [ "${#target[@]}" -gt 1 ]; then
+ errors+=("Several targets: ${target[*]}")
+fi
+
+if ! echo "${target[*]}" | grep -e "^aarch64" >/dev/null; then
+ skips+=("Skipping target: ${target[*]}")
+fi
+
+if [ ${#errors[@]} = 0 ] && [ ${#skips[@]} != 0 ] \
+ && [ ${#orig_out[@]} = 0 ] && [ ${#stdin_input[@]} != 0 ]; then
+ # Bionic has several cases where orig_cc [expectedly?] fails.
+ # Ignore these.
+ report_errors
+ exec "$orig_cc" "${orig_opts[@]}"
+fi
+
+print_shadow_path ()
+{
+ local path="$1"
+ local prefix="${2-}"
+
+ case "$path" in
+ "/dev/null") echo "$path"; return ;;
+ "/"*) errors+=("Absolute path: $path") ;;
+ esac
+
+ # Check that we are under $top
+ case "$(pwd -P | sed -e "s#^$top##")" in
+ "/"*) errors+=("Running outside of $top") ;;
+ esac
+
+ echo "$(pwd -P)/$path" | sed -e "s#$top#$shadow_top${prefix}#"
+}
+
+generate_shadow_rsp ()
+{
+ local orig_rsp="$1"
+
+ local shadow_rsp orig_file shadow_file
+
+ shadow_rsp=$(print_shadow_path "$orig_rsp")
+ mkdir -p "$(dirname "$shadow_rsp")"
+ rm -f "$shadow_rsp"
+
+ if [ "$(stat --format=%s "$orig_rsp")" = 0 ]; then
+ touch "$shadow_rsp"
+ else
+ local quote delim=""
+ while read -d '' -r orig_file; do
+ # unquote orig
+ case "$orig_file" in
+ \'*\') quote="'"; orig_file=${orig_file:1:-1} ;;
+ *) quote="" ;;
+ esac
+ shadow_file=$(print_shadow_path "$orig_file")
+ if ! [ -e "$shadow_file" ]; then
+ shadow_file="$orig_file"
+ fi
+ # quote shadow
+ echo -ne "$delim$quote$shadow_file$quote" >> "$shadow_rsp"
+ delim=" "
+ done < <({ cat "$orig_rsp"; echo; } | xargs printf '%s\0')
+ fi
+
+ echo "$shadow_rsp"
+}
+
+make_shadow_opts ()
+{
+ local opt
+ local shadow_file
+
+ while [ "$#" -gt 0 ]; do
+ opt="$1"
+ shift
+
+ case "$opt" in
+ "-o")
+ shadow_opts+=("$opt")
+ opt=$(print_shadow_path "$1")
+ shadow_out+=("$opt")
+ shift
+ ;;
+ "-fuse-ld=lld")
+ opt="-fuse-ld=$(dirname "$shadow_cc")/ld.lld"
+ ;;
+ "-target"|"-x"|"-isystem"|"--sysroot"|"-MF"|"-MQ"|"-I"|"-include"|"-z"|"-D"|"-iquote")
+ shadow_opts+=("$opt")
+ opt="$1"
+ shift
+ ;;
+ "-Werror"*) continue ;;
+ "-")
+ errors+=("Stdin input should have been skipped")
+ ;;
+ "-"*) ;;
+ "@"*".rsp")
+ opt="${opt#@}"
+ if [ x"$(basename "$opt" .rsp)" = x"$(basename "${orig_out[*]}")" ]; then
+ opt=$(generate_shadow_rsp "$opt")
+ else
+ errors+=("RSP file $opt does not match orig_out ${orig_out[*]}")
+ fi
+ opt="@$opt"
+ ;;
+ "@"*)
+ errors+=("Unexpected option: $opt")
+ opt="${opt#@}"
+ # shellcheck disable=SC2046
+ make_shadow_opts $(cat "$opt")
+ continue
+ ;;
+ *)
+ shadow_file=$(print_shadow_path "$opt")
+ if [ -e "$shadow_file" ]; then
+ opt="$shadow_file"
+ shadow_input+=("$shadow_file")
+ fi
+ ;;
+ esac
+ shadow_opts+=("$opt")
+ done
+}
+
+if [ ${#errors[@]} = 0 ] && [ ${#skips[@]} = 0 ]; then
+ make_shadow_opts "${orig_opts[@]}"
+fi
+
+if [ ${#errors[@]} = 0 ] && [ ${#skips[@]} = 0 ]; then
+ shadow_log=$(print_shadow_path "${orig_out[*]}" "-logs")
+
+ mkdir -p "$(dirname "${shadow_out[*]}")"
+ mkdir -p "$(dirname "$shadow_log")"
+
+ dump_log > "$shadow_log"
+ echo "$shadow_cc" "${shadow_opts[@]}" >> "$shadow_log"
+ "$shadow_cc" "${shadow_opts[@]}" >> "$shadow_log" 2>&1 &
+ shadow_res=0 && wait $! || shadow_res=$?
+
+ if [ $shadow_res != 0 ]; then
+ errors+=("shadow_cc failed with $shadow_res")
+ elif ! [ -e "${shadow_out[*]}" ]; then
+ errors+=("shadow_cc failed to generate output")
+ elif [ x"${shadow_out[*]}" != x"/dev/null" ]; then
+ shadow_link=$(IFS=""; print_shadow_path "${orig_out[*]}" "-${target[*]-default}${mode[*]}")
+ mkdir -p "$(dirname "$shadow_link")"
+ ln -s -f "${shadow_out[*]}" "$shadow_link"
+ fi
+fi
+
+#CCACHE# "$orig_cc" "${orig_opts[@]}" &
+orig_res=0 && wait $! || orig_res=$?
+
+if [ $orig_res != 0 ]; then
+ errors+=("orig_cc failed with $orig_res")
+fi
+
+exit $orig_res