summaryrefslogtreecommitdiff
path: root/tests/t0057-missing-generated-dependencies.sh
blob: 7ad50015eb0f1b4c4b37870971ce59580b6dd565 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/bin/sh
set -eu

base="${TMPDIR-/tmp}/mcpu-cpp-missing-generated-deps-$$"
mkdir -p "$base/user" "$base/sys"
trap 'rm -rf "$base"' EXIT HUP INT TERM

cd "$base"

cat > main.c <<'EOT'
#include "generated-user.h"
#include <generated-system.h>
#define GENERATED_MACRO_HEADER "generated-macro.h"
#include GENERATED_MACRO_HEADER
EOT

# Without -MG, the first unresolved include remains a hard error.
if "$MCPU_CPP" --no-config -M main.c > no-mg.out 2> no-mg.err; then
  echo "missing include unexpectedly succeeded without -MG" >&2
  exit 1
fi
grep "cannot find include file 'generated-user.h'" no-mg.err >/dev/null

# -M -MG records unresolved operands exactly as written and does not diagnose
# them as missing files.  Macro-expanded include operands use their expanded
# filename.
"$MCPU_CPP" --no-config -M -MG main.c > M.d 2> M.err
test ! -s M.err
grep '^main\.o:' M.d >/dev/null
for f in main.c generated-user.h generated-system.h generated-macro.h
do
  grep -F "$f" M.d >/dev/null || {
    echo "-M -MG omitted unresolved dependency: $f" >&2
    exit 1
  }
done

# -MM retains unresolved quoted/user includes but filters unresolved angle
# includes as system-class dependencies.
"$MCPU_CPP" --no-config -MM -MG main.c > MM.d
grep -F 'generated-user.h' MM.d >/dev/null
grep -F 'generated-macro.h' MM.d >/dev/null
if grep -F 'generated-system.h' MM.d >/dev/null; then
  echo "-MM -MG kept unresolved angle/system dependency" >&2
  exit 1
fi

# Missing dependencies reached from a real system header inherit system
# context, even when the nested directive uses quotes.  User-header quoted
# descendants remain user dependencies.
cat > sys/system-parent.h <<'EOT'
#include "generated-from-system.h"
EOT
cat > user/user-parent.h <<'EOT'
#include "generated-from-user.h"
EOT
cat > nested.c <<'EOT'
#include <system-parent.h>
#include <user-parent.h>
EOT

"$MCPU_CPP" --no-config -MM -MG -I user -isystem sys nested.c > nested-MM.d
grep -F 'user/user-parent.h' nested-MM.d >/dev/null
grep -F 'generated-from-user.h' nested-MM.d >/dev/null
if grep -F 'sys/system-parent.h' nested-MM.d >/dev/null ||
   grep -F 'generated-from-system.h' nested-MM.d >/dev/null; then
  echo "-MM -MG kept system-context dependency" >&2
  exit 1
fi

"$MCPU_CPP" --no-config -M -MG -I user -isystem sys nested.c > nested-M.d
grep -F 'sys/system-parent.h' nested-M.d >/dev/null
grep -F 'generated-from-system.h' nested-M.d >/dev/null

# Unresolved dependency identity is textual and separate from physical
# st_dev/st_ino identity.  shadow.h exists in CWD, but <shadow.h> is not found
# through the angle search chain under --no-config; a later quoted ./shadow.h
# resolves that physical file.  Both registry entries must survive under -M.
cat > shadow.h <<'EOT'
#define SHADOW_VALUE 1
EOT
cat > identity.c <<'EOT'
#include <shadow.h>
#include "./shadow.h"
EOT
"$MCPU_CPP" --no-config -M -MG identity.c > identity-M.d
grep '^identity\.o: identity\.c shadow\.h \./\./shadow\.h$' identity-M.d >/dev/null || {
  echo "unresolved and physical dependency identities were incorrectly merged" >&2
  cat identity-M.d >&2
  exit 1
}

# In -MM the unresolved angle entry is filtered, while the resolved quoted
# physical dependency remains.
"$MCPU_CPP" --no-config -MM -MG identity.c > identity-MM.d
grep -F '././shadow.h' identity-MM.d >/dev/null
case "$(cat identity-MM.d)" in
  *' shadow.h '*)
    echo "-MM kept the unresolved angle dependency" >&2
    exit 1
    ;;
esac

# Repeated unresolved operands are deduplicated textually.  Their first
# classification is retained, matching GNU CPP: angle-first stays system-only,
# while quote-first stays visible to -MM.
cat > first-system.c <<'EOT'
#include <same-missing.h>
#include "same-missing.h"
EOT
"$MCPU_CPP" --no-config -MM -MG first-system.c > first-system.d
if grep -F 'same-missing.h' first-system.d >/dev/null; then
  echo "angle-first unresolved dependency lost its first classification" >&2
  exit 1
fi

cat > first-user.c <<'EOT'
#include "same-missing.h"
#include <same-missing.h>
EOT
"$MCPU_CPP" --no-config -MM -MG first-user.c > first-user.d
grep -F 'same-missing.h' first-user.d >/dev/null

# Different unresolved spellings are distinct because no physical identity is
# available to canonicalize them.
cat > spelling.c <<'EOT'
#include "generated.h"
#include "./generated.h"
EOT
"$MCPU_CPP" --no-config -M -MG spelling.c > spelling.d
grep -F ' generated.h' spelling.d >/dev/null
grep -F ' ./generated.h' spelling.d >/dev/null

# -MG also applies to missing command-line forced files.  They enter the same
# unresolved registry as user dependencies and preserve the command-line
# operand; no synthetic path is prepended.
: > forced.c
"$MCPU_CPP" --no-config -M -MG \
  -imacros missing-macros.h -include missing-include.h forced.c > forced-M.d
grep -F 'missing-macros.h' forced-M.d >/dev/null
grep -F 'missing-include.h' forced-M.d >/dev/null

"$MCPU_CPP" --no-config -MM -MG \
  -imacros missing-macros.h -include missing-include.h forced.c > forced-MM.d
grep -F 'missing-macros.h' forced-MM.d >/dev/null
grep -F 'missing-include.h' forced-MM.d >/dev/null

# -MG is dependency-only: GNU permits it with -M/-MM, not side-effect -MD/-MMD
# and not without dependency generation.
for opts in '-MG' '-MD -MG' '-MMD -MG'
do
  if "$MCPU_CPP" --no-config $opts forced.c > invalid.out 2> invalid.err; then
    echo "$opts unexpectedly accepted" >&2
    exit 1
  fi
  grep -- '-MG may only be used with -M or -MM' invalid.err >/dev/null
done

# Explicit dependency targets continue to compose with -MG.
"$MCPU_CPP" --no-config -M -MG -MT generated-target.o main.c > target.d
grep '^generated-target\.o:' target.d >/dev/null
grep -F 'generated-user.h' target.d >/dev/null

# Public help exposes the implemented option.
"$MCPU_CPP" --help > help.out
grep '^  -MG                  treat missing headers as generated dependencies$' help.out >/dev/null