run_include_next.sh (3177B)
1 #!/usr/bin/env bash 2 # test/pp/run_include_next.sh — regression for `#include_next` and 3 # `__has_include_next` (clang/GCC preprocessor extensions). 4 # 5 # #include_next resumes the header search in the directories *after* the one the 6 # current file was found in — the mechanism system-header wrappers use to pull in 7 # the "real" header of the same name further down the search path. It cannot be 8 # exercised by the single-`-I` golden corpus (test/pp/run.sh), so it gets its own 9 # two-directory harness here. 10 # 11 # Layout: dirs a/ and b/ both hold widget.h. Compiling `#include <widget.h>` with 12 # `-I a -I b` resolves to a/widget.h; its `#include_next <widget.h>` must then 13 # reach b/widget.h (the next dir), not loop back on itself. __has_include_next 14 # from a/ must see b/widget.h as present, and from b/ (the last dir) as absent. 15 # 16 # Host-target only: no sysroot needed (all headers are local). 17 18 set -u 19 20 ROOT=${KIT_TEST_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)} 21 KIT=${KIT:-"$ROOT/build/kit"} 22 export KIT 23 24 KIT_KIT_DIR="$ROOT/test/lib" 25 . "$ROOT/test/lib/kit_sh_kit.sh" 26 kit_require_kit pp-include-next 27 28 kit_report_init 29 work=$(mktemp -d "${TMPDIR:-/tmp}/kit-pp-incnext.XXXXXX") 30 trap 'rm -rf "$work"' EXIT 31 cd "$work" || exit 2 32 33 mkdir -p a b 34 cat > a/widget.h <<'EOF' 35 marker_a_before 36 #if __has_include_next(<widget.h>) 37 a_sees_next 38 #else 39 a_no_next 40 #endif 41 #include_next <widget.h> 42 marker_a_after 43 EOF 44 cat > b/widget.h <<'EOF' 45 marker_b 46 #if __has_include_next(<widget.h>) 47 b_sees_next 48 #else 49 b_no_next 50 #endif 51 EOF 52 printf '#include <widget.h>\ndone\n' > main.c 53 54 # emit_seq NAME : `kit cc -E -I a -I b main.c` must succeed and its output tokens 55 # must appear in the exact relative order of the remaining args. 56 emit_seq() { 57 name=$1; shift 58 if ! "$KIT" cc -E -I a -I b main.c -o "$work/$name.pp" \ 59 >"$work/$name.out" 2>"$work/$name.err"; then 60 kit_fail "$name" "kit cc -E failed; see $work/$name.err" 61 return 62 fi 63 # Collapse to one token per line, then check the needles appear in order. 64 tr -s '[:space:]' '\n' < "$work/$name.pp" > "$work/$name.toks" 65 local prev=0 line 66 for tok in "$@"; do 67 line=$(grep -nxF "$tok" "$work/$name.toks" | head -1 | cut -d: -f1) 68 if [ -z "$line" ]; then 69 kit_fail "$name" "missing token '$tok'"; return 70 fi 71 if [ "$line" -le "$prev" ]; then 72 kit_fail "$name" "token '$tok' out of order (line $line <= $prev)"; return 73 fi 74 prev=$line 75 done 76 kit_pass "$name" 77 } 78 79 # include_next from a/ reaches b/ (and a/ continues after); __has_include_next 80 # is true in a/ (b follows) and false in b/ (last dir). 81 emit_seq include_next_order \ 82 marker_a_before a_sees_next marker_b b_no_next marker_a_after done 83 84 # A token that must NOT appear: a/ must not loop back onto itself (a_no_next), 85 # and b/ must not think another widget.h follows it (b_sees_next). 86 if grep -qxF a_no_next "$work/include_next_order.toks" 2>/dev/null \ 87 || grep -qxF b_sees_next "$work/include_next_order.toks" 2>/dev/null; then 88 kit_fail include_next_no_loop "unexpected a_no_next/b_sees_next token" 89 else 90 kit_pass include_next_no_loop 91 fi 92 93 kit_summary pp-include-next 94 kit_exit