From b6a9eaf548f581f65a8f2fe6d6003ff6129d25e3 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Mon, 3 Feb 2025 21:39:14 +0000 Subject: [PATCH] Bug 1943149 - build(swgl): work around broken (upstream) `cc::Tool` detection of `clang --driver-mode=cl` r=gfx-reviewers,nical With the current version of `cc`, we depend on behavior where, if `CC` is set to something like `clang --driver-mode=cl`, we expect to be able to use arguments on the command line a la MSVC's `cl.exe`. We were actually the original contributors of a heuristic to detect this in the `cc` crate, and it's served us well. In `cc` upstream since 1.0.89, a new heuristic for detecting compiler families in `cc::Tool` was introduced which does not have the desired behavior, and misclassifies the above case as being `clang`-like, rather than `cl`-like. The heuristic we originally submitted upstream is now in a fallback path which does not get used for our case. This causes `cc`'s default flags and APIs like `cc::Tool::is_like_msvc` to be incorrect. `swgl`, in particular, breaks because of this, since it's opinionated on the arguments it wants to provide to compilers. Work around the above regression by detecting checking `Tool`s' base command and "wrapper arguments" to see if we have a wrapper argument matching `--driver-mode=cl`. If so, provide `cl`-like arguments in `swgl`, rather than `clang`-like arguments. This behavior has been fixed upstream; see . Once released, we can consume it and revert this patch. Differential Revision: https://phabricator.services.mozilla.com/D236305 --- gfx/wr/swgl/build.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/gfx/wr/swgl/build.rs b/gfx/wr/swgl/build.rs index 71546e474872..6a4d267926c9 100644 --- a/gfx/wr/swgl/build.rs +++ b/gfx/wr/swgl/build.rs @@ -116,7 +116,7 @@ fn translate_shader( let mut build = cc::Build::new(); build.no_default_flags(true); if let Ok(tool) = build.try_get_compiler() { - if tool.is_like_msvc() { + if is_like_msvc(&tool) { build.flag("/EP"); if tool.path().to_str().is_some_and(|p| p.contains("clang")) { build.flag("/clang:-undef"); @@ -185,7 +185,7 @@ fn main() { build.cpp(true); if let Ok(tool) = build.try_get_compiler() { - if tool.is_like_msvc() { + if is_like_msvc(&tool) { build .flag("/std:c++17") .flag("/EHs-") @@ -212,7 +212,7 @@ fn main() { // instructions makes things easier on the processor and in places where it matters we can // probably explicitly use reciprocal instructions and avoid the refinement step. // Also, allow checks for non-finite values which fast-math may disable. - if tool.is_like_msvc() { + if is_like_msvc(&tool) { build .flag("/fp:fast") .flag("-Xclang") @@ -252,3 +252,20 @@ impl Drop for EnvVarGuard { } } } + +fn is_like_msvc(tool: &cc::Tool) -> bool { + tool.is_like_msvc() || { + // `mozilla-central` does this funky thing where it replaces `clang-cl.exe` with + // `clang.exe --driver-mode=cl`, which isn't considered by `Tool::is_like_msvc`, _but_ + // it forces the CLI to adhere to a `cl`-like interface and reject naively `clang`-like + // arguments. + // + // See also `config/static-checking-config.mk`: + // + let starts_with_driver_mode_cl = |arg: &std::ffi::OsStr| { + arg.to_str() + .is_some_and(|a| a.starts_with("--driver-mode=cl")) + }; + tool.is_like_clang() && tool.to_command().get_args().any(starts_with_driver_mode_cl) + } +}