From 79cbc5f29e362019356cb2fb1f4d5bb01a0bbdaf Mon Sep 17 00:00:00 2001 From: AJIOB Date: Fri, 3 Apr 2026 17:48:01 +0300 Subject: [PATCH] Don't wait depfiles for gcc/clang preprocessed inputs Fixes #2664 --- src/compiler/compiler.rs | 2 +- src/compiler/gcc.rs | 93 +++++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 1d9ccff75..20a064faf 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -615,7 +615,7 @@ where // In this mode, cache entries are exclusively distinguished by their preprocessed // source contents. But two files may differ in their names and / or the names of // included files while still producing the same preprocessed output, so they get the - // same cache entry. That entry will have wrong (file names) dependency informaton in + // same cache entry. That entry will have wrong (file names) dependency information in // the dependency file except for the compilation unit that originally produced it. // Since we did local preprocessing, that should already have produced the dependency // file - just leave that one alone and don't overwrite it from the cache. diff --git a/src/compiler/gcc.rs b/src/compiler/gcc.rs index 5613ac892..7bd4f9689 100644 --- a/src/compiler/gcc.rs +++ b/src/compiler/gcc.rs @@ -699,23 +699,27 @@ where ); profile_generate = true; } - if need_explicit_dep_target { - dependency_args.push(dep_flag); - dependency_args.push(dep_target.unwrap_or_else(|| output.clone().into_os_string())); - } - if let DepArgumentRequirePath::Missing = need_explicit_dep_argument_path { - dependency_args.push(OsString::from("-MF")); - dependency_args.push(Path::new(&output).with_extension("d").into_os_string()); - } - if let Some(path) = dep_path { - outputs.insert( - "d", - ArtifactDescriptor { - path: path.clone(), - optional: false, - }, - ); + // If the language doesn't need preprocessing, it doesn't generate a dependency file. See issue #2664 + if language.needs_c_preprocessing() { + if need_explicit_dep_target { + dependency_args.push(dep_flag); + dependency_args.push(dep_target.unwrap_or_else(|| output.clone().into_os_string())); + } + if let DepArgumentRequirePath::Missing = need_explicit_dep_argument_path { + dependency_args.push(OsString::from("-MF")); + dependency_args.push(Path::new(&output).with_extension("d").into_os_string()); + } + + if let Some(path) = dep_path { + outputs.insert( + "d", + ArtifactDescriptor { + path: path.clone(), + optional: false, + }, + ); + } } if let Some(path) = serialize_diagnostics { @@ -1122,6 +1126,7 @@ impl Iterator for ExpandIncludeFile<'_> { #[cfg(test)] mod test { use fs::File; + use itertools::assert_equal; use std::io::Write; use super::*; @@ -1404,6 +1409,62 @@ mod test { assert!(profile_generate); } + #[test] + fn test_parse_arguments_depfile_for_raw_assembly_gcc() { + let args = stringvec!["-c", "foo.s", "-o", "foo.o", "-MD", "-MF", "foo.d"]; + let ParsedArguments { + input, + language, + outputs, + preprocessor_args, + .. + } = match parse_arguments_(args, false) { + CompilerArguments::Ok(args) => args, + o => panic!("Got unexpected parse result: {:?}", o), + }; + assert_eq!(Some("foo.s"), input.to_str()); + assert_eq!(Language::Assembler, language); + assert_equal( + outputs, + vec![( + "obj", + ArtifactDescriptor { + path: "foo.o".into(), + optional: false, + }, + )], + ); + assert!(preprocessor_args.is_empty()); + } + + #[test] + fn test_parse_arguments_depfile_for_preprocessed_c_clang() { + let args = stringvec!["-c", "foo.i", "-o", "foo.o", "-MD", "-MF", "foo.d"]; + let ParsedArguments { + input, + language, + outputs, + preprocessor_args, + .. + } = match parse_arguments_clang(args, false) { + CompilerArguments::Ok(args) => args, + o => panic!("Got unexpected parse result: {:?}", o), + }; + assert_eq!(Some("foo.i"), input.to_str()); + assert_eq!(Language::CPreprocessed, language); + assert_equal( + outputs, + vec![( + "obj", + ArtifactDescriptor { + path: "foo.o".into(), + optional: false, + }, + )], + ); + assert!(preprocessor_args.is_empty()); + } + #[test] fn test_parse_arguments_test_coverage_outputs_gcno() { let args = stringvec!["-ftest-coverage", "-c", "foo.cpp", "-o", "foo.o"];