Просмотр исходного кода

Multi-Ninja: Add precompile headers support

Fixes: #19789
Cristian Adam 6 лет назад
Родитель
Сommit
a55df20499

+ 9 - 2
Source/cmGeneratorTarget.cxx

@@ -3396,8 +3396,15 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
       { "OBJCXX", ".objcxx.hxx" }
       { "OBJCXX", ".objcxx.hxx" }
     };
     };
 
 
-    filename = cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(),
-                        ".dir/cmake_pch", languageToExtension.at(language));
+    filename =
+      cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
+
+    if (this->GetGlobalGenerator()->IsMultiConfig()) {
+      filename = cmStrCat(filename, "/", config);
+    }
+
+    filename =
+      cmStrCat(filename, "/cmake_pch", languageToExtension.at(language));
 
 
     const std::string filename_tmp = cmStrCat(filename, ".tmp");
     const std::string filename_tmp = cmStrCat(filename, ".tmp");
     if (!pchReuseFrom) {
     if (!pchReuseFrom) {

+ 2 - 0
Source/cmGlobalGenerator.h

@@ -415,6 +415,8 @@ public:
 
 
   virtual bool IsXcode() const { return false; }
   virtual bool IsXcode() const { return false; }
 
 
+  virtual bool IsVisualStudio() const { return false; }
+
   /** Return true if we know the exact location of object files.
   /** Return true if we know the exact location of object files.
       If false, store the reason in the given string.
       If false, store the reason in the given string.
       This is meaningful only after EnableLanguage has been called.  */
       This is meaningful only after EnableLanguage has been called.  */

+ 2 - 0
Source/cmGlobalVisualStudioGenerator.h

@@ -150,6 +150,8 @@ public:
   bool Open(const std::string& bindir, const std::string& projectName,
   bool Open(const std::string& bindir, const std::string& projectName,
             bool dryRun) override;
             bool dryRun) override;
 
 
+  bool IsVisualStudio() const override { return true; }
+
 protected:
 protected:
   cmGlobalVisualStudioGenerator(cmake* cm,
   cmGlobalVisualStudioGenerator(cmake* cm,
                                 std::string const& platformInGeneratorName);
                                 std::string const& platformInGeneratorName);

+ 136 - 129
Source/cmLocalGenerator.cxx

@@ -2413,163 +2413,170 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
 
 
 void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 {
 {
-  // FIXME: Handle all configurations in multi-config generators.
-  std::string config;
-  if (!this->GetGlobalGenerator()->IsMultiConfig()) {
-    config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
-  }
-  const std::string buildType = cmSystemTools::UpperCase(config);
-
-  // FIXME: Refactor collection of sources to not evaluate object libraries.
-  std::vector<cmSourceFile*> sources;
-  target->GetSourceFiles(sources, buildType);
-
-  for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
-    auto langSources =
-      std::count_if(sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
-        return lang == sf->GetLanguage() &&
-          !sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
-      });
-    if (langSources == 0) {
-      continue;
-    }
+  std::vector<std::string> configsList;
+  std::string configDefault = this->Makefile->GetConfigurations(configsList);
+  if (configsList.empty()) {
+    configsList.push_back(configDefault);
+  }
+
+  for (std::string const& config : configsList) {
+    const std::string buildType = cmSystemTools::UpperCase(config);
+
+    // FIXME: Refactor collection of sources to not evaluate object libraries.
+    std::vector<cmSourceFile*> sources;
+    target->GetSourceFiles(sources, buildType);
+
+    for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
+      auto langSources = std::count_if(
+        sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
+          return lang == sf->GetLanguage() &&
+            !sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
+        });
+      if (langSources == 0) {
+        continue;
+      }
 
 
-    const std::string pchSource = target->GetPchSource(config, lang);
-    const std::string pchHeader = target->GetPchHeader(config, lang);
+      const std::string pchSource = target->GetPchSource(config, lang);
+      const std::string pchHeader = target->GetPchHeader(config, lang);
 
 
-    if (pchSource.empty() || pchHeader.empty()) {
-      continue;
-    }
+      if (pchSource.empty() || pchHeader.empty()) {
+        continue;
+      }
 
 
-    const std::string pchExtension =
-      this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
+      const std::string pchExtension =
+        this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
 
 
-    if (pchExtension.empty()) {
-      continue;
-    }
+      if (pchExtension.empty()) {
+        continue;
+      }
 
 
-    const char* pchReuseFrom =
-      target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+      const char* pchReuseFrom =
+        target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
 
 
-    auto pch_sf = this->Makefile->GetOrCreateSource(
-      pchSource, false, cmSourceFileLocationKind::Known);
+      auto pch_sf = this->Makefile->GetOrCreateSource(
+        pchSource, false, cmSourceFileLocationKind::Known);
 
 
-    if (!this->GetGlobalGenerator()->IsXcode()) {
-      if (!pchReuseFrom) {
-        target->AddSource(pchSource, true);
-      }
+      if (!this->GetGlobalGenerator()->IsXcode()) {
+        if (!pchReuseFrom) {
+          target->AddSource(pchSource, true);
+        }
 
 
-      const std::string pchFile = target->GetPchFile(config, lang);
+        const std::string pchFile = target->GetPchFile(config, lang);
 
 
-      // Exclude the pch files from linking
-      if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
-        if (!pchReuseFrom) {
-          pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
-        } else {
-          auto reuseTarget =
-            this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
+        // Exclude the pch files from linking
+        if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
+          if (!pchReuseFrom) {
+            pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
+          } else {
+            auto reuseTarget =
+              this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
 
 
-          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 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 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);
+              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(),
-                "/", pchReuseFrom, ".dir/${PDB_PREFIX}", pchReuseFrom,
-                extension);
+              file << "# CMake generated file\n";
+              for (auto extension : { ".pdb", ".idb" }) {
+                const std::string from_file =
+                  cmStrCat(reuseTarget->GetLocalGenerator()
+                             ->GetCurrentBinaryDirectory(),
+                           "/", pchReuseFrom, ".dir/${PDB_PREFIX}",
+                           pchReuseFrom, extension);
 
 
-              const std::string to_dir = cmStrCat(
-                target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
-                target->GetName(), ".dir/${PDB_PREFIX}");
+                const std::string to_dir = cmStrCat(
+                  target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+                  "/", target->GetName(), ".dir/${PDB_PREFIX}");
 
 
-              const std::string to_file =
-                cmStrCat(to_dir, pchReuseFrom, extension);
+                const std::string to_file =
+                  cmStrCat(to_dir, pchReuseFrom, extension);
 
 
-              std::string dest_file = to_file;
+                std::string dest_file = to_file;
 
 
-              const std::string prefix = target->GetSafeProperty("PREFIX");
-              if (!prefix.empty()) {
-                dest_file = cmStrCat(to_dir, prefix, pchReuseFrom, extension);
-              }
+                const std::string prefix = target->GetSafeProperty("PREFIX");
+                if (!prefix.empty()) {
+                  dest_file =
+                    cmStrCat(to_dir, prefix, pchReuseFrom, 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
+                file << "if (EXISTS \"" << from_file << "\" AND \""
+                     << from_file << "\" IS_NEWER_THAN \"" << dest_file
                      << "\")\n";
                      << "\")\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";
               }
               }
-              file << "endif()\n";
-            }
 
 
-            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,
-                                       pchReuseFrom, ".pdb"));
-
-            if (this->GetGlobalGenerator()->IsMultiConfig()) {
-              this->AddCustomCommandToTarget(
-                target->GetName(), outputs, no_deps, commandLines,
-                cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
-            } 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);
-
-              if (copy_rule) {
-                target->AddSource(copy_rule->ResolveFullPath());
+              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,
+                                         pchReuseFrom, ".pdb"));
+
+              if (this->GetGlobalGenerator()->IsVisualStudio()) {
+                this->AddCustomCommandToTarget(
+                  target->GetName(), outputs, no_deps, commandLines,
+                  cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
+              } 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);
+
+                if (copy_rule) {
+                  target->AddSource(copy_rule->ResolveFullPath());
+                }
               }
               }
-            }
 
 
-            target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                                        target_compile_pdb_dir);
-          }
+              target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
+                                          target_compile_pdb_dir);
+            }
 
 
-          std::string pchSourceObj =
-            reuseTarget->GetPchFileObject(config, lang);
+            std::string pchSourceObj =
+              reuseTarget->GetPchFileObject(config, lang);
 
 
-          // Link to the pch object file
-          target->Target->AppendProperty(
-            "LINK_FLAGS",
-            cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
-            true);
+            // Link to the pch object file
+            target->Target->AppendProperty(
+              "LINK_FLAGS",
+              cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
+              true);
+          }
+        } else {
+          pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
         }
         }
-      } else {
-        pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
-      }
 
 
-      // Add pchHeader to source files, which will
-      // be grouped as "Precompile Header File"
-      auto pchHeader_sf = this->Makefile->GetOrCreateSource(
-        pchHeader, false, cmSourceFileLocationKind::Known);
-      std::string err;
-      pchHeader_sf->ResolveFullPath(&err);
-      target->AddSource(pchHeader);
+        // Add pchHeader to source files, which will
+        // be grouped as "Precompile Header File"
+        auto pchHeader_sf = this->Makefile->GetOrCreateSource(
+          pchHeader, false, cmSourceFileLocationKind::Known);
+        std::string err;
+        pchHeader_sf->ResolveFullPath(&err);
+        target->AddSource(pchHeader);
+      }
     }
     }
   }
   }
 }
 }

+ 3 - 0
Tests/RunCMake/PrecompileHeaders/DisabledPch-check.cmake

@@ -1,4 +1,7 @@
 set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
 set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
+endif()
 set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 
 
 if (NOT EXISTS ${foo_pch_header})
 if (NOT EXISTS ${foo_pch_header})

+ 17 - 0
Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake

@@ -0,0 +1,17 @@
+if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  return()
+endif()
+
+set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
+
+if (NOT EXISTS ${foo_pch_header})
+  set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")
+  return()
+endif()
+
+file(STRINGS ${foo_pch_header} foo_pch_header_strings)
+
+if (NOT foo_pch_header_strings MATCHES ";#include \"[^\"]*PrecompileHeaders/include/foo.h\";#include <stdio.h>(;|$)")
+  set(RunCMake_TEST_FAILED "Generated foo pch header\n  ${foo_pch_header}\nhas bad content:\n  ${foo_pch_header_strings}")
+  return()
+endif()

+ 9 - 0
Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake

@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.15)
+project(PchDebugGenex C)
+
+add_library(foo foo.c)
+target_include_directories(foo PUBLIC include)
+target_precompile_headers(foo PUBLIC
+  "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/include/foo.h>"
+  <stdio.h>
+)

+ 4 - 0
Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake

@@ -1,5 +1,9 @@
 set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
 set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
 set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
+  set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.h")
+endif()
 
 
 if (NOT EXISTS ${foo_pch_header})
 if (NOT EXISTS ${foo_pch_header})
   set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")
   set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")

+ 4 - 0
Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake

@@ -1,5 +1,9 @@
 set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.hxx")
 set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.hxx")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.h")
+  set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.hxx")
+endif()
 
 
 if (NOT EXISTS ${foobar_pch_h_header})
 if (NOT EXISTS ${foobar_pch_h_header})
   set(RunCMake_TEST_FAILED "Generated foobar C pch header ${foobar_pch_h_header} does not exist")
   set(RunCMake_TEST_FAILED "Generated foobar C pch header ${foobar_pch_h_header} does not exist")

+ 3 - 0
Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue-check.cmake

@@ -1,4 +1,7 @@
 set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/cmake_pch.hxx")
 set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/cmake_pch.hxx")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/Debug/cmake_pch.hxx")
+endif()
 
 
 file(STRINGS ${main_pch_header} main_pch_header_strings)
 file(STRINGS ${main_pch_header} main_pch_header_strings)
 string(REGEX MATCH "#pragma warning\\(push, 0\\).*#include.*pch.h.*#pragma warning\\(pop\\)" matched_code ${main_pch_header_strings})
 string(REGEX MATCH "#pragma warning\\(push, 0\\).*#include.*pch.h.*#pragma warning\\(pop\\)" matched_code ${main_pch_header_strings})

+ 1 - 0
Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake

@@ -13,6 +13,7 @@ function(run_test name)
 endfunction()
 endfunction()
 
 
 run_cmake(DisabledPch)
 run_cmake(DisabledPch)
+run_cmake(PchDebugGenex)
 run_test(PchInterface)
 run_test(PchInterface)
 run_cmake(PchPrologueEpilogue)
 run_cmake(PchPrologueEpilogue)
 run_test(SkipPrecompileHeaders)
 run_test(SkipPrecompileHeaders)

+ 1 - 1
Tests/RunCMake/VS10Project/VsPrecompileHeaders-check.cmake

@@ -1,4 +1,4 @@
-set(pch_header "CMakeFiles/tgt.dir/cmake_pch.hxx")
+set(pch_header "CMakeFiles/tgt.dir/Debug/cmake_pch.hxx")
 set(pch_source [=[CMakeFiles\\tgt.dir\\cmake_pch.cxx]=])
 set(pch_source [=[CMakeFiles\\tgt.dir\\cmake_pch.cxx]=])
 
 
 if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${pch_header}")
 if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${pch_header}")

+ 1 - 1
Tests/RunCMake/XcodeProject/XcodePrecompileHeaders-check.cmake

@@ -1,4 +1,4 @@
-set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/cmake_pch.hxx")
+set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Debug/cmake_pch.hxx")
 
 
 if(NOT EXISTS "${pch_header}")
 if(NOT EXISTS "${pch_header}")
   set(RunCMake_TEST_FAILED "Generated PCH header ${pch_header} does not exist.")
   set(RunCMake_TEST_FAILED "Generated PCH header ${pch_header} does not exist.")