@@ -7840,10 +7840,15 @@ prepare_build(bool print_fingerprint,
78407840 // ── 2. is it on disk ──
78417841 // Cache key: hash(url + refkind + declared ref + resolved commit).
78427842 // For fixed rev/tag deps the declared ref is also the resolved ref.
7843- std::hash<std::string> H;
7844- auto gitRoot = mcppHome / "git" / std::format("{:016x}",
7845- H(spec.git + "|" + spec.gitRefKind + "|" + spec.gitRev
7846- + "|" + resolvedGitRev));
7843+ // Deterministic across hosts: `std::hash` is not (see the note on
7844+ // mcpp::pm::index_package_digest). This key names the git cache
7845+ // directory AND the lock hash below, so a host-dependent hash made
7846+ // both the cache directory and mcpp.lock differ by platform.
7847+ auto H = [](std::string_view s) -> std::string {
7848+ return mcpp::toolchain::hash_string(s);
7849+ };
7850+ auto gitRoot = mcppHome / "git" / H(spec.git + "|" + spec.gitRefKind
7851+ + "|" + spec.gitRev + "|" + resolvedGitRev);
78477852 std::error_code ec;
78487853 std::filesystem::create_directories(gitRoot.parent_path(), ec);
78497854
@@ -7917,9 +7922,9 @@ prepare_build(bool print_fingerprint,
79177922 if (spec.gitRefKind == "branch") source += "@" + resolvedGitRev;
79187923 root_git_lock_identities[name] = GitLockIdentity{
79197924 .source = std::move(source),
7920- .hash = std::format( "fnv1a:{:016x}", H(spec.git + "|"
7925+ .hash = "fnv1a:" + H(spec.git + "|"
79217926 + spec.gitRefKind + "|" + spec.gitRev + "|"
7922- + resolvedGitRev)) ,
7927+ + resolvedGitRev),
79237928 };
79247929 }
79257930 sourceCommit = resolvedGitRev;
@@ -14479,8 +14484,7 @@ prepare_build(bool print_fingerprint,
1447914484 if (gitIt == root_git_lock_identities.end()) {
1448014485 lp.source = std::format("git+{}#{}={}",
1448114486 spec.git, spec.gitRefKind, spec.gitRev);
14482- std::hash<std::string> hasher;
14483- lp.hash = std::format("fnv1a:{:016x}", hasher(lp.source));
14487+ lp.hash = "fnv1a:" + mcpp::toolchain::hash_string(lp.source);
1448414488 } else {
1448514489 lp.source = gitIt->second.source;
1448614490 lp.hash = gitIt->second.hash;
@@ -14510,9 +14514,13 @@ prepare_build(bool print_fingerprint,
1451014514 // Use a deterministic hash based on namespace + name + version.
1451114515 // A future PR can replace this with a real content hash from the
1451214516 // xpkg.lua's declared sha256 or from the install plan.
14513- std::hash<std::string> hasher;
14514- auto hashInput = std::format("{}:{}@{}", sourceIndex, lp.name, lp.version);
14515- lp.hash = std::format("fnv1a:{:016x}", hasher(hashInput));
14517+ //
14518+ // NOT `std::hash<std::string>`: its output is implementation-defined
14519+ // (MSVC FNV-1a, libstdc++/libc++ MurmurHash), so the same dependency
14520+ // used to hash differently on Windows and Linux while the `fnv1a:`
14521+ // prefix claimed otherwise. `index_package_digest` is FNV-1a on
14522+ // every host.
14523+ lp.hash = mcpp::pm::index_package_digest(sourceIndex, lp.name, lp.version);
1451614524 lock.packages.push_back(std::move(lp));
1451714525 }
1451814526 if (!lock.packages.empty() || !lock.indices.empty()) {
0 commit comments