1
0
Эх сурвалжийг харах

Merge topic 'detect-colliding-target-dirs' into release-4.2

bc7fac6ad3 cmGeneratorTarget: detect colliding target directories

Acked-by: Kitware Robot <[email protected]>
Merge-request: !11658
Brad King 2 долоо хоног өмнө
parent
commit
57c7fa0d5f

+ 1 - 0
Source/cmExportTryCompileFileGenerator.cxx

@@ -94,6 +94,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
   cmTarget dummyHead("try_compile_dummy_exe", cmStateEnums::EXECUTABLE,
                      cmTarget::Visibility::Normal, tgt->Target->GetMakefile(),
                      cmTarget::PerConfig::Yes);
+  dummyHead.SetIsForTryCompile();
 
   cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator());
 

+ 21 - 2
Source/cmGeneratorTarget.cxx

@@ -5483,8 +5483,27 @@ std::string cmGeneratorTarget::GetSupportDirectory(
   cmStateEnums::IntermediateDirKind kind) const
 {
   cmLocalGenerator* lg = this->GetLocalGenerator();
-  return cmStrCat(lg->GetObjectOutputRoot(kind), '/',
-                  lg->GetTargetDirectory(this, kind));
+  auto targetDir = cmStrCat(lg->GetObjectOutputRoot(kind), '/',
+                            lg->GetTargetDirectory(this, kind));
+
+#ifndef CMAKE_BOOTSTRAP
+  auto& tdr =
+    this->GetGlobalGenerator()->RegisterTargetDirectory(this, targetDir);
+  if (tdr.CollidesWith && !tdr.Warned) {
+    this->Makefile->IssueMessage(
+      MessageType::WARNING,
+      cmStrCat("The '", tdr.CollidesWith->GetName(), "' and '",
+               this->GetName(),
+               "' targets share an intermediate directory\n    ", targetDir,
+               "\nwhich may cause problems with the build graph. This project "
+               "is not compatible with the `SHORT` target intermediate "
+               "directory strategy. Possible remedies include: moving the "
+               "target into different directories or renaming a target."));
+    tdr.Warned = true;
+  }
+#endif
+
+  return targetDir;
 }
 
 std::string cmGeneratorTarget::GetCMFSupportDirectory(

+ 29 - 0
Source/cmGlobalGenerator.cxx

@@ -2054,6 +2054,35 @@ std::string cmGlobalGenerator::ComputeTargetShortName(
   return cmStrCat(tgtHash, dirHash);
 }
 
+cmGlobalGenerator::TargetDirectoryRegistration&
+cmGlobalGenerator::RegisterTargetDirectory(cmGeneratorTarget const* tgt,
+                                           std::string const& targetDir) const
+{
+  if (!tgt->IsNormal() || tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
+      tgt->Target->IsForTryCompile()) {
+    static TargetDirectoryRegistration utilityRegistration(nullptr, true);
+    return utilityRegistration;
+  }
+
+  // Get the registration instance for the target.
+#if __cplusplus >= 201703L
+  auto registration = this->TargetDirectoryRegistrations.try_emplace(tgt);
+#else
+  auto registration = this->TargetDirectoryRegistrations.insert(
+    std::make_pair(tgt, TargetDirectoryRegistration()));
+#endif
+  // If it was just inserted, search for a `CollidesWith` possibility.
+  if (registration.second) {
+    auto& otherTargets = this->TargetDirectories[targetDir];
+    if (!otherTargets.empty()) {
+      registration.first->second.CollidesWith = *otherTargets.begin();
+    }
+    otherTargets.insert(tgt);
+  }
+
+  return registration.first->second;
+}
+
 void cmGlobalGenerator::ComputeTargetObjectDirectory(
   cmGeneratorTarget* /*unused*/) const
 {

+ 23 - 0
Source/cmGlobalGenerator.h

@@ -648,6 +648,20 @@ public:
   virtual std::string GetShortBinaryOutputDir() const;
   std::string ComputeTargetShortName(std::string const& bindir,
                                      std::string const& targetName) const;
+  struct TargetDirectoryRegistration
+  {
+    TargetDirectoryRegistration() = default;
+    TargetDirectoryRegistration(cmGeneratorTarget const* t, bool w)
+      : CollidesWith(t)
+      , Warned(w)
+    {
+    }
+
+    cmGeneratorTarget const* CollidesWith = nullptr;
+    bool Warned = false;
+  };
+  TargetDirectoryRegistration& RegisterTargetDirectory(
+    cmGeneratorTarget const* tgt, std::string const& targetDir) const;
 
   virtual void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
 
@@ -823,12 +837,21 @@ private:
     std::unordered_map<std::string, cmGeneratorTarget*>;
   using MakefileMap = std::unordered_map<std::string, cmMakefile*>;
   using LocalGeneratorMap = std::unordered_map<std::string, cmLocalGenerator*>;
+  using TargetDirectoryRegistrationMap =
+    std::map<cmGeneratorTarget const*, TargetDirectoryRegistration>;
+  using TargetDirectoryMap =
+    std::unordered_map<std::string, std::set<cmGeneratorTarget const*>>;
   // Map efficiently from target name to cmTarget instance.
   // Do not use this structure for looping over all targets.
   // It contains both normal and globally visible imported targets.
   TargetMap TargetSearchIndex;
   GeneratorTargetMap GeneratorTargetSearchIndex;
 
+  // Map from target to a directory registration.
+  mutable TargetDirectoryRegistrationMap TargetDirectoryRegistrations;
+  // Map from target directories to targets using it.
+  mutable TargetDirectoryMap TargetDirectories;
+
   // Map efficiently from source directory path to cmMakefile instance.
   // Do not use this structure for looping over all directories.
   // It may not contain all of them (see note in IndexMakefile method).

+ 11 - 0
Source/cmTarget.cxx

@@ -609,6 +609,7 @@ public:
   bool BuildInterfaceIncludesAppended;
   bool PerConfig;
   bool IsSymbolic;
+  bool IsForTryCompile{ false };
   cmTarget::Visibility TargetVisibility;
   std::set<BT<std::pair<std::string, bool>>> Utilities;
   std::set<std::string> CodegenDependencies;
@@ -2906,6 +2907,16 @@ bool cmTarget::CanCompileSources() const
   return false;
 }
 
+void cmTarget::SetIsForTryCompile()
+{
+  this->impl->IsForTryCompile = true;
+}
+
+bool cmTarget::IsForTryCompile() const
+{
+  return this->impl->IsForTryCompile;
+}
+
 char const* cmTarget::GetSuffixVariableInternal(
   cmStateEnums::ArtifactType artifact) const
 {

+ 2 - 0
Source/cmTarget.h

@@ -237,6 +237,8 @@ public:
   bool IsRuntimeBinary() const;
   bool IsSymbolic() const;
   bool CanCompileSources() const;
+  void SetIsForTryCompile();
+  bool IsForTryCompile() const;
 
   bool GetMappedConfig(std::string const& desiredConfig, cmValue& loc,
                        cmValue& imp, std::string& suffix) const;

+ 10 - 0
Tests/RunCMake/IntermediateDirStrategy/Collides-stderr.txt

@@ -0,0 +1,10 @@
+CMake Warning in collides/CMakeLists.txt:
+  The 'CubeTestPluginLogic' and 'TeamworkServerBlobStoreUploadSessionStore'
+  targets share an intermediate directory
+
+      .*/Tests/RunCMake/IntermediateDirStrategy/Collides-build/(collides/)?.o/039c43fd
+
+  which may cause problems with the build graph.  This project is not
+  compatible with the `SHORT` target intermediate directory strategy.
+  Possible remedies include: moving the target into different directories or
+  renaming a target.

+ 4 - 0
Tests/RunCMake/IntermediateDirStrategy/Collides.cmake

@@ -0,0 +1,4 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+enable_language(C)
+
+add_subdirectory(collides)

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

@@ -47,5 +47,6 @@ function(run_install_test case)
 endfunction()
 
 if (RunCMake_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+  run_cmake(Collides)
   run_install_test(ShortObjectDoesntChangeInstall)
 endif ()

+ 2 - 0
Tests/RunCMake/IntermediateDirStrategy/collides/CMakeLists.txt

@@ -0,0 +1,2 @@
+add_library(CubeTestPluginLogic STATIC lib1.c)
+add_library(TeamworkServerBlobStoreUploadSessionStore STATIC lib2.c)

+ 4 - 0
Tests/RunCMake/IntermediateDirStrategy/collides/lib1.c

@@ -0,0 +1,4 @@
+int f(int a)
+{
+  return a;
+}

+ 4 - 0
Tests/RunCMake/IntermediateDirStrategy/collides/lib2.c

@@ -0,0 +1,4 @@
+int f(int a)
+{
+  return a;
+}