From bbc61bd81a3f7d9c815e5dd3cb4a5e0ba2a3bed4 Mon Sep 17 00:00:00 2001 From: naoNao89 <90588855+naoNao89@users.noreply.github.com> Date: Wed, 17 Dec 2025 19:04:41 +0700 Subject: [PATCH] Fix #359: Support language-selection flags in is_flag_supported() Changed flag validation from file-based to stdin-based compilation to support language-selection flags like -xassembler-with-cpp. This also improves flag validation by ensuring invalid flags are properly rejected. - Use stdin compilation with explicit language for most flags - For -x flags, let the flag determine the language - Add -Werror=unknown-warning-option for clang to reject invalid -W flags - Remove unused ensure_check_file() method - Add regression test for assembly flags --- src/lib.rs | 96 +++++++++++++++++++++++++++++++++++---------------- tests/test.rs | 25 ++++++++++++++ 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 71ec1caf..65af84de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1425,25 +1425,6 @@ impl Build { ) } - fn ensure_check_file(&self) -> Result { - let out_dir = self.get_out_dir()?; - let src = if self.cuda { - assert!(self.cpp); - out_dir.join("flag_check.cu") - } else if self.cpp { - out_dir.join("flag_check.cpp") - } else { - out_dir.join("flag_check.c") - }; - - if !src.exists() { - let mut f = fs::File::create(&src)?; - write!(f, "int main(void) {{ return 0; }}")?; - } - - Ok(src) - } - fn is_flag_supported_inner( &self, flag: &OsStr, @@ -1467,7 +1448,6 @@ impl Build { } let out_dir = self.get_out_dir()?; - let src = self.ensure_check_file()?; let obj = out_dir.join("flag_check"); let mut compiler = { @@ -1499,6 +1479,14 @@ impl Build { // Avoid reporting that the arg is unsupported just because the // compiler complains that it wasn't used. compiler.push_cc_arg("-Wno-unused-command-line-argument".into()); + // Turn unknown warning options into errors so invalid -W flags are properly rejected + compiler.push_cc_arg("-Werror=unknown-warning-option".into()); + } + + if compiler.is_like_gnu() || compiler.is_like_clang() { + // Turn warnings into errors to ensure invalid flags are rejected + // (e.g., -std=c++11 for C code, invalid warning flags) + compiler.push_cc_arg("-Werror".into()); } let mut cmd = compiler.to_command(); @@ -1522,13 +1510,10 @@ impl Build { // https://github.com/rust-lang/cc-rs/issues/1423 cmd.arg("-c"); - if compiler.supports_path_delimiter() { - cmd.arg("--"); - } - - cmd.arg(&src); - - if compiler.is_like_msvc() { + // MSVC doesn't support stdin compilation, so use file-based approach for it + // For GCC/Clang, use stdin to support language-selection flags like -xassembler-with-cpp + // See: https://github.com/rust-lang/cc-rs/issues/359 + let is_supported = if compiler.is_like_msvc() { // On MSVC we need to make sure the LIB directory is included // so the CRT can be found. for (key, value) in &tool.env { @@ -1537,10 +1522,61 @@ impl Build { break; } } - } - let output = cmd.current_dir(out_dir).output()?; - let is_supported = output.status.success() && output.stderr.is_empty(); + // Use file-based compilation for MSVC + let src = if self.cuda { + assert!(self.cpp); + out_dir.join("flag_check.cu") + } else if self.cpp { + out_dir.join("flag_check.cpp") + } else { + out_dir.join("flag_check.c") + }; + + if !src.exists() { + let mut f = fs::File::create(&src)?; + write!(f, "int main(void) {{ return 0; }}")?; + } + + if compiler.supports_path_delimiter() { + cmd.arg("--"); + } + cmd.arg(&src); + + let output = cmd.current_dir(&out_dir).output()?; + output.status.success() && output.stderr.is_empty() + } else { + // Use stdin compilation for GCC/Clang + let flag_str = flag.to_string_lossy(); + let is_language_flag = flag_str.starts_with("-x"); + + if !is_language_flag { + // For non-language-selection flags, explicitly specify the language + // to ensure proper validation (e.g., -std=c++11 should fail for C code) + if self.cpp { + cmd.arg("-xc++"); + } else if self.cuda { + cmd.arg("-xcuda"); + } else { + cmd.arg("-xc"); + } + } + // For language-selection flags (like -xassembler-with-cpp), don't specify + // a language - let the flag itself determine it + + cmd.arg("-"); + + let mut child = cmd + .stdin(std::process::Stdio::piped()) + .current_dir(&out_dir) + .spawn()?; + + // Close stdin immediately (empty input is sufficient for flag validation) + drop(child.stdin.take()); + + let output = child.wait_with_output()?; + output.status.success() && output.stderr.is_empty() + }; self.build_cache .known_flag_support_status_cache diff --git a/tests/test.rs b/tests/test.rs index eae9c332..18d290eb 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -417,6 +417,31 @@ fn gnu_flag_if_supported_cpp() { test.cmd(0).must_have("-std=c++11"); } +// Regression test for issue #359: is_flag_supported should work with +// language-specific flags (e.g., assembly flags) by using stdin compilation +// instead of file-based compilation to avoid file extension issues. +#[cfg(not(windows))] +#[test] +fn is_flag_supported_assembly_flags() { + let test = Test::gnu(); + + // Test that assembly-specific flags are correctly detected as supported + let build = test.gcc(); + let result = build.is_flag_supported("-xassembler-with-cpp"); + assert!( + result.is_ok() && result.unwrap(), + "Assembly flag -xassembler-with-cpp should be supported" + ); + + // Test that normal C flags still work + let build = test.gcc(); + let result = build.is_flag_supported("-Wall"); + assert!( + result.is_ok() && result.unwrap(), + "C flag -Wall should be supported" + ); +} + #[test] fn gnu_static() { reset_env();