Browse Source

Merge topic 'multi-ninja-pch'

a55df20499 Multi-Ninja: Add precompile headers support

Acked-by: Kitware Robot <[email protected]>
Merge-request: !4201
Brad King 5 years ago
parent
commit
941c09616b

+ 9 - 2
Source/cmGeneratorTarget.cxx

@@ -3407,8 +3407,15 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
       { "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");
     if (!pchReuseFrom) {

+ 2 - 0
Source/cmGlobalGenerator.h

@@ -415,6 +415,8 @@ public:
 
   virtual bool IsXcode() const { return false; }
 
+  virtual bool IsVisualStudio() const { return false; }
+
   /** Return true if we know the exact location of object files.
       If false, store the reason in the given string.
       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 dryRun) override;
 
+  bool IsVisualStudio() const override { return true; }
+
 protected:
   cmGlobalVisualStudioGenerator(cmake* cm,
                                 std::string const& platformInGeneratorName);

+ 136 - 129
Source/cmLocalGenerator.cxx

@@ -2421,163 +2421,170 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
 
 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";
+                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")
+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")
 
 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(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})
   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_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})
   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")
+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)
 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()
 
 run_cmake(DisabledPch)
+run_cmake(PchDebugGenex)
 run_test(PchInterface)
 run_cmake(PchPrologueEpilogue)
 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]=])
 
 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}")
   set(RunCMake_TEST_FAILED "Generated PCH header ${pch_header} does not exist.")