]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
feat: Add support for MSVC /Yc option (precompiled headers) (#1384)
authorClemens Wasser <clemens.wasser@gmail.com>
Wed, 24 Jan 2024 19:58:47 +0000 (20:58 +0100)
committerGitHub <noreply@github.com>
Wed, 24 Jan 2024 19:58:47 +0000 (20:58 +0100)
src/ArgsInfo.hpp
src/argprocessing.cpp
src/ccache.cpp
src/compopt.cpp
src/core/Result.cpp
src/core/Result.hpp
src/core/ResultRetriever.cpp
unittest/test_argprocessing.cpp

index e577929a9622842f47b3f5925944830a6c4eca2b..ee78a8357b13eaeb9fbe2aba0c58e951c4a87c8f 100644 (file)
@@ -93,6 +93,9 @@ struct ArgsInfo
   // (--serialize-diagnostics)?
   bool generating_diagnostics = false;
 
+  // Are we generating a pch file (msvc -Yc)?
+  bool generating_pch = false;
+
   // Whether to strip color codes from diagnostic messages on output.
   bool strip_diagnostics_colors = false;
 
index eebe7e926603d7f5bc18ab31fe47a3d8a36d2f7e..9f6001dd8f936b6aaf39c8b56a0ef69a43e70a92 100644 (file)
@@ -67,6 +67,8 @@ struct ArgumentProcessingState
   bool found_pch = false;
   bool found_fpch_preprocess = false;
   bool found_Yu = false;
+  bool found_Yc = false;
+  std::string found_Fp_file;
   bool found_valid_Fp = false;
   bool found_syntax_only = false;
   ColorDiagnostics color_diagnostics = ColorDiagnostics::automatic;
@@ -143,6 +145,13 @@ detect_pch(const std::string& option,
   // anything just because it has a corresponding precompiled header,
   // because Clang doesn't behave that way either.
   std::string pch_file;
+  if (option == "-Yc") {
+    state.found_Yc = true;
+    if (!state.found_Fp_file.empty()) {
+      included_pch_file = state.found_Fp_file;
+      return true;
+    }
+  }
   if (option == "-Yu") {
     state.found_Yu = true;
     if (state.found_valid_Fp) { // Use file set by -Fp.
@@ -161,6 +170,13 @@ detect_pch(const std::string& option,
     if (!fs::path(file).has_extension()) {
       file += ".pch";
     }
+
+    state.found_Fp_file = file;
+
+    if (state.found_Yc) {
+      included_pch_file = state.found_Fp_file;
+      return true;
+    }
     if (DirEntry(file).is_regular_file()) {
       state.found_valid_Fp = true;
       if (!state.found_Yu) {
@@ -398,7 +414,7 @@ process_option_arg(const Context& ctx,
 
   // These are always too hard.
   if (compopt_too_hard(arg) || util::starts_with(arg, "-fdump-")
-      || util::starts_with(arg, "-MJ") || util::starts_with(arg, "-Yc")
+      || util::starts_with(arg, "-MJ")
       || util::starts_with(arg, "--config-system-dir=")
       || util::starts_with(arg, "--config-user-dir=")) {
     LOG("Compiler option {} is unsupported", args[i]);
@@ -1056,7 +1072,7 @@ process_option_arg(const Context& ctx,
 
   // Detect PCH for options with concatenated path (relative or absolute).
   if (util::starts_with(arg, "-include") || util::starts_with(arg, "-Fp")
-      || util::starts_with(arg, "-Yu")) {
+      || util::starts_with(arg, "-Yu") || util::starts_with(arg, "-Yc")) {
     const size_t path_pos = util::starts_with(arg, "-include") ? 8 : 3;
     if (!detect_pch(arg.substr(0, path_pos),
                     arg.substr(path_pos),
@@ -1066,6 +1082,9 @@ process_option_arg(const Context& ctx,
       return Statistic::bad_compiler_arguments;
     }
 
+    if (state.found_Yc) {
+      args_info.generating_pch = true;
+    }
     // Fall through to the next section, so intentionally not returning here.
   }
 
index 260bcab7a75d7d24b343d400a9fe10e60c047baf..3e6e0338f37e2c4c9f72933103b81e8153473fb2 100644 (file)
@@ -369,7 +369,7 @@ remember_include_file(Context& ctx,
   Hash::Digest file_digest;
 
   const bool is_pch = is_precompiled_header(path);
-  if (is_pch) {
+  if (is_pch && !ctx.args_info.generating_pch) {
     if (ctx.args_info.included_pch_file.empty()) {
       LOG("Detected use of precompiled header: {}", path);
     }
@@ -597,7 +597,8 @@ process_preprocessed_file(Context& ctx, Hash& hash, const std::string& path)
 
   // Explicitly check the .gch/.pch/.pth file as Clang does not include any
   // mention of it in the preprocessed output.
-  if (!ctx.args_info.included_pch_file.empty()) {
+  if (!ctx.args_info.included_pch_file.empty()
+      && !ctx.args_info.generating_pch) {
     std::string pch_path =
       Util::make_relative_path(ctx, ctx.args_info.included_pch_file);
     hash.hash(pch_path);
@@ -641,7 +642,8 @@ result_key_from_depfile(Context& ctx, Hash& hash)
 
   // Explicitly check the .gch/.pch/.pth file as it may not be mentioned in the
   // dependencies output.
-  if (!ctx.args_info.included_pch_file.empty()) {
+  if (!ctx.args_info.included_pch_file.empty()
+      && !ctx.args_info.generating_pch) {
     std::string pch_path =
       Util::make_relative_path(ctx, ctx.args_info.included_pch_file);
     hash.hash(pch_path);
@@ -700,7 +702,8 @@ result_key_from_includes(Context& ctx, Hash& hash, std::string_view stdout_data)
 
   // Explicitly check the .pch file as it is not mentioned in the
   // includes output.
-  if (!ctx.args_info.included_pch_file.empty()) {
+  if (!ctx.args_info.included_pch_file.empty()
+      && !ctx.args_info.generating_pch) {
     std::string pch_path =
       Util::make_relative_path(ctx, ctx.args_info.included_pch_file);
     hash.hash(pch_path);
@@ -895,6 +898,11 @@ write_result(Context& ctx,
     LOG("Object file {} missing", ctx.args_info.output_obj);
     return false;
   }
+  if (ctx.args_info.generating_pch
+      && !serializer.add_file(core::Result::FileType::included_pch_file,
+                              ctx.args_info.included_pch_file)) {
+    LOG("PCH file {} missing", ctx.args_info.included_pch_file);
+  }
   if (ctx.args_info.generating_dependencies
       && !serializer.add_file(core::Result::FileType::dependency,
                               ctx.args_info.output_dep)) {
index 4a0148b465aad0a78a7c3968e84c897fb0e0aa6d..01ad88e8fcae12243f15ceb2018be5d1bae99a46 100644 (file)
@@ -95,7 +95,7 @@ const CompOpt compopts[] = {
   {"-Xcompiler", AFFECTS_CPP | TAKES_ARG}, // nvcc
   {"-Xlinker", TAKES_ARG | TAKES_CONCAT_ARG | AFFECTS_COMP},
   {"-Xpreprocessor", AFFECTS_CPP | TOO_HARD_DIRECT | TAKES_ARG},
-  {"-Yc", TAKES_ARG | TOO_HARD},                                    // msvc
+  {"-Yc", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
   {"-Yu", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
   {"-all_load", AFFECTS_COMP},
   {"-analyze", TOO_HARD}, // Clang
index 5189c30a1e8e887b55170073d55db8eefa09d52a..24b7f379c294a820f5524caeb5027271961323a4 100644 (file)
@@ -148,6 +148,9 @@ file_type_to_string(FileType type)
 
   case FileType::assembler_listing:
     return ".al";
+
+  case FileType::included_pch_file:
+    return ".pch";
   }
 
   return k_unknown_file_type;
index 3080f71956d9e8ea5ca0212adec39a25907a7170..db796a11a7b9e184fbbfb6bfcbc5dda78f84d2a7 100644 (file)
@@ -81,6 +81,9 @@ enum class FileType : UnderlyingFileTypeInt {
 
   // Assembler listing file from -Wa,-a=file.
   assembler_listing = 9,
+
+  // PCH file created by msvc additionally to the obj file
+  included_pch_file = 10,
 };
 
 const char* file_type_to_string(FileType type);
index 9b8bc2ebf64def3bce8db44b4bae8c4c4f3d8184..8f4a5567b482d22f2ccff937b87911db2fd4c7e4 100644 (file)
@@ -199,6 +199,9 @@ ResultRetriever::get_dest_path(FileType file_type) const
 
   case FileType::assembler_listing:
     return m_ctx.args_info.output_al;
+
+  case FileType::included_pch_file:
+    return m_ctx.args_info.included_pch_file;
   }
 
   return {};
index f9941be2f99ed41789eba9df1822bdfa88572691..109e06f46a6ed2dad370cad247164a82ccca6494 100644 (file)
@@ -735,6 +735,49 @@ TEST_CASE("MSVC options"
   CHECK(result.compiler_args.to_string() == "cl.exe /foobar -c");
 }
 
+TEST_CASE("MSVC PCH options")
+{
+  TestContext test_context;
+  Context ctx;
+  ctx.config.set_compiler_type(CompilerType::msvc);
+  util::write_file("foo.cpp", "");
+  util::write_file("pch.h", "");
+  util::write_file("pch.cpp", "");
+
+  SUBCASE("Create PCH")
+  {
+    ctx.orig_args = Args::from_string(
+      "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h /Fopch.cpp.obj /c pch.cpp");
+    const ProcessArgsResult result = process_args(ctx);
+    REQUIRE(!result.error);
+    CHECK(ctx.args_info.generating_pch);
+    CHECK(ctx.args_info.included_pch_file == "pch.cpp.pch");
+    CHECK(ctx.args_info.output_obj == "pch.cpp.obj");
+    CHECK(result.preprocessor_args.to_string()
+          == "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h");
+    CHECK(result.compiler_args.to_string()
+          == "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h -c");
+  }
+
+  util::write_file("pch.cpp.pch", "");
+  ctx.config.update_from_map({{"sloppiness", "pch_defines,time_macros"}});
+
+  SUBCASE("Consume PCH")
+  {
+    ctx.orig_args = Args::from_string(
+      "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h /Fofoo.cpp.obj /c foo.cpp");
+    const ProcessArgsResult result = process_args(ctx);
+    REQUIRE(!result.error);
+    CHECK(!ctx.args_info.generating_pch);
+    CHECK(ctx.args_info.included_pch_file == "pch.cpp.pch");
+    CHECK(ctx.args_info.output_obj == "foo.cpp.obj");
+    CHECK(result.preprocessor_args.to_string()
+          == "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h");
+    CHECK(result.compiler_args.to_string()
+          == "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h -c");
+  }
+}
+
 TEST_CASE("MSVC debug information format options")
 {
   TestContext test_context;