Skip to content

Commit 2e7fe50

Browse files
authored
feat: fast-path fingerprint coherence + diagnostic warning (#35)
P1: .build_cache stores fingerprint hex, try_fast_build validates consistency. P1.5: warning printed when fingerprint changes.
1 parent 9bd1a6d commit 2e7fe50

2 files changed

Lines changed: 39 additions & 7 deletions

File tree

src/build/ninja_backend.cppm

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,7 @@ std::string emit_ninja_string(const BuildPlan& plan) {
253253
"-fdeps-file=$out -fdeps-target=$compile_target "
254254
"-M -MM -MF $out.dep -E $in -o $compile_target\n");
255255
} else {
256-
// Clang path: clang-scan-deps produces P1689 JSON to stdout,
257-
// then we redirect to $out. The -- separator passes the full
258-
// compile command so clang-scan-deps knows the flags/sysroot.
256+
// Clang path: clang-scan-deps produces P1689 JSON to stdout.
259257
append(" command = $toolenv $scan_deps -format=p1689 -- "
260258
"$cxx $cxxflags -c $in -o $compile_target > $out\n");
261259
}

src/cli.cppm

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,7 +2106,8 @@ constexpr std::string_view kBuildCacheFile = "target/.build_cache";
21062106
void write_build_cache(const std::filesystem::path& projectRoot,
21072107
const std::filesystem::path& outputDir,
21082108
const std::string& ninjaProgram,
2109-
const std::string& targetTriple) {
2109+
const std::string& targetTriple,
2110+
const std::string& fingerprintHex = "") {
21102111
auto path = projectRoot / kBuildCacheFile;
21112112
std::error_code ec;
21122113
std::filesystem::create_directories(path.parent_path(), ec);
@@ -2115,6 +2116,7 @@ void write_build_cache(const std::filesystem::path& projectRoot,
21152116
f << outputDir.string() << '\n';
21162117
f << ninjaProgram << '\n';
21172118
f << targetTriple << '\n';
2119+
f << fingerprintHex << '\n';
21182120
}
21192121
}
21202122

@@ -2173,10 +2175,27 @@ int run_build_plan(BuildContext& ctx, bool verbose, bool no_cache,
21732175
}
21742176
}
21752177

2178+
// P1.5: warn if fingerprint changed from last build (explains full rebuild).
2179+
{
2180+
auto cachePath = ctx.projectRoot / kBuildCacheFile;
2181+
std::ifstream cf(cachePath);
2182+
std::string oldDir;
2183+
if (std::getline(cf, oldDir) && !oldDir.empty()) {
2184+
auto oldFp = std::filesystem::path(oldDir).filename().string();
2185+
auto newFp = ctx.outputDir.filename().string();
2186+
if (oldFp != newFp) {
2187+
mcpp::ui::warning(std::format(
2188+
"fingerprint changed ({} → {}), full rebuild",
2189+
oldFp, newFp));
2190+
}
2191+
}
2192+
}
2193+
21762194
// P0: save build cache for fast-path on next invocation.
21772195
if (!no_cache && !r->ninjaProgram.empty()) {
2196+
auto fpHex = ctx.outputDir.filename().string();
21782197
write_build_cache(ctx.projectRoot, ctx.outputDir, r->ninjaProgram,
2179-
std::string(targetOverride));
2198+
std::string(targetOverride), fpHex);
21802199
}
21812200

21822201
mcpp::ui::finished("release", r->elapsed);
@@ -2204,15 +2223,30 @@ std::optional<int> try_fast_build(const std::filesystem::path& projectRoot,
22042223
if (!std::filesystem::exists(cachePath, ec)) return std::nullopt;
22052224

22062225
std::ifstream f(cachePath);
2207-
std::string outputDirStr, ninjaProgram, cachedTarget;
2226+
std::string outputDirStr, ninjaProgram, cachedTarget, cachedFingerprint;
22082227
if (!std::getline(f, outputDirStr) || outputDirStr.empty()) return std::nullopt;
22092228
if (!std::getline(f, ninjaProgram) || ninjaProgram.empty()) return std::nullopt;
2210-
std::getline(f, cachedTarget); // may be empty for old cache files
2229+
std::getline(f, cachedTarget); // may be empty for old cache files
2230+
std::getline(f, cachedFingerprint); // may be empty for pre-0.0.15 caches
22112231

22122232
// Reject cache if target triple changed (e.g. previous build used
22132233
// --target x86_64-linux-musl but this one is a default build).
22142234
if (cachedTarget != currentTarget) return std::nullopt;
22152235

2236+
// P1: verify fingerprint matches the outputDir basename. If someone
2237+
// switched mcpp installations (different toolchain binary), the cached
2238+
// outputDir points to a stale fingerprint directory. Detect and reject.
2239+
if (!cachedFingerprint.empty()) {
2240+
std::filesystem::path outputDir(outputDirStr);
2241+
auto dirBasename = outputDir.filename().string();
2242+
if (dirBasename != cachedFingerprint) {
2243+
// Cache is inconsistent — invalidate it.
2244+
std::error_code ec2;
2245+
std::filesystem::remove(cachePath, ec2);
2246+
return std::nullopt;
2247+
}
2248+
}
2249+
22162250
std::filesystem::path outputDir(outputDirStr);
22172251

22182252
auto ninjaPath = outputDir / "build.ninja";

0 commit comments

Comments
 (0)