From 368ac6f6e34562fe4f22d912c704ffc51e467c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez?= Date: Wed, 9 Jul 2025 23:07:05 +0200 Subject: [PATCH] Stop passing an invalid target to `llvm-mingw`'s cross-compilation wrappers The cross-compilation toolchains distributed by the `llvm-mingw` project for building code for the `*-pc-windows-gnullvm` targets have a wrapper script in place of their `clang` binaries that calls them with a specific target, much like it has been the case with the Android NDK. When `cc-rs` sets a explicit `--target` flag, the wrapper script breaks down, and is no longer able to use the proper linker and libraries. To improve on this situation and make it possible to cross-compile Rust projects that depend on building C code with `cc-rs`, let's skip passing this flag when cross-compilation with such a wrapper script is attempted. --- src/lib.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index fe2d600f..7c494eb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3003,6 +3003,23 @@ impl Build { }; } + // Under cross-compilation scenarios, llvm-mingw's clang executable is just a + // wrapper script that calls the actual clang binary with a suitable `--target` + // argument, much like the Android NDK case outlined above. Passing a target + // argument ourselves in this case will result in an error, as they expect + // targets like `x86_64-w64-mingw32`, and we can't always set such a target + // string because it is specific to this MinGW cross-compilation toolchain. + // + // For example, the following command will always fail due to using an unsuitable + // `--target` argument we'd otherwise pass: + // $ /opt/llvm-mingw-20250613-ucrt-ubuntu-22.04-x86_64/bin/x86_64-w64-mingw32-clang --target=x86_64-pc-windows-gnu dummy.c + // + // Code reference: + // https://github.com/mstorsjo/llvm-mingw/blob/a1f6413e5c21fd74b64137b56167f4fba500d1d8/wrappers/clang-target-wrapper.sh#L31 + if !cfg!(windows) && target.os == "windows" && is_llvm_mingw_wrapper(&tool.path) { + tool.has_internal_target_arg = true; + } + // If we found `cl.exe` in our environment, the tool we're returning is // an MSVC-like tool, *and* no env vars were set then set env vars for // the tool that we're returning. @@ -4171,6 +4188,17 @@ fn android_clang_compiler_uses_target_arg_internally(clang_path: &Path) -> bool false } +fn is_llvm_mingw_wrapper(clang_path: &Path) -> bool { + if let Some(filename) = clang_path + .file_name() + .and_then(|file_name| file_name.to_str()) + { + filename.ends_with("-w64-mingw32-clang") || filename.ends_with("-w64-mingw32-clang++") + } else { + false + } +} + // FIXME: Use parsed target. fn autodetect_android_compiler(raw_target: &str, gnu: &str, clang: &str) -> String { let new_clang_key = match raw_target {