|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Reproductions for .agents/docs/2026-10-10-one-source-one-meaning-design.md. |
| 3 | +# Prints what each case observes; asserts nothing. |
| 4 | +# |
| 5 | +# MCPP=<path to mcpp> bash 2026-10-10-one-source-one-meaning-repro.sh |
| 6 | +# |
| 7 | +# R1 conditional dialect_cxxflags in three positions (#786, #785) |
| 8 | +# R2 action output shared by two profiles (out_dir has no configuration) |
| 9 | +# R3 #778 on Linux: member target cleared, workspace ninja log kept |
| 10 | +# R4 #790: implementation partition in a .cpp, rebuilt every time |
| 11 | +# R5 interface unit (`export module`) in a .cpp |
| 12 | +# R6 implementation partition in a .cpp imported by the interface |
| 13 | +set -u |
| 14 | +MCPP="${MCPP:-mcpp}" |
| 15 | +LLVM="${LLVM:-llvm@23.1.3}" |
| 16 | +T=$(mktemp -d) |
| 17 | +echo "mcpp: $("$MCPP" --version 2>&1 | head -1) work: $T" |
| 18 | +binrun() { local b; b=$(find target -path '*/bin/*' -name "$1" -type f -newer "$2" 2>/dev/null | xargs -r ls -t | head -1); [ -n "$b" ] && "$b" || echo "(no binary)"; } |
| 19 | + |
| 20 | +# ── R1 ──────────────────────────────────────────────────────────────── |
| 21 | +main_dial() { cat > "$1" <<'EOF' |
| 22 | +#include <cstdio> |
| 23 | +#ifndef DIAL |
| 24 | +#define DIAL 0 |
| 25 | +#endif |
| 26 | +int main() { std::printf("DIAL=%d\n", DIAL); } |
| 27 | +EOF |
| 28 | +} |
| 29 | +app_toml() { cat <<EOF |
| 30 | +[package] |
| 31 | +name = "app" |
| 32 | +version = "0.1.0" |
| 33 | +[build] |
| 34 | +sources = ["main.cpp"] |
| 35 | +[targets.app] |
| 36 | +kind = "bin" |
| 37 | +main = "main.cpp" |
| 38 | +$1 |
| 39 | +EOF |
| 40 | +} |
| 41 | +COND1='[target.'"'"'cfg(os = "linux")'"'"'.build] |
| 42 | +dialect_cxxflags = ["-DDIAL=1"]' |
| 43 | +COND2='[target.'"'"'cfg(os = "linux")'"'"'.build] |
| 44 | +dialect_cxxflags = ["-DDIAL=2"]' |
| 45 | +mkdir -p "$T/r1/ws-root/app" "$T/r1/member/app" "$T/r1/standalone" |
| 46 | +printf '[workspace]\nmembers = ["app"]\n%s\n' "$COND1" > "$T/r1/ws-root/mcpp.toml" |
| 47 | +app_toml "" > "$T/r1/ws-root/app/mcpp.toml"; main_dial "$T/r1/ws-root/app/main.cpp" |
| 48 | +printf '[workspace]\nmembers = ["app"]\n' > "$T/r1/member/mcpp.toml" |
| 49 | +app_toml "$COND2" > "$T/r1/member/app/mcpp.toml"; main_dial "$T/r1/member/app/main.cpp" |
| 50 | +app_toml "$COND2" > "$T/r1/standalone/mcpp.toml"; main_dial "$T/r1/standalone/main.cpp" |
| 51 | +for c in ws-root member; do |
| 52 | + (cd "$T/r1/$c" && "$MCPP" build -p app > build.log 2>&1; echo "R1 $c: $(binrun app mcpp.toml) warnings: $(grep -ci warn build.log)") |
| 53 | +done |
| 54 | +(cd "$T/r1/standalone" && "$MCPP" build > build.log 2>&1; echo "R1 standalone: $(binrun app mcpp.toml)") |
| 55 | + |
| 56 | +# ── R2 ──────────────────────────────────────────────────────────────── |
| 57 | +mkdir -p "$T/r2/src"; cd "$T/r2" |
| 58 | +cat > mcpp.toml <<'EOF' |
| 59 | +[package] |
| 60 | +name = "gp" |
| 61 | +version = "0.1.0" |
| 62 | +[build] |
| 63 | +sources = ["src/main.cpp"] |
| 64 | +[targets.gp] |
| 65 | +kind = "bin" |
| 66 | +main = "src/main.cpp" |
| 67 | +EOF |
| 68 | +cat > src/main.cpp <<'EOF' |
| 69 | +#include <cstdio> |
| 70 | +const char* gen_profile(); |
| 71 | +int main() { std::printf("GEN=%s\n", gen_profile()); } |
| 72 | +EOF |
| 73 | +printf '#!/bin/sh\nprintf '"'"'const char* gen_profile() { return "%%s"; }\\n'"'"' "$1" > "$2"\n' > gen.sh |
| 74 | +cat > build.mcpp <<'EOF' |
| 75 | +import std; |
| 76 | +import mcpp; |
| 77 | +int main() { |
| 78 | + const auto root = std::filesystem::path(mcpp::manifest_dir()); |
| 79 | + const auto out = (std::filesystem::path(mcpp::out_dir()) / "gen.cpp").generic_string(); |
| 80 | + const auto gen = (root / "gen.sh").generic_string(); |
| 81 | + mcpp::action a; |
| 82 | + a.id = "gen"; |
| 83 | + a.role = mcpp::roles::source; |
| 84 | + a.arg("sh").arg(gen.c_str()).arg(mcpp::profile()).arg(out.c_str()) |
| 85 | + .input(gen.c_str()).output(out.c_str()).submit(); |
| 86 | + return 0; |
| 87 | +} |
| 88 | +EOF |
| 89 | +for p in "" --release ""; do |
| 90 | + "$MCPP" build $p > build.log 2>&1 || tail -5 build.log |
| 91 | + echo "R2 build ${p:-(dev)}: $(binrun gp gen.sh)" |
| 92 | +done |
| 93 | +echo "R2 out_dir: $(find target -name gen.cpp | head -3 | tr '\n' ' ')" |
| 94 | + |
| 95 | +# ── R3 ──────────────────────────────────────────────────────────────── |
| 96 | +mkdir -p "$T/r3/app"; cd "$T/r3" |
| 97 | +printf '[workspace]\nmembers = ["app"]\n' > mcpp.toml |
| 98 | +cat > app/mcpp.toml <<'EOF' |
| 99 | +[package] |
| 100 | +namespace = "repro" |
| 101 | +name = "app" |
| 102 | +version = "0.0.1" |
| 103 | +[build] |
| 104 | +sources = [] |
| 105 | +[targets.resource_test] |
| 106 | +kind = "bin" |
| 107 | +main = "main.cpp" |
| 108 | +EOF |
| 109 | +printf 'extern const char* resource();\nint main() { return resource()[0] == '"'"'R'"'"' ? 0 : 1; }\n' > app/main.cpp |
| 110 | +printf '#!/bin/sh\nprintf '"'"'const char* resource() { return "RESOURCE"; }\\n'"'"' > "$1"\n' > app/gen.sh |
| 111 | +cat > app/build.mcpp <<'EOF' |
| 112 | +import std; |
| 113 | +import mcpp; |
| 114 | +int main() { |
| 115 | + const auto root = std::filesystem::path(mcpp::manifest_dir()); |
| 116 | + const auto out = (std::filesystem::path(mcpp::out_dir()) / "generated.cpp").generic_string(); |
| 117 | + const auto gen = (root / "gen.sh").generic_string(); |
| 118 | + mcpp::action a; |
| 119 | + a.id = "generate:resource"; |
| 120 | + a.role = mcpp::roles::source; |
| 121 | + a.arg("sh").arg(gen.c_str()).arg(out.c_str()).input(gen.c_str()).output(out.c_str()).submit(); |
| 122 | + return 0; |
| 123 | +} |
| 124 | +EOF |
| 125 | +"$MCPP" build -p app --release > b1.log 2>&1; echo "R3 first: rc=$? size=$(stat -c %s app/target/.build-mcpp/out/generated.cpp 2>/dev/null)" |
| 126 | +mv app/target saved-app-target |
| 127 | +"$MCPP" build -p app --release > b2.log 2>&1; echo "R3 after clearing member target: rc=$? size=$(stat -c %s app/target/.build-mcpp/out/generated.cpp 2>/dev/null) $(grep -m1 -o 'undefined reference[^)]*' b2.log)" |
| 128 | + |
| 129 | +# ── R4–R6 ───────────────────────────────────────────────────────────── |
| 130 | +mod_pkg() { # dir, extra-for-repro.cppm |
| 131 | +mkdir -p "$1/src" |
| 132 | +cat > "$1/mcpp.toml" <<EOF |
| 133 | +[package] |
| 134 | +name = "repro" |
| 135 | +version = "0.1.0" |
| 136 | +[toolchain] |
| 137 | +default = "$LLVM" |
| 138 | +[targets.repro] |
| 139 | +kind = "bin" |
| 140 | +main = "src/main.cpp" |
| 141 | +EOF |
| 142 | +printf 'export module repro;\nexport import :api;\n%s\n' "$2" > "$1/src/repro.cppm" |
| 143 | +printf 'export module repro:api;\nexport auto answer() -> int;\n' > "$1/src/api.cppm" |
| 144 | +printf 'module repro:api_impl;\nimport :api;\nauto answer() -> int { return 42; }\n' > "$1/src/api_impl.cpp" |
| 145 | +printf 'import repro;\nimport std;\nauto main() -> int { std::println("{}", answer()); }\n' > "$1/src/main.cpp" |
| 146 | +} |
| 147 | +mod_pkg "$T/r4" ""; cd "$T/r4" |
| 148 | +for i in 1 2 3; do "$MCPP" build --verbose > b$i.log 2>&1; done |
| 149 | +echo "R4 build 2: $(grep -cE '^\[[0-9]+/' b2.log) steps; build 3: $(grep -cE '^\[[0-9]+/' b3.log) steps" |
| 150 | +echo "R4 pcm files: $(find target -name '*.pcm' -path '*pcm.cache*' -printf '%f ' 2>/dev/null)" |
| 151 | + |
| 152 | +mod_pkg "$T/r6" "import :api_impl;"; cd "$T/r6" |
| 153 | +"$MCPP" build > b.log 2>&1; echo "R6 import of the .cpp partition: rc=$? $(grep -m1 -o "fatal error: .*" b.log)" |
| 154 | + |
| 155 | +mkdir -p "$T/r5/src"; cd "$T/r5" |
| 156 | +cat > mcpp.toml <<EOF |
| 157 | +[package] |
| 158 | +name = "r5" |
| 159 | +version = "0.1.0" |
| 160 | +[toolchain] |
| 161 | +default = "$LLVM" |
| 162 | +[targets.r5] |
| 163 | +kind = "bin" |
| 164 | +main = "src/main.cpp" |
| 165 | +EOF |
| 166 | +printf 'export module r5;\nexport auto answer() -> int { return 42; }\n' > src/r5.cpp |
| 167 | +printf 'import r5;\nimport std;\nauto main() -> int { std::println("{}", answer()); }\n' > src/main.cpp |
| 168 | +"$MCPP" build > b1.log 2>&1; r1=$?; "$MCPP" build --verbose > b2.log 2>&1 |
| 169 | +echo "R5 interface in .cpp: rc=$r1 $(grep -m1 -oE '(error|fatal error): .*' b1.log) second build: $(grep -cE '^\[[0-9]+/' b2.log) steps" |
0 commit comments