]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
feat(msvc): Add support for caching /sourceDependencies file
authorJoel Rosdahl <joel@rosdahl.net>
Sat, 8 Nov 2025 12:28:13 +0000 (13:28 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 22 Nov 2025 09:36:10 +0000 (10:36 +0100)
src/ccache/argprocessing.cpp
src/ccache/argsinfo.hpp
src/ccache/ccache.cpp
src/ccache/core/result.cpp
src/ccache/core/result.hpp
src/ccache/core/resultretriever.cpp

index a38d342fff206f2d2c0e9bdfe419677c741721ad..7c3d00b18d1e4e05772d55a992ce9d59b87af57b 100644 (file)
@@ -1089,6 +1089,52 @@ process_option_arg(const Context& ctx,
     return Statistic::none;
   }
 
+  const std::string_view source_dep_directives_opt =
+    "-sourceDependencies:directives";
+  if (util::starts_with(arg, source_dep_directives_opt)) {
+    LOG("Compiler option {} is unsupported", args[i]);
+    return Statistic::unsupported_compiler_option;
+  }
+
+  const std::string_view source_dep_opt = "-sourceDependencies";
+  if (util::starts_with(arg, source_dep_opt)) {
+    // The generated file embeds absolute include paths resolved relative to the
+    // actual working directory even when -I uses relative paths. To avoid false
+    // positive cache hits across different working directories, bind the result
+    // key to the actual CWD.
+    //
+    // Note: A future alternative could be to instead disable direct/depend mode
+    // and let the preprocessor create the file instead.
+    LOG("Hashing current working directory since {} is used", arg);
+    state.hash_actual_cwd = true;
+
+    state.add_compiler_only_arg(args[i]);
+
+    if (arg == source_dep_opt) {
+      // /sourceDependencies FILE
+      if (i == args.size() - 1) {
+        LOG("Missing argument to {}", args[i]);
+        return Statistic::bad_compiler_arguments;
+      }
+      state.add_compiler_only_arg_no_hash(args[i + 1]);
+      args_info.output_sd = args[i + 1];
+      ++i;
+    } else {
+      // /sourceDependenciesFILE
+      auto file = std::string_view(args[i]).substr(source_dep_opt.length());
+      if (file == "-") {
+        LOG("Compiler option {} is unsupported", args[i]);
+        return Statistic::unsupported_compiler_option;
+      }
+      if (fs::is_directory(file)) {
+        LOG("{} with directory ({}) is unsupported", args[i], file);
+        return Statistic::unsupported_compiler_option;
+      }
+      args_info.output_sd = file;
+    }
+    return Statistic::none;
+  }
+
   if (config.compiler_type() == CompilerType::gcc) {
     if (arg == "-fdiagnostics-color" || arg == "-fdiagnostics-color=always") {
       state.color_diagnostics = ColorDiagnostics::always;
index 4b1ddb69f7fea76fa87293ef070691409fb2014d..f591449a0f5c9d3a930de56d0b004536accd9970 100644 (file)
@@ -62,6 +62,9 @@ struct ArgsInfo
   // Diagnostic generation information (Clang). Contains pathname if not empty.
   std::filesystem::path output_dia;
 
+  // Source dependencies output file (MSVC). Contains pathname if not empty.
+  std::filesystem::path output_sd;
+
   // Split dwarf information (GCC 4.8 and up). Contains pathname if not empty.
   std::filesystem::path output_dwo;
 
index 5d5e6de0f2f618dd01ec9d0120452507f58e130a..8450def11c4ec8964b61b7a1a9b11c805d9c6402 100644 (file)
@@ -1035,6 +1035,12 @@ write_result(Context& ctx,
     LOG("Diagnostics file {} missing", ctx.args_info.output_dia);
     return false;
   }
+  if (!ctx.args_info.output_sd.empty()
+      && !serializer.add_file(core::result::FileType::source_dependencies,
+                              ctx.args_info.output_sd)) {
+    LOG("Source dependencies file {} missing", ctx.args_info.output_sd);
+    return false;
+  }
   if (ctx.args_info.seen_split_dwarf
       // Only store .dwo file if it was created by the compiler (GCC and Clang
       // behave differently e.g. for "-gsplit-dwarf -g1").
@@ -2862,6 +2868,9 @@ do_cache_compilation(Context& ctx)
   if (!ctx.args_info.output_dia.empty()) {
     LOG("Diagnostics file: {}", ctx.args_info.output_dia);
   }
+  if (!ctx.args_info.output_sd.empty()) {
+    LOG("Source dependencies file: {}", ctx.args_info.output_sd);
+  }
   if (!ctx.args_info.output_dwo.empty()) {
     LOG("Split dwarf file: {}", ctx.args_info.output_dwo);
   }
index 41abfd374bd61425b647e96f6a88f0d0cc7a3811..47a174d482af454b298485acee1b8e8b16597679 100644 (file)
@@ -156,6 +156,9 @@ file_type_to_string(FileType type)
 
   case FileType::ipa_clones:
     return ".000i.ipa-clones";
+
+  case FileType::source_dependencies:
+    return ".sourcedeps.json";
   }
 
   return k_unknown_file_type;
index 7da388c56d585bb3454cf8167ba73d8d7f39b2ba..eb4aa464430497dfd48944e5f79528f70c96057a 100644 (file)
@@ -93,6 +93,9 @@ enum class FileType : UnderlyingFileTypeInt {
   // ipa clones generated by -fdump-ipa-clones, i.e. output file but with a
   // .000i.ipa-clones extension.
   ipa_clones = 12,
+
+  // Source dependencies file specified by MSVC /sourceDependencies.
+  source_dependencies = 13,
 };
 
 const char* file_type_to_string(FileType type);
index e27798d53a9706d87d4642bbea2d7f24dacadd1d..ab0edd187dbd0936a23c33441a50ac5fe95e1e6a 100644 (file)
@@ -201,11 +201,15 @@ ResultRetriever::get_dest_path(FileType file_type) const
       return m_ctx.args_info.output_ci;
     }
     break;
+
   case FileType::ipa_clones:
     if (m_ctx.args_info.generating_ipa_clones) {
       return m_ctx.args_info.output_ipa;
     }
     break;
+
+  case FileType::source_dependencies:
+    return m_ctx.args_info.output_sd;
   }
 
   return {};