test(wasm): the cases the review found
WasmBuildRefusals checks that -flto in compileFlags and in linkFlags, -fno-exceptions and a shared library are each refused with their cause, and that none of them leaves bin/ or build/ behind. With the check disabled, each of them failed on a missing std.cppm instead, after the build directories had been made. WasiSysrootWithoutExceptions also takes its sysroot through missing and without the target's directory, each with a message of its own, checks that a refused build leaves nothing behind, and that a static library passes without libunwind. WasmExceptions catches an exception thrown inside libc++.a (stoi). vector::at throws from a header compiled into the fixture, so the fixture also passed against the libc++ built without exceptions. Its C source uses setjmp, which the old C flags did not compile. An exception that escapes main has to end the run as wasmtime's uncaught exception, where any nonzero exit used to pass, a trap or a timeout included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
45b9f5cbb7
commit
2a05b8e6fb
7 changed files with 171 additions and 20 deletions
|
|
@ -12,16 +12,20 @@ using namespace Crafter;
|
|||
// a sysroot that lacks them (an older wasi-sdk, one built without its
|
||||
// exceptions option) otherwise compiles and then fails the first link with
|
||||
// "unable to find library -lunwind", which does not say why it was asked
|
||||
// for. The check runs before the std module is built, so the first case
|
||||
// needs no working wasm toolchain.
|
||||
// for. A sysroot that is not there at all, or has nothing for the target,
|
||||
// gets a message of its own rather than that one. The checks run before
|
||||
// anything is made, so a refused build leaves no bin/ behind, and they need
|
||||
// no working wasm toolchain.
|
||||
//
|
||||
// A scratch sysroot is taken through three states: no libunwind; libunwind
|
||||
// under eh/; libunwind in the triple's own directory, which the driver
|
||||
// searches after eh/. The last two pass the check and fail later on the
|
||||
// sysroot's empty std module source, which is not what is under test. The
|
||||
// cache is redirected into the scratch directory as well: the std PCM cache
|
||||
// is not keyed on the sysroot, and a PCM built from the fake source must not
|
||||
// land where the real wasm tests read theirs.
|
||||
// A scratch sysroot is taken through these states: missing; without
|
||||
// lib/wasm32-wasip1; without libunwind, for an executable and for a static
|
||||
// library, which links nothing and passes; with libunwind under eh/; with
|
||||
// libunwind in the triple's own directory, which the driver searches after
|
||||
// eh/. The cases that pass the check fail later on the sysroot's empty std
|
||||
// module source, which is not what is under test. The cache is redirected
|
||||
// into the scratch directory as well: the std PCM cache is not keyed on the
|
||||
// sysroot, and a PCM built from the fake source must not land where the real
|
||||
// wasm tests read theirs.
|
||||
|
||||
extern "C" int setenv(const char* name, const char* value, int overwrite);
|
||||
|
||||
|
|
@ -35,14 +39,14 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
BuildResult BuildAgainst(const fs::path& project, const fs::path& sysroot) {
|
||||
BuildResult BuildAgainst(const fs::path& project, const fs::path& sysroot, ConfigurationType type = ConfigurationType::Executable) {
|
||||
Configuration app;
|
||||
app.path = project;
|
||||
app.name = "hello";
|
||||
app.outputName = "hello";
|
||||
app.target = "wasm32-wasip1";
|
||||
app.sysroot = sysroot.string();
|
||||
app.type = ConfigurationType::Executable;
|
||||
app.type = type;
|
||||
std::array<fs::path, 0> ifaces = {};
|
||||
std::array<fs::path, 1> impls = { "main" };
|
||||
app.GetInterfacesAndImplementations(ifaces, impls);
|
||||
|
|
@ -68,16 +72,27 @@ int main() {
|
|||
|
||||
const fs::path sysroot = scratch / "sysroot";
|
||||
const fs::path libDir = sysroot / "lib" / "wasm32-wasip1";
|
||||
fs::create_directories(libDir / "eh");
|
||||
{
|
||||
const BuildResult r = BuildAgainst(project, sysroot);
|
||||
Check(r.result.contains(std::format("no WASI sysroot at {}", sysroot.string())), std::format("a missing sysroot is named as missing: {}", r.result));
|
||||
}
|
||||
|
||||
fs::create_directories(sysroot / "share" / "libc++" / "v1");
|
||||
std::ofstream(sysroot / "share" / "libc++" / "v1" / "std.cppm");
|
||||
{
|
||||
const BuildResult r = BuildAgainst(project, sysroot);
|
||||
Check(r.result.contains(std::format("has nothing for wasm32-wasip1 (no {})", libDir.string())), std::format("a sysroot without the target's directory says so: {}", r.result));
|
||||
}
|
||||
|
||||
fs::create_directories(libDir / "eh");
|
||||
constexpr std::string_view missing = "has no C++ exception support";
|
||||
{
|
||||
const BuildResult r = BuildAgainst(project, sysroot);
|
||||
Check(r.result.contains(missing), std::format("without libunwind the build stops on the sysroot: {}", r.result));
|
||||
Check(r.result.contains((libDir / "eh" / "libunwind.a").string()), std::format("the message names the library it looked for: {}", r.result));
|
||||
Check(!fs::exists(project / "bin") && !fs::exists(project / "build"), "a refused build leaves no bin/ or build/ behind");
|
||||
}
|
||||
Check(!BuildAgainst(project, sysroot, ConfigurationType::LibraryStatic).result.contains(missing), "a static library links nothing and passes without libunwind");
|
||||
|
||||
std::ofstream(libDir / "eh" / "libunwind.a");
|
||||
Check(!BuildAgainst(project, sysroot).result.contains(missing), "libunwind under eh/ passes the check");
|
||||
|
|
|
|||
Loading…
Reference in a new issue