]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Disable base directory when using MSVC's /Yc option
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 26 Mar 2026 08:13:39 +0000 (09:13 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 26 Mar 2026 11:53:41 +0000 (12:53 +0100)
When creating a precompiled header (PCH), MSVC does not like relative
paths for /Yc and /FI arguments, so don't rewrite paths to relative in
that case.

Fixes #1710.

src/ccache/argprocessing.cpp
unittest/test_argprocessing.cpp

index 535c4a176b6a068e7d84fc4a41328454e724d7ab..a130e907a2053cdf262f32451356ba4fd414eb06 100644 (file)
@@ -1405,13 +1405,25 @@ process_arg(const Context& ctx,
             Config& config,
             util::Args& args,
             size_t& args_index,
-            ArgumentProcessingState& state)
+            ArgumentProcessingState& state,
+            bool& restart)
 {
-  const auto processed =
+  const auto statistic =
     process_option_arg(ctx, args_info, config, args, args_index, state);
-  if (processed) {
-    const auto& error = *processed;
-    return error;
+
+  if (statistic && *statistic != Statistic::none) {
+    return *statistic; // error found
+  }
+
+  if (state.found_Yc && config.is_compiler_group_msvc()
+      && !config.base_dirs().empty()) {
+    LOG("Creating PCH with MSVC, disabling base directory");
+    config.set_base_dirs({});
+    restart = true;
+  }
+
+  if (statistic) {
+    return *statistic; // processed option without error
   }
 
   size_t& i = args_index;
@@ -1461,19 +1473,34 @@ process_args(Context& ctx)
   ArgsInfo& args_info = ctx.args_info;
   Config& config = ctx.config;
 
-  // args is a copy of the original arguments given to the compiler but with
-  // arguments from @file and similar constructs expanded. It's only used as a
-  // temporary data structure to loop over.
-  util::Args args = ctx.orig_args;
   ArgumentProcessingState state;
 
-  state.add_common_arg(args[0]); // Compiler
-
   std::optional<Statistic> argument_error;
-  for (size_t i = 1; i < args.size(); i++) {
-    const auto error = process_arg(ctx, args_info, ctx.config, args, i, state);
-    if (error != Statistic::none && !argument_error) {
-      argument_error = error;
+  while (true) {
+    // args is a copy of the original arguments given to the compiler but where
+    // arguments from @file and similar constructs will be expanded. It's only
+    // used as a temporary data structure to loop over.
+    util::Args args = ctx.orig_args;
+    args_info = {};
+    state = {};
+    argument_error = std::nullopt;
+
+    state.add_common_arg(args[0]); // Compiler
+
+    bool restart = false;
+    for (size_t i = 1; i < args.size(); i++) {
+      const auto statistic =
+        process_arg(ctx, args_info, ctx.config, args, i, state, restart);
+      if (restart) {
+        break;
+      }
+      if (statistic != Statistic::none && !argument_error) {
+        argument_error = statistic;
+      }
+    }
+
+    if (!restart) {
+      break;
     }
   }
 
index 1b9f548f6f85147e5ca268e99408bec3700858f1..f031edc895d9feca3739901e151a6bdf58681add 100644 (file)
@@ -765,6 +765,51 @@ TEST_CASE("MSVC PCH options")
   }
 }
 
+TEST_CASE("MSVC /Yc in response file disables base_dir rewriting")
+{
+  TestContext test_context;
+  Context ctx;
+  ctx.config.set_compiler_type(CompilerType::msvc);
+  ctx.config.set_base_dir(get_root());
+  REQUIRE(util::write_file("pch.h", ""));
+  REQUIRE(util::write_file("pch.cpp", ""));
+
+  const auto pch_path = ctx.actual_cwd / "pch.cpp.pch";
+  const auto include_path = ctx.actual_cwd / "pch.h";
+  const auto output_path = ctx.actual_cwd / "pch.cpp.obj";
+  const auto source_path = ctx.actual_cwd / "pch.cpp";
+  REQUIRE(util::write_file("pch.rsp",
+                           FMT("/Yc /Fp{} /FI{} /Fo{} /c {}\n",
+                               pch_path,
+                               include_path,
+                               output_path,
+                               source_path)));
+
+  ctx.orig_args = Args::from_string("cl.exe @pch.rsp");
+  const auto result = process_args(ctx);
+
+  REQUIRE(result);
+  CHECK(ctx.args_info.generating_pch);
+  CHECK(ctx.args_info.output_obj == output_path);
+  CHECK(result->preprocessor_args.to_string()
+        == FMT("cl.exe /Yc -Fp{} -FI{}", pch_path, include_path));
+}
+
+TEST_CASE("MSVC /Yc with base_dir preserves later argument errors")
+{
+  TestContext test_context;
+  Context ctx;
+  ctx.config.set_compiler_type(CompilerType::msvc);
+  ctx.config.set_base_dir(get_root());
+  REQUIRE(util::write_file("pch.cpp", ""));
+
+  ctx.orig_args = Args::from_string("cl.exe /Yc /c pch.cpp /FI");
+
+  const auto result = process_args(ctx);
+
+  CHECK(result.error() == Statistic::bad_compiler_arguments);
+}
+
 TEST_CASE("MSVC PCH options with empty -Yc")
 {
   TestContext test_context;