浏览代码

Multi-Ninja: Fix reusable PCHs for MSVC

Fixes: #20721
Cristian Adam 5 年之前
父节点
当前提交
1f791eb160
共有 2 个文件被更改,包括 150 次插入95 次删除
  1. 145 95
      Source/cmLocalGenerator.cxx
  2. 5 0
      Source/cmLocalGenerator.h

+ 145 - 95
Source/cmLocalGenerator.cxx

@@ -2569,6 +2569,8 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
     std::vector<cmSourceFile*> sources;
     std::vector<cmSourceFile*> sources;
     target->GetSourceFiles(sources, config);
     target->GetSourceFiles(sources, config);
 
 
+    const std::string configUpper = cmSystemTools::UpperCase(config);
+
     for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
     for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
       auto langSources = std::count_if(
       auto langSources = std::count_if(
         sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
         sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
@@ -2642,106 +2644,45 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 
 
               if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
               if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
 
 
-                const std::string pdb_prefix =
-                  this->GetGlobalGenerator()->IsMultiConfig()
-                  ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
-                  : "";
-
-                const std::string target_compile_pdb_dir = cmStrCat(
-                  target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
-                  "/", target->GetName(), ".dir/");
-
-                const std::string copy_script =
-                  cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
-                cmGeneratedFileStream file(copy_script);
-
-                file << "# CMake generated file\n";
-                for (auto extension : { ".pdb", ".idb" }) {
-                  const std::string from_file =
-                    cmStrCat(reuseTarget->GetLocalGenerator()
-                               ->GetCurrentBinaryDirectory(),
-                             "/", *ReuseFrom, ".dir/${PDB_PREFIX}", *ReuseFrom,
-                             extension);
-
-                  const std::string to_dir = cmStrCat(
-                    target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
-                    "/", target->GetName(), ".dir/${PDB_PREFIX}");
-
-                  const std::string to_file =
-                    cmStrCat(to_dir, *ReuseFrom, extension);
-
-                  std::string dest_file = to_file;
-
-                  std::string const& prefix =
-                    target->GetSafeProperty("PREFIX");
-                  if (!prefix.empty()) {
-                    dest_file =
-                      cmStrCat(to_dir, prefix, *ReuseFrom, extension);
-                  }
-
-                  file << "if (EXISTS \"" << from_file << "\" AND \""
-                       << from_file << "\" IS_NEWER_THAN \"" << dest_file
-                       << "\")\n";
-                  file << "  file(COPY \"" << from_file << "\""
-                       << " DESTINATION \"" << to_dir << "\")\n";
-                  if (!prefix.empty()) {
-                    file << "  file(REMOVE \"" << dest_file << "\")\n";
-                    file << "  file(RENAME \"" << to_file << "\" \""
-                         << dest_file << "\")\n";
-                  }
-                  file << "endif()\n";
-                }
+                const std::string compilerId =
+                  this->Makefile->GetSafeDefinition(
+                    cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
 
 
-                bool stdPipesUTF8 = true;
-                cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
-                  { cmSystemTools::GetCMakeCommand(),
-                    cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P",
-                    copy_script });
-
-                const std::string no_main_dependency;
-                const std::vector<std::string> no_deps;
-                const char* no_message = "";
-                const char* no_current_dir = nullptr;
-                std::vector<std::string> no_byproducts;
-
-                std::vector<std::string> outputs;
-                outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
-                                           *ReuseFrom, ".pdb"));
-
-                if (this->GetGlobalGenerator()->IsVisualStudio()) {
-                  this->AddCustomCommandToTarget(
-                    target->GetName(), outputs, no_deps, commandLines,
-                    cmCustomCommandType::PRE_BUILD, no_message, no_current_dir,
-                    true, false, "", "", false,
-                    cmObjectLibraryCommands::Reject, stdPipesUTF8);
-                } else {
-                  cmImplicitDependsList no_implicit_depends;
-                  cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
-                    outputs, no_byproducts, no_deps, no_main_dependency,
-                    no_implicit_depends, commandLines, no_message,
-                    no_current_dir, false, true, false, false, "", "",
-                    stdPipesUTF8);
-
-                  if (copy_rule) {
-                    target->AddSource(copy_rule->ResolveFullPath());
-                  }
-                }
+                const std::string compilerVersion =
+                  this->Makefile->GetSafeDefinition(
+                    cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"));
 
 
-                target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                                            target_compile_pdb_dir);
+                const std::string langFlags =
+                  this->Makefile->GetSafeDefinition(
+                    cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper));
+
+                // MSVC 2008 is producing both .pdb and .idb files with /Zi.
+                if ((langFlags.find("/ZI") != std::string::npos ||
+                     langFlags.find("-ZI") != std::string::npos) ||
+                    (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+                                                   compilerVersion.c_str(),
+                                                   "16.0") &&
+                     compilerId == "MSVC")) {
+                  CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget,
+                                    { ".pdb", ".idb" });
+                } else if ((langFlags.find("/Zi") != std::string::npos ||
+                            langFlags.find("-Zi") != std::string::npos)) {
+                  CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget,
+                                    { ".pdb" });
+                }
               }
               }
 
 
-              std::string pchSourceObj =
-                reuseTarget->GetPchFileObject(config, lang, arch);
-
-              const std::string configUpper = cmSystemTools::UpperCase(config);
+              if (reuseTarget->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+                std::string pchSourceObj =
+                  reuseTarget->GetPchFileObject(config, lang, arch);
 
 
-              // Link to the pch object file
-              target->Target->AppendProperty(
-                cmStrCat("LINK_FLAGS_", configUpper),
-                cmStrCat(" ",
-                         this->ConvertToOutputFormat(pchSourceObj, SHELL)),
-                true);
+                // Link to the pch object file
+                target->Target->AppendProperty(
+                  cmStrCat("LINK_FLAGS_", configUpper),
+                  cmStrCat(" ",
+                           this->ConvertToOutputFormat(pchSourceObj, SHELL)),
+                  true);
+              }
             }
             }
           } else {
           } else {
             pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
             pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
@@ -2765,6 +2706,115 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
   }
   }
 }
 }
 
 
+void cmLocalGenerator::CopyPchCompilePdb(
+  const std::string& config, cmGeneratorTarget* target,
+  const std::string& ReuseFrom, cmGeneratorTarget* reuseTarget,
+  const std::vector<std::string>& extensions)
+{
+  const std::string pdb_prefix =
+    this->GetGlobalGenerator()->IsMultiConfig() ? cmStrCat(config, "/") : "";
+
+  const std::string target_compile_pdb_dir =
+    cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
+             target->GetName(), ".dir/");
+
+  const std::string copy_script =
+    cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
+  cmGeneratedFileStream file(copy_script);
+
+  file << "# CMake generated file\n";
+
+  file << "# The compiler generated pdb file needs to be written to disk\n"
+       << "# by mspdbsrv. The foreach retry loop is needed to make sure\n"
+       << "# the pdb file is ready to be copied.\n\n";
+
+  for (auto const& extension : extensions) {
+    const std::string from_file =
+      cmStrCat(reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+               "/", ReuseFrom, ".dir/${PDB_PREFIX}", ReuseFrom, extension);
+
+    const std::string to_dir =
+      cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
+               target->GetName(), ".dir/${PDB_PREFIX}");
+
+    const std::string to_file = cmStrCat(to_dir, ReuseFrom, extension);
+
+    std::string dest_file = to_file;
+
+    std::string const& prefix = target->GetSafeProperty("PREFIX");
+    if (!prefix.empty()) {
+      dest_file = cmStrCat(to_dir, prefix, ReuseFrom, extension);
+    }
+
+    file << "foreach(retry RANGE 1 30)\n";
+    file << "  if (EXISTS \"" << from_file << "\" AND \"" << from_file
+         << "  \" IS_NEWER_THAN \"" << dest_file << "\")\n";
+    file << "    execute_process(COMMAND ${CMAKE_COMMAND} -E copy";
+    file << " \"" << from_file << "\""
+         << " \"" << to_dir << "\" RESULT_VARIABLE result "
+         << " ERROR_QUIET)\n";
+    file << "    if (NOT result EQUAL 0)\n"
+         << "      execute_process(COMMAND ${CMAKE_COMMAND}"
+         << " -E sleep 1)\n"
+         << "    else()\n";
+    if (!prefix.empty()) {
+      file << "  file(REMOVE \"" << dest_file << "\")\n";
+      file << "  file(RENAME \"" << to_file << "\" \"" << dest_file << "\")\n";
+    }
+    file << "      break()\n"
+         << "    endif()\n";
+    file << "  else()\n"
+         << "    execute_process(COMMAND ${CMAKE_COMMAND}"
+         << " -E sleep 1)\n"
+         << "  endif()\n";
+    file << "endforeach()\n";
+  }
+
+  bool stdPipesUTF8 = true;
+
+  auto configGenex = [&](cm::string_view expr) -> std::string {
+    if (this->GetGlobalGenerator()->IsVisualStudio()) {
+      return cmStrCat("$<$<CONFIG:", config, ">:", expr, ">");
+    }
+    return std::string(expr);
+  };
+
+  cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
+    { configGenex(cmSystemTools::GetCMakeCommand()),
+      configGenex(cmStrCat("-DPDB_PREFIX=", pdb_prefix)), configGenex("-P"),
+      configGenex(copy_script) });
+
+  const std::string no_main_dependency;
+  const std::vector<std::string> no_deps;
+  const char* no_message = "";
+  const char* no_current_dir = nullptr;
+  std::vector<std::string> no_byproducts;
+
+  std::vector<std::string> outputs;
+  outputs.push_back(
+    cmStrCat(target_compile_pdb_dir, pdb_prefix, ReuseFrom, ".pdb"));
+
+  if (this->GetGlobalGenerator()->IsVisualStudio()) {
+    this->AddCustomCommandToTarget(
+      target->GetName(), outputs, no_deps, commandLines,
+      cmCustomCommandType::PRE_BUILD, no_message, no_current_dir, true, false,
+      "", "", false, cmObjectLibraryCommands::Reject, stdPipesUTF8);
+  } else {
+    cmImplicitDependsList no_implicit_depends;
+    cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
+      outputs, no_byproducts, no_deps, no_main_dependency, no_implicit_depends,
+      commandLines, no_message, no_current_dir, false, true, false, false, "",
+      "", stdPipesUTF8);
+
+    if (copy_rule) {
+      target->AddSource(copy_rule->ResolveFullPath());
+    }
+  }
+
+  target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
+                              target_compile_pdb_dir);
+}
+
 namespace {
 namespace {
 
 
 inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf,
 inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf,

+ 5 - 0
Source/cmLocalGenerator.h

@@ -540,6 +540,11 @@ private:
   void ComputeObjectMaxPath();
   void ComputeObjectMaxPath();
   bool AllAppleArchSysrootsAreTheSame(const std::vector<std::string>& archs,
   bool AllAppleArchSysrootsAreTheSame(const std::vector<std::string>& archs,
                                       const char* sysroot);
                                       const char* sysroot);
+
+  void CopyPchCompilePdb(const std::string& config, cmGeneratorTarget* target,
+                         const std::string& ReuseFrom,
+                         cmGeneratorTarget* reuseTarget,
+                         std::vector<std::string> const& extensions);
 };
 };
 
 
 #if !defined(CMAKE_BOOTSTRAP)
 #if !defined(CMAKE_BOOTSTRAP)