|
| 1 | +#!/usr/bin/env bash |
| 2 | +# 190_link_rspfile_newlines.sh — the link response file separates objects by |
| 3 | +# NEWLINES, not spaces. |
| 4 | +# |
| 5 | +# Two ceilings sit between a link edge and the OS, and routing the objects |
| 6 | +# through a response file only removes the first: |
| 7 | +# |
| 8 | +# 1. the COMMAND LINE — Windows CreateProcess 32 KiB, POSIX MAX_ARG_STRLEN |
| 9 | +# 128 KiB (ninja spawns `sh -c "<whole command>"`, so the command is one |
| 10 | +# argv entry). Removed by using @rspfile at all — mcpp#344 / PR#345. |
| 11 | +# 2. the response file's LINE LENGTH — link.exe caps it at 128 KiB: |
| 12 | +# |
| 13 | +# fatal error LNK1170: line in command file contains 135135 |
| 14 | +# or more characters |
| 15 | +# |
| 16 | +# which is where mcpp-index's opencv-module landed on windows, with every |
| 17 | +# object written onto a single line. |
| 18 | +# |
| 19 | +# `rspfile_content = $in_newline` removes the second. After it, no ceiling |
| 20 | +# scales with the number of objects. |
| 21 | +# |
| 22 | +# Asserted structurally (the generated rule) AND observably (the file ninja |
| 23 | +# actually writes, kept with -d keeprsp) — the first alone would still pass if |
| 24 | +# ninja ever changed what $in_newline expands to. |
| 25 | +set -e |
| 26 | + |
| 27 | +TMP=$(mktemp -d) |
| 28 | +trap "rm -rf $TMP" EXIT |
| 29 | +cd "$TMP" |
| 30 | + |
| 31 | +mkdir -p multi/src |
| 32 | +cat > multi/mcpp.toml <<'EOF' |
| 33 | +[package] |
| 34 | +name = "multi" |
| 35 | +version = "0.1.0" |
| 36 | +EOF |
| 37 | +# Enough objects that "one per line" is unambiguous — a single-object link |
| 38 | +# would look identical either way. |
| 39 | +i=1 |
| 40 | +while [ "$i" -le 24 ]; do |
| 41 | + printf 'int f%d() { return %d; }\n' "$i" "$i" > "multi/src/f$i.cpp" |
| 42 | + i=$((i + 1)) |
| 43 | +done |
| 44 | +printf 'int main() { return 0; }\n' > multi/src/main.cpp |
| 45 | + |
| 46 | +cd multi |
| 47 | +"$MCPP" build > b.log 2>&1 || { cat b.log; echo "FAIL: build"; exit 1; } |
| 48 | + |
| 49 | +ninja_file=$(find target -name build.ninja | head -1) |
| 50 | +[ -n "$ninja_file" ] || { echo "FAIL: no build.ninja"; exit 1; } |
| 51 | + |
| 52 | +# 1. Structural: no link rule may write its response file on one line. |
| 53 | +if grep -qE '^[[:space:]]*rspfile_content = \$in[[:space:]]*$' "$ninja_file"; then |
| 54 | + grep -nE '^[[:space:]]*rspfile_content' "$ninja_file" |
| 55 | + echo "FAIL: a link rule still writes its response file on ONE line (\$in)" |
| 56 | + exit 1 |
| 57 | +fi |
| 58 | +grep -qE '^[[:space:]]*rspfile_content = \$in_newline[[:space:]]*$' "$ninja_file" || { |
| 59 | + grep -nE '^[[:space:]]*rspfile_content' "$ninja_file" |
| 60 | + echo "FAIL: no link rule uses \$in_newline"; exit 1; } |
| 61 | +echo " ok: link rules declare rspfile_content = \$in_newline" |
| 62 | + |
| 63 | +# 2. Observable: ninja keeps the response file under -d keeprsp, and it holds |
| 64 | +# one object per line rather than all of them on the first. |
| 65 | +bdir=$(dirname "$ninja_file") |
| 66 | +bin_rel=$(cd "$bdir" && ls bin/ 2>/dev/null | head -1) |
| 67 | +[ -n "$bin_rel" ] || { echo "FAIL: no linked binary to inspect"; exit 1; } |
| 68 | +(cd "$bdir" && rm -f "bin/$bin_rel" && ninja -d keeprsp "bin/$bin_rel" > /dev/null 2>&1) \ |
| 69 | + || { echo "FAIL: relink under -d keeprsp"; exit 1; } |
| 70 | + |
| 71 | +rsp=$(find "$bdir" -name '*.rsp' | head -1) |
| 72 | +[ -n "$rsp" ] || { echo "FAIL: -d keeprsp left no response file"; exit 1; } |
| 73 | + |
| 74 | +# 25 objects -> 24 newlines (the last line carries no trailing newline). |
| 75 | +lines=$(wc -l < "$rsp") |
| 76 | +[ "$lines" -ge 20 ] || { |
| 77 | + echo "response file has $lines newline(s):"; head -c 300 "$rsp"; echo |
| 78 | + echo "FAIL: objects are not one-per-line — the LNK1170 shape is back" |
| 79 | + exit 1; } |
| 80 | + |
| 81 | +# ...and no single line is anywhere near link.exe's 128 KiB cap. |
| 82 | +longest=$(awk '{ if (length($0) > m) m = length($0) } END { print m+0 }' "$rsp") |
| 83 | +[ "$longest" -lt 4096 ] || { |
| 84 | + echo "FAIL: longest response-file line is $longest chars"; exit 1; } |
| 85 | +echo " ok: $((lines + 1)) objects, longest response-file line $longest chars" |
| 86 | + |
| 87 | +echo "OK" |
0 commit comments