diff options
Diffstat (limited to 'tests/t0057-missing-generated-dependencies.sh')
| -rwxr-xr-x | tests/t0057-missing-generated-dependencies.sh | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/tests/t0057-missing-generated-dependencies.sh b/tests/t0057-missing-generated-dependencies.sh new file mode 100755 index 0000000..7ad5001 --- /dev/null +++ b/tests/t0057-missing-generated-dependencies.sh @@ -0,0 +1,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 |
