Skip to content

Commit 71ee489

Browse files
speak-agentclaude
andcommitted
the two probe tests that never ran anywhere now run
`find_a_cxx_compiler` answers `/usr/bin/c++` first, which is GCC on every host this suite runs on, and GCC takes no `--target`. The two tests that check the probe measures the target rather than the host therefore skipped on every host including the CI shards with an LLVM toolchain --- coverage that looks like coverage and is not, which is the shape the rest of this branch exists to remove. They now look for a clang, and for one that actually has the back end they name: the host this was written on carries a vendor clang with neither RISC-V nor AArch64, so a PATH-only search would have skipped for a reason that has nothing to do with what is being tested. The search asks each candidate before accepting it, and falls back to the LLVM payload mcpp installs, which every shard resolving an `llvm@` toolchain has already downloaded. Measured here: 15 passed, 0 skipped, where it was 13 passed and 2 skipped. Co-authored-by: Claude Code <noreply@anthropic.com>
1 parent 9af26c6 commit 71ee489

1 file changed

Lines changed: 79 additions & 12 deletions

File tree

tests/unit/test_cenv_probe.cpp

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
import std;
3939
import mcpp.toolchain.cenv_probe;
40+
import mcpp.platform;
4041

4142
namespace cp = mcpp::toolchain::cenv_probe;
4243

@@ -64,6 +65,77 @@ std::filesystem::path cxx() {
6465
return p;
6566
}
6667

68+
// A CLANG, FOR THE TWO TESTS THAT NEED ONE, AND FOUND ON PATH RATHER THAN AT A
69+
// FIXED LOCATION.
70+
//
71+
// `find_a_cxx_compiler` answers `/usr/bin/c++` first, which is GCC on every
72+
// host this suite runs on --- and GCC takes no `--target`. The two tests below
73+
// therefore skipped on EVERY host, including the CI shards that have an LLVM
74+
// toolchain, which is the shape of coverage that looks like coverage and is
75+
// not. Searching PATH makes them run wherever a clang is reachable; where none
76+
// is, they skip and say so, and `CenvProbeArgv` still pins the invariant with
77+
// no compiler at all.
78+
// Whether this compiler both takes `--target` and has the back end the two
79+
// tests below name. A clang that answers for neither is not a smaller version
80+
// of one that does; it is a different tool for this purpose.
81+
bool answers_for_a_cross_target(const std::filesystem::path& bin) {
82+
auto r = mcpp::platform::process::capture_stdout(
83+
{bin.string(), "--target=riscv64-none-elf", "-x", "c++", "-E", "-dM", "-"});
84+
return r.exit_code == 0
85+
&& r.output.find("#define __riscv ") != std::string::npos;
86+
}
87+
88+
std::filesystem::path find_a_clang() {
89+
if (const char* env = std::getenv("MCPP_TEST_CLANGXX"); env && *env)
90+
return env;
91+
const char* path = std::getenv("PATH");
92+
if (!path) return {};
93+
std::string_view rest{path};
94+
#ifdef _WIN32
95+
constexpr char kSep = ';';
96+
constexpr std::string_view kName = "clang++.exe";
97+
#else
98+
constexpr char kSep = ':';
99+
constexpr std::string_view kName = "clang++";
100+
#endif
101+
while (!rest.empty()) {
102+
auto at = rest.find(kSep);
103+
auto dir = rest.substr(0, at);
104+
rest = (at == std::string_view::npos) ? std::string_view{}
105+
: rest.substr(at + 1);
106+
if (dir.empty()) continue;
107+
std::error_code ec;
108+
auto candidate = std::filesystem::path(dir) / kName;
109+
if (std::filesystem::exists(candidate, ec) && answers_for_a_cross_target(candidate))
110+
return candidate;
111+
}
112+
// AND THE PAYLOAD mcpp ITSELF INSTALLS. A clang on PATH is not
113+
// necessarily one built with the back end this test names --- the host
114+
// this was written on carries a vendor clang with neither RISC-V nor
115+
// AArch64, so a PATH-only search skipped for a reason that has nothing to
116+
// do with what is being tested. mcpp's own LLVM payload has them, and
117+
// every CI shard that resolves an `llvm@` toolchain has downloaded it.
118+
std::error_code ec;
119+
auto home = std::getenv("MCPP_HOME")
120+
? std::filesystem::path(std::getenv("MCPP_HOME"))
121+
: std::filesystem::path(
122+
std::getenv("HOME") ? std::getenv("HOME") : ".") / ".mcpp";
123+
auto payloads = home / "registry" / "data" / "xpkgs" / "xim-x-llvm";
124+
if (std::filesystem::is_directory(payloads, ec))
125+
for (auto const& ver : std::filesystem::directory_iterator(payloads, ec)) {
126+
auto candidate = ver.path() / "bin" / kName;
127+
if (std::filesystem::exists(candidate, ec)
128+
&& answers_for_a_cross_target(candidate))
129+
return candidate;
130+
}
131+
return {};
132+
}
133+
134+
std::filesystem::path clangxx() {
135+
static const std::filesystem::path p = find_a_clang();
136+
return p;
137+
}
138+
67139
// The host's own word size, measured the same way `cenv::realise`'s callers
68140
// would declare it — this test's "declared" values are deliberately chosen
69141
// relative to the REAL host, so a correct declaration is one that could
@@ -295,17 +367,12 @@ namespace {
295367
// Whether this compiler answers for a target it is not hosted on. A GCC
296368
// driver does not take `--target`, and a clang built without the RISC-V
297369
// backend answers nothing useful; both skip.
298-
bool answers_for_riscv() {
299-
TmpCache probe;
300-
auto r = cp::verify(cxx(), {"--target=riscv64-none-elf"}, 0, 0,
301-
{"__riscv"}, {}, probe.dir);
302-
return r.has_value() && r->mismatches.empty();
303-
}
370+
bool answers_for_riscv() { return !clangxx().empty(); }
304371
} // namespace
305372

306373
TEST(CenvProbe, AnArgvWithATargetMeasuresThatTargetAndNotTheHost) {
307-
if (cxx().empty()) GTEST_SKIP() << "no C++ compiler found to probe";
308-
if (!answers_for_riscv()) GTEST_SKIP() << "this compiler does not answer for riscv64-none-elf";
374+
if (clangxx().empty()) GTEST_SKIP() << "no clang++ on PATH";
375+
if (!answers_for_riscv()) GTEST_SKIP() << "this clang does not answer for riscv64-none-elf";
309376
TmpCache cache;
310377
// The freestanding probe's own shape, with the target selection the
311378
// caller (`mcpp.build.prepare`) now supplies. `__linux__` must be absent
@@ -317,23 +384,23 @@ TEST(CenvProbe, AnArgvWithATargetMeasuresThatTargetAndNotTheHost) {
317384
};
318385
std::vector<std::string> defined{"__unix__", "__riscv"};
319386
std::vector<std::string> undefined{"__linux__", "_WIN32"};
320-
auto r = cp::verify(cxx(), argv, 32, 0, defined, undefined, cache.dir);
387+
auto r = cp::verify(clangxx(), argv, 32, 0, defined, undefined, cache.dir);
321388
ASSERT_TRUE(r.has_value()) << r.error();
322389
for (auto const& mm : r->mismatches)
323390
ADD_FAILURE() << mm.fact << ": declared " << mm.declared
324391
<< ", measured " << mm.measured;
325392
}
326393

327394
TEST(CenvProbe, TheSameArgvWithoutATargetMeasuresTheHost) {
328-
if (cxx().empty()) GTEST_SKIP() << "no C++ compiler found to probe";
329-
if (!answers_for_riscv()) GTEST_SKIP() << "this compiler does not answer for riscv64-none-elf";
395+
if (clangxx().empty()) GTEST_SKIP() << "no clang++ on PATH";
396+
if (!answers_for_riscv()) GTEST_SKIP() << "this clang does not answer for riscv64-none-elf";
330397
TmpCache cache;
331398
// The mirror of the test above, and the one that makes it mean
332399
// something: with the target removed, the expectation that held for the
333400
// target must now FAIL. A test that only asserts the fixed shape passes
334401
// identically against a probe that ignores its argv.
335402
std::vector<std::string> argv{"-ffreestanding", "-D__unix__", "-fno-short-wchar"};
336-
auto r = cp::verify(cxx(), argv, 0, 0, {"__riscv"}, {}, cache.dir);
403+
auto r = cp::verify(clangxx(), argv, 0, 0, {"__riscv"}, {}, cache.dir);
337404
ASSERT_TRUE(r.has_value()) << r.error();
338405
EXPECT_FALSE(r->mismatches.empty())
339406
<< "a probe with no target selection must not report the target's "

0 commit comments

Comments
 (0)