diff --git a/implementations/Crafter.Build-Clang.cpp b/implementations/Crafter.Build-Clang.cpp index 35b64d7..ba9f3d7 100644 --- a/implementations/Crafter.Build-Clang.cpp +++ b/implementations/Crafter.Build-Clang.cpp @@ -256,6 +256,15 @@ fs::path Crafter::StdPcmDir(const Configuration& config) { // the consuming TUs see a target-feature mismatch. Suffix the cache dir // with the variant flags when present. std::string stdPcmKey = std::format("{}-{}-{}", config.target, config.march, GetToolchain().Key()); + // The flags every wasm unit gets are compiled into the std PCM as well, + // and the importing units have to match them. Two releases that share a + // cache and a compiler, as the Flatpak's branches do, would otherwise + // take turns rebuilding this one std PCM, each time underneath the PCMs + // built against the previous one, and clang crashes on those rather than + // rejecting them. + if (config.target.starts_with("wasm32")) { + stdPcmKey += std::format("-{:08x}", static_cast(std::hash{}(WasmBaselineFlags))); + } for (const std::string& f : config.wasmVariantFlags) { stdPcmKey += "+"; for (char c : f) stdPcmKey += (c == '/' || c == '\\') ? '_' : c; @@ -263,6 +272,12 @@ fs::path Crafter::StdPcmDir(const Configuration& config) { return GetCacheDir()/stdPcmKey; } +std::string Crafter::WasmCompileFlags(const Configuration& config) { + std::string flags = std::format(" {}", WasmBaselineFlags); + for (const std::string& f : config.wasmVariantFlags) flags += std::format(" {}", f); + return flags; +} + fs::path Crafter::ExpectedOutput(const Configuration& config) { const fs::path dir = config.BinDir(); const bool mingwTarget = config.target == "x86_64-w64-mingw32"; @@ -317,15 +332,11 @@ CompileCommand Crafter::GetCompileCommand(const Configuration& config) { if (isWasm) { // -mllvm is consumed by codegen but not the link driver, which is the // same command line; quiet the unused-flag warning rather than split - // compile and link commands. - out.command += " -fno-exceptions -msimd128 -fno-c++-static-destructors -mllvm -wasm-enable-sjlj -D_WASI_EMULATED_SIGNAL -Wno-unused-command-line-argument"; - // Active variant pass (see the variant driver at the end of Build): - // extra codegen flags (e.g. -mrelaxed-simd) applied to every TU. Empty - // for the baseline build. Part of VariantId, so these objects/PCMs - // land in their own dir. - for (const std::string& f : config.wasmVariantFlags) { - out.command += std::format(" {}", f); - } + // compile and link commands. An active variant pass (see the variant + // driver at the end of Build) adds its codegen flags (e.g. + // -mrelaxed-simd) to every TU; they are part of VariantId, so those + // objects/PCMs land in their own dir. + out.command += std::format("{} -Wno-unused-command-line-argument", WasmCompileFlags(config)); } if (config.target == "x86_64-w64-mingw32") { // mingw libstdc++ defines TLS via __emutls_v.* (emulated TLS); without @@ -405,12 +416,14 @@ CompileCommand Crafter::GetCompileCommand(const Configuration& config) { // (cross-TU inlining) plus dead-section GC and safe identical-code folding. // Default-on in Release, never Debug (keeps builds fast and debuggable). // Excluded for wasm32 — its -mllvm/sjlj codegen flags don't compose with - // LTO here — and for nvcc .cu objects below (they can't emit LLVM bitcode, - // so they link in as ordinary objects alongside the bitcode ones). ThinLTO - // rather than monolithic -flto so link time and memory scale with arbitrary - // user project sizes. Compile-side flags (-flto, -ffunction/-fdata-sections) - // ride on `command`, which is reused as the link base; the link-only -Wl - // flags go on linkExtras so they don't warn on each -c compile. + // LTO here, and wasi-sdk lists exceptions under LTO as broken + // (WebAssembly/wasi-sdk#629) — and for nvcc .cu objects below (they can't + // emit LLVM bitcode, so they link in as ordinary objects alongside the + // bitcode ones). ThinLTO rather than monolithic -flto so link time and + // memory scale with arbitrary user project sizes. Compile-side flags + // (-flto, -ffunction/-fdata-sections) ride on `command`, which is reused + // as the link base; the link-only -Wl flags go on linkExtras so they + // don't warn on each -c compile. out.useLto = !config.debug && !isWasm; out.ltoCompileFlags = out.useLto ? " -flto=thin -ffunction-sections -fdata-sections" : ""; out.ltoLinkFlags = out.useLto ? " -flto=thin -Wl,--gc-sections -Wl,--icf=safe" : ""; @@ -1139,6 +1152,12 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map.wasm (produced by Build's - // variant driver); the baseline maps to outputName.wasm. Even with no - // declared variants we still emit a one-entry manifest so the runtime has a + // as the fallback. Every entry carries WasmBaselineProbes besides its own: + // every file is built with the baseline flags, so an engine without + // exception handling can run none of them, and runtime.js tells it so + // instead of failing to compile the module. A variant with a non-empty + // label maps to outputName.