Skip to content

Commit 83304e2

Browse files
committed
refactor: neutralize bmi_cache naming for GCC/Clang parity
Rename gcmFiles→bmiFiles, gcmDir()→bmiDir(), add bmiDirName/manifestTag fields to CacheKey. Manifest format now uses the tag from CacheKey (gcm: or pcm:) and parsing accepts both prefixes for forward compat. Callers set bmiDirName/manifestTag via BmiTraits from PR1.
1 parent f831d98 commit 83304e2

3 files changed

Lines changed: 45 additions & 39 deletions

File tree

src/bmi_cache.cppm

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// Layout (per docs/26-bmi-cache.md):
44
// $MCPP_HOME/bmi/<fingerprint>/deps/<indexName>/<pkgName>@<version>/
5-
// gcm.cache/<module>.gcm
5+
// {gcm,pcm}.cache/<module>.{gcm,pcm}
66
// obj/<file>.m.o + <file>.o
77
// manifest.txt (sentinel + file list)
88
//
@@ -31,20 +31,22 @@ struct CacheKey {
3131
std::string indexName; // "mcpplibs" / "xim" / ...
3232
std::string packageName; // "mcpplibs.cmdline"
3333
std::string version; // "0.0.1"
34+
std::string bmiDirName = "gcm.cache"; // "gcm.cache" | "pcm.cache"
35+
std::string manifestTag = "gcm"; // "gcm" | "pcm"
3436

3537
std::filesystem::path dir() const {
3638
return mcppHome / "bmi" / fingerprint / "deps"
3739
/ indexName / std::format("{}@{}", packageName, version);
3840
}
3941

4042
std::filesystem::path manifestFile() const { return dir() / "manifest.txt"; }
41-
std::filesystem::path gcmDir() const { return dir() / "gcm.cache"; }
43+
std::filesystem::path bmiDir() const { return dir() / bmiDirName; }
4244
std::filesystem::path objDir() const { return dir() / "obj"; }
4345
};
4446

4547
// File names (basename only) that belong to one dep package's cache entry.
4648
struct DepArtifacts {
47-
std::vector<std::string> gcmFiles; // basenames in gcm.cache/
49+
std::vector<std::string> bmiFiles; // basenames in bmiDir/
4850
std::vector<std::string> objFiles; // basenames in obj/
4951
};
5052

@@ -55,14 +57,14 @@ bool is_cached(const CacheKey& key);
5557
std::expected<DepArtifacts, std::string>
5658
read_manifest(const CacheKey& key);
5759

58-
// Copy missing cached files into projectTarget/{gcm.cache,obj}. Existing
59-
// project outputs are left untouched: GCC BMIs may differ byte-for-byte between
60+
// Copy missing cached files into projectTarget/{bmiDirName,obj}. Existing
61+
// project outputs are left untouched: BMIs may differ byte-for-byte between
6062
// equivalent builds, and overwriting them would dirty downstream modules.
6163
std::expected<DepArtifacts, std::string>
6264
stage_into(const CacheKey& key,
6365
const std::filesystem::path& projectTargetDir);
6466

65-
// Copy fresh build outputs from projectTarget/{gcm.cache,obj} → cache dir
67+
// Copy fresh build outputs from projectTarget/{bmiDirName,obj} → cache dir
6668
// and write manifest.txt last (atomic-ish sentinel).
6769
std::expected<void, std::string>
6870
populate_from(const CacheKey& key,
@@ -91,9 +93,9 @@ bool copy_one(const std::filesystem::path& from,
9193
return !ec;
9294
}
9395

94-
std::string serialize_manifest(const DepArtifacts& a) {
96+
std::string serialize_manifest(std::string_view tag, const DepArtifacts& a) {
9597
std::string out = "# Auto-generated by mcpp bmi_cache. Do not edit.\n";
96-
for (auto& g : a.gcmFiles) out += std::format("gcm: {}\n", g);
98+
for (auto& g : a.bmiFiles) out += std::format("{}: {}\n", tag, g);
9799
for (auto& o : a.objFiles) out += std::format("obj: {}\n", o);
98100
return out;
99101
}
@@ -107,7 +109,8 @@ parse_manifest(const std::filesystem::path& p) {
107109
while (std::getline(is, line)) {
108110
while (!line.empty() && (line.back() == '\r' || line.back() == ' ')) line.pop_back();
109111
if (line.empty() || line[0] == '#') continue;
110-
if (line.starts_with("gcm: ")) a.gcmFiles.push_back(line.substr(5));
112+
if (line.starts_with("gcm: ")) a.bmiFiles.push_back(line.substr(5));
113+
else if (line.starts_with("pcm: ")) a.bmiFiles.push_back(line.substr(5));
111114
else if (line.starts_with("obj: ")) a.objFiles.push_back(line.substr(5));
112115
}
113116
return a;
@@ -121,8 +124,8 @@ bool is_cached(const CacheKey& key) {
121124
auto arts = parse_manifest(mf);
122125
if (!arts) return false;
123126
// Verify every listed file actually exists on disk.
124-
for (auto& g : arts->gcmFiles) {
125-
if (!std::filesystem::exists(key.gcmDir() / g)) return false;
127+
for (auto& g : arts->bmiFiles) {
128+
if (!std::filesystem::exists(key.bmiDir() / g)) return false;
126129
}
127130
for (auto& o : arts->objFiles) {
128131
if (!std::filesystem::exists(key.objDir() / o)) return false;
@@ -142,23 +145,23 @@ stage_into(const CacheKey& key,
142145
auto arts = parse_manifest(key.manifestFile());
143146
if (!arts) return std::unexpected(arts.error());
144147

145-
auto projectGcm = projectTargetDir / "gcm.cache";
148+
auto projectBmi = projectTargetDir / key.bmiDirName;
146149
auto projectObj = projectTargetDir / "obj";
147150
std::error_code ec;
148-
std::filesystem::create_directories(projectGcm, ec);
151+
std::filesystem::create_directories(projectBmi, ec);
149152
std::filesystem::create_directories(projectObj, ec);
150153

151-
for (auto& g : arts->gcmFiles) {
152-
auto from = key.gcmDir() / g;
153-
auto to = projectGcm / g;
154+
for (auto& g : arts->bmiFiles) {
155+
auto from = key.bmiDir() / g;
156+
auto to = projectBmi / g;
154157
if (std::filesystem::exists(to, ec)) {
155158
ec.clear();
156159
continue;
157160
}
158161
ec.clear();
159162
if (!copy_one(from, to, ec)) {
160163
return std::unexpected(std::format(
161-
"stage gcm '{}': {}", g, ec.message()));
164+
"stage bmi '{}': {}", g, ec.message()));
162165
}
163166
touch_now(to);
164167
}
@@ -221,25 +224,25 @@ populate_from(const CacheKey& key,
221224
~LockGuard() { release_lock(fd); }
222225
} guard{ lockFd };
223226

224-
auto cacheGcm = key.gcmDir();
227+
auto cacheBmi = key.bmiDir();
225228
auto cacheObj = key.objDir();
226229
std::error_code ec;
227-
std::filesystem::create_directories(cacheGcm, ec);
230+
std::filesystem::create_directories(cacheBmi, ec);
228231
std::filesystem::create_directories(cacheObj, ec);
229232

230-
auto projectGcm = projectTargetDir / "gcm.cache";
233+
auto projectBmi = projectTargetDir / key.bmiDirName;
231234
auto projectObj = projectTargetDir / "obj";
232235

233-
for (auto& g : arts.gcmFiles) {
234-
auto from = projectGcm / g;
235-
auto to = cacheGcm / g;
236+
for (auto& g : arts.bmiFiles) {
237+
auto from = projectBmi / g;
238+
auto to = cacheBmi / g;
236239
if (!std::filesystem::exists(from)) {
237240
return std::unexpected(std::format(
238241
"expected build output missing: {}", from.string()));
239242
}
240243
if (!copy_one(from, to, ec)) {
241244
return std::unexpected(std::format(
242-
"populate gcm '{}': {}", g, ec.message()));
245+
"populate bmi '{}': {}", g, ec.message()));
243246
}
244247
}
245248
for (auto& o : arts.objFiles) {
@@ -260,7 +263,7 @@ populate_from(const CacheKey& key,
260263
tmp += ".tmp";
261264
{
262265
std::ofstream os(tmp);
263-
os << serialize_manifest(arts);
266+
os << serialize_manifest(key.manifestTag, arts);
264267
}
265268
std::filesystem::rename(tmp, key.manifestFile(), ec);
266269
if (ec) {

src/cli.cppm

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,12 +2023,15 @@ prepare_build(bool print_fingerprint,
20232023
}
20242024
if (skipCache) continue;
20252025

2026+
auto bmiT = mcpp::toolchain::bmi_traits(*tc);
20262027
mcpp::bmi_cache::CacheKey key {
20272028
.mcppHome = (*cfg2)->mcppHome,
20282029
.fingerprint = fp.hex,
20292030
.indexName = (*cfg2)->defaultIndex,
20302031
.packageName = depName,
20312032
.version = depVer,
2033+
.bmiDirName = std::string(bmiT.bmiDir),
2034+
.manifestTag = std::string(bmiT.manifestPrefix),
20322035
};
20332036

20342037
// Compute the artifacts list from the build plan: every
@@ -2042,11 +2045,11 @@ prepare_build(bool print_fingerprint,
20422045
if (rels.starts_with("..")) continue; // not under depRoot
20432046

20442047
if (cu.providesModule) {
2045-
std::string gcm;
2048+
std::string bmi;
20462049
for (char c : *cu.providesModule)
2047-
gcm.push_back(c == ':' ? '-' : c);
2048-
gcm += ".gcm";
2049-
arts.gcmFiles.push_back(std::move(gcm));
2050+
bmi.push_back(c == ':' ? '-' : c);
2051+
bmi += std::string(bmiT.bmiExt);
2052+
arts.bmiFiles.push_back(std::move(bmi));
20502053
}
20512054
arts.objFiles.push_back(cu.object.filename().string());
20522055
}

tests/unit/test_bmi_cache.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ TEST(BmiCache, KeyDirLayoutMatchesDocs26) {
4646
EXPECT_EQ(k.dir().string(),
4747
"/home/u/.mcpp/bmi/deadbeef0123abcd/deps/mcpplibs/mcpplibs.cmdline@0.0.1");
4848
EXPECT_EQ(k.manifestFile().filename().string(), "manifest.txt");
49-
EXPECT_EQ(k.gcmDir().filename().string(), "gcm.cache");
49+
EXPECT_EQ(k.bmiDir().filename().string(), "gcm.cache");
5050
EXPECT_EQ(k.objDir().filename().string(), "obj");
5151
}
5252

@@ -68,7 +68,7 @@ TEST(BmiCache, PopulateThenStageRoundTrip) {
6868
writeFile(project / "obj" / "cmdline.m.o", "OBJ-A");
6969

7070
DepArtifacts arts {
71-
.gcmFiles = { "mcpplibs.cmdline.gcm", "mcpplibs.cmdline-options.gcm" },
71+
.bmiFiles = { "mcpplibs.cmdline.gcm", "mcpplibs.cmdline-options.gcm" },
7272
.objFiles = { "cmdline.m.o" },
7373
};
7474

@@ -77,16 +77,16 @@ TEST(BmiCache, PopulateThenStageRoundTrip) {
7777
ASSERT_TRUE(pop) << pop.error();
7878

7979
EXPECT_TRUE(std::filesystem::exists(k.manifestFile()));
80-
EXPECT_TRUE(std::filesystem::exists(k.gcmDir() / "mcpplibs.cmdline.gcm"));
81-
EXPECT_TRUE(std::filesystem::exists(k.gcmDir() / "mcpplibs.cmdline-options.gcm"));
80+
EXPECT_TRUE(std::filesystem::exists(k.bmiDir() / "mcpplibs.cmdline.gcm"));
81+
EXPECT_TRUE(std::filesystem::exists(k.bmiDir() / "mcpplibs.cmdline-options.gcm"));
8282
EXPECT_TRUE(std::filesystem::exists(k.objDir() / "cmdline.m.o"));
8383
EXPECT_TRUE(is_cached(k));
8484

8585
// Round-trip: stage into a fresh project dir.
8686
auto project2 = t.path / "proj2" / "target";
8787
auto staged = stage_into(k, project2);
8888
ASSERT_TRUE(staged) << staged.error();
89-
EXPECT_EQ(staged->gcmFiles.size(), 2u);
89+
EXPECT_EQ(staged->bmiFiles.size(), 2u);
9090
EXPECT_EQ(staged->objFiles.size(), 1u);
9191
EXPECT_TRUE(std::filesystem::exists(project2 / "gcm.cache" / "mcpplibs.cmdline.gcm"));
9292
EXPECT_TRUE(std::filesystem::exists(project2 / "obj" / "cmdline.m.o"));
@@ -108,7 +108,7 @@ TEST(BmiCache, StageIntoDoesNotTouchIdenticalOutputs) {
108108
writeFile(project / "obj" / "cmdline.m.o", "OBJ-A");
109109

110110
DepArtifacts arts {
111-
.gcmFiles = { "mcpplibs.cmdline.gcm" },
111+
.bmiFiles = { "mcpplibs.cmdline.gcm" },
112112
.objFiles = { "cmdline.m.o" },
113113
};
114114

@@ -140,7 +140,7 @@ TEST(BmiCache, StageIntoDoesNotOverwriteExistingOutputs) {
140140
writeFile(cacheProject / "obj" / "cmdline.m.o", "CACHE-OBJ");
141141

142142
DepArtifacts arts {
143-
.gcmFiles = { "mcpplibs.cmdline.gcm" },
143+
.bmiFiles = { "mcpplibs.cmdline.gcm" },
144144
.objFiles = { "cmdline.m.o" },
145145
};
146146

@@ -178,7 +178,7 @@ TEST(BmiCache, IsCachedFalseWhenSentinelExistsButFileMissing) {
178178
writeFile(project / "gcm.cache" / "lib.gcm", "G");
179179
writeFile(project / "obj" / "lib.m.o", "O");
180180

181-
DepArtifacts arts { .gcmFiles = {"lib.gcm"}, .objFiles = {"lib.m.o"} };
181+
DepArtifacts arts { .bmiFiles = {"lib.gcm"}, .objFiles = {"lib.m.o"} };
182182
auto k = makeKey(home);
183183
ASSERT_TRUE(populate_from(k, project, arts));
184184
ASSERT_TRUE(is_cached(k));
@@ -193,7 +193,7 @@ TEST(BmiCache, PopulateFailsIfBuildOutputMissing) {
193193
auto home = t.path / "home";
194194
auto project = t.path / "proj" / "target";
195195
std::filesystem::create_directories(project / "gcm.cache");
196-
DepArtifacts arts { .gcmFiles = {"missing.gcm"}, .objFiles = {} };
196+
DepArtifacts arts { .bmiFiles = {"missing.gcm"}, .objFiles = {} };
197197
auto k = makeKey(home);
198198
auto pop = populate_from(k, project, arts);
199199
EXPECT_FALSE(pop);
@@ -219,7 +219,7 @@ TEST(BmiCache, PopulateSkipsWhenLockHeld) {
219219
ASSERT_GE(fd, 0);
220220
ASSERT_EQ(::flock(fd, LOCK_EX | LOCK_NB), 0);
221221

222-
DepArtifacts arts { .gcmFiles = {"lib.gcm"}, .objFiles = {"lib.m.o"} };
222+
DepArtifacts arts { .bmiFiles = {"lib.gcm"}, .objFiles = {"lib.m.o"} };
223223
auto pop = populate_from(k, project, arts);
224224
EXPECT_TRUE(pop) << "should silently skip when lock is held";
225225
// manifest.txt must NOT have been written by the second writer.

0 commit comments

Comments
 (0)