Browse Source

Merge topic 'improve-CMP0028-messages'

ea050286e7 CMP0028: Report the target whose link interface has an offending item
a97c92e46e CMP0028: Report backtrace to link item rather than target creation
0dcbf4ab58 cmGeneratorTarget: Record when imported target link iface libs are done

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !6810
Brad King 4 years ago
parent
commit
af9fcbd006

+ 79 - 32
Source/cmGeneratorTarget.cxx

@@ -2687,7 +2687,6 @@ public:
     : Config(std::move(config))
     , Languages(languages)
     , HeadTarget(head)
-    , Target(target)
     , SecondPass(secondPass)
   {
     this->Visited.insert(target);
@@ -2696,36 +2695,6 @@ public:
   void Visit(cmLinkItem const& item)
   {
     if (!item.Target) {
-      if (item.AsStr().find("::") != std::string::npos) {
-        bool noMessage = false;
-        MessageType messageType = MessageType::FATAL_ERROR;
-        std::ostringstream e;
-        switch (this->Target->GetLocalGenerator()->GetPolicyStatus(
-          cmPolicies::CMP0028)) {
-          case cmPolicies::WARN: {
-            e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
-            messageType = MessageType::AUTHOR_WARNING;
-          } break;
-          case cmPolicies::OLD:
-            noMessage = true;
-            break;
-          case cmPolicies::REQUIRED_IF_USED:
-          case cmPolicies::REQUIRED_ALWAYS:
-          case cmPolicies::NEW:
-            // Issue the fatal message.
-            break;
-        }
-
-        if (!noMessage) {
-          e << "Target \"" << this->Target->GetName()
-            << "\" links to target \"" << item.AsStr()
-            << "\" but the target was not found.  Perhaps a find_package() "
-               "call is missing for an IMPORTED target, or an ALIAS target is "
-               "missing?";
-          this->Target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
-            messageType, e.str(), this->Target->GetBacktrace());
-        }
-      }
       return;
     }
     if (!this->Visited.insert(item.Target).second) {
@@ -2758,7 +2727,6 @@ private:
   std::string Config;
   std::unordered_set<std::string>& Languages;
   cmGeneratorTarget const* HeadTarget;
-  const cmGeneratorTarget* Target;
   std::set<cmGeneratorTarget const*> Visited;
   bool SecondPass;
   bool HadLinkLanguageSensitiveCondition = false;
@@ -6277,6 +6245,84 @@ cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation(
   return i->second.get();
 }
 
+void cmGeneratorTarget::CheckLinkLibraries() const
+{
+  // Check link the implementation for each generated configuration.
+  for (auto const& hmp : this->LinkImplMap) {
+    HeadToLinkImplementationMap const& hm = hmp.second;
+    // There could be several entries used when computing the pre-CMP0022
+    // default link interface.  Check only the entry for our own link impl.
+    auto const hmi = hm.find(this);
+    if (hmi == hm.end() || !hmi->second.LibrariesDone) {
+      continue;
+    }
+    for (cmLinkImplItem const& item : hmi->second.Libraries) {
+      if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) {
+        return;
+      }
+    }
+  }
+
+  // Check link the interface for each generated combination of
+  // configuration and consuming head target.  We should not need to
+  // consider LinkInterfaceUsageRequirementsOnlyMap because its entries
+  // should be a subset of LinkInterfaceMap (with LINK_ONLY left out).
+  for (auto const& hmp : this->LinkInterfaceMap) {
+    for (auto const& hmi : hmp.second) {
+      if (!hmi.second.LibrariesDone) {
+        continue;
+      }
+      for (cmLinkItem const& item : hmi.second.Libraries) {
+        if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) {
+          return;
+        }
+      }
+    }
+  }
+}
+
+bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role,
+                                             cmLinkItem const& item) const
+{
+  if (item.Target || item.AsStr().find("::") == std::string::npos) {
+    return true;
+  }
+  MessageType messageType = MessageType::FATAL_ERROR;
+  std::string e;
+  switch (this->GetLocalGenerator()->GetPolicyStatus(cmPolicies::CMP0028)) {
+    case cmPolicies::WARN: {
+      e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0028), "\n");
+      messageType = MessageType::AUTHOR_WARNING;
+    } break;
+    case cmPolicies::OLD:
+      return true;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      // Issue the fatal message.
+      break;
+  }
+
+  if (role == LinkItemRole::Implementation) {
+    e = cmStrCat(e, "Target \"", this->GetName(), "\" links to");
+  } else {
+    e = cmStrCat(e, "The link interface of target \"", this->GetName(),
+                 "\" contains");
+  }
+  e = cmStrCat(e, ":\n  ", item.AsStr(), "\n",
+               "but the target was not found.  Possible reasons include:\n"
+               "  * There is a typo in the target name.\n"
+               "  * A find_package call is missing for an IMPORTED target.\n"
+               "  * An ALIAS target is missing.\n");
+  cmListFileBacktrace backtrace = item.Backtrace;
+  if (backtrace.Empty()) {
+    backtrace = this->GetBacktrace();
+  }
+  this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(messageType, e,
+                                                              backtrace);
+  return false;
+}
+
 void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
 {
   int patch;
@@ -7284,6 +7330,7 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
   cmOptionalLinkInterface& iface = hm[headTarget];
   if (!iface.AllDone) {
     iface.AllDone = true;
+    iface.LibrariesDone = true;
     iface.Multiplicity = info->Multiplicity;
     cmExpandList(info->Languages, iface.Languages);
     this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries),

+ 11 - 0
Source/cmGeneratorTarget.h

@@ -84,6 +84,10 @@ public:
   cmComputeLinkInformation* GetLinkInformation(
     const std::string& config) const;
 
+  // Perform validation checks on memoized link structures.
+  // Call this after generation is complete.
+  void CheckLinkLibraries() const;
+
   cmStateEnums::TargetType GetType() const;
   const std::string& GetName() const;
   std::string GetExportName() const;
@@ -973,6 +977,13 @@ private:
   cmLinkImplementation const* GetLinkImplementation(const std::string& config,
                                                     bool secondPass) const;
 
+  enum class LinkItemRole
+  {
+    Implementation,
+    Interface,
+  };
+  bool VerifyLinkItemColons(LinkItemRole role, cmLinkItem const& item) const;
+
   // Cache import information from properties for each configuration.
   struct ImportInfo
   {

+ 15 - 0
Source/cmGlobalGenerator.cxx

@@ -328,6 +328,18 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
   return failed;
 }
 
+void cmGlobalGenerator::CheckTargetLinkLibraries() const
+{
+  for (const auto& generator : this->LocalGenerators) {
+    for (const auto& gt : generator->GetGeneratorTargets()) {
+      gt->CheckLinkLibraries();
+    }
+    for (const auto& gt : generator->GetOwnedImportedGeneratorTargets()) {
+      gt->CheckLinkLibraries();
+    }
+  }
+}
+
 bool cmGlobalGenerator::CheckTargetsForType() const
 {
   if (!this->GetLanguageEnabled("Swift")) {
@@ -1606,6 +1618,9 @@ void cmGlobalGenerator::Generate()
     this->ExtraGenerator->Generate();
   }
 
+  // Perform validation checks on memoized link structures.
+  this->CheckTargetLinkLibraries();
+
   if (!this->CMP0042WarnTargets.empty()) {
     std::ostringstream w;
     w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n";

+ 1 - 0
Source/cmGlobalGenerator.h

@@ -684,6 +684,7 @@ private:
 
   virtual void ForceLinkerLanguages();
 
+  void CheckTargetLinkLibraries() const;
   bool CheckTargetsForMissingSources() const;
   bool CheckTargetsForType() const;
   bool CheckTargetsForPchCompilePdb() const;

+ 5 - 0
Source/cmLocalGenerator.h

@@ -193,6 +193,11 @@ public:
     return this->GeneratorTargets;
   }
 
+  const GeneratorTargetVector& GetOwnedImportedGeneratorTargets() const
+  {
+    return this->OwnedImportedGeneratorTargets;
+  }
+
   void AddGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt);
   void AddImportedGeneratorTarget(cmGeneratorTarget* gt);
   void AddOwnedImportedGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt);

+ 11 - 5
Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt

@@ -1,6 +1,12 @@
-CMake Error at CMP0028-NEW-iface.cmake:6 \(add_library\):
-  Target "foo" links to target "External::Library" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+CMake Error at CMP0028-NEW-iface\.cmake:5 \(target_link_libraries\):
+  The link interface of target "iface" contains:
+
+    External::Library
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 11 - 5
Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt

@@ -1,6 +1,12 @@
-CMake Error at CMP0028-NEW.cmake:4 \(add_library\):
-  Target "foo" links to target "External::Library" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+CMake Error at CMP0028-NEW\.cmake:5 \(target_link_libraries\):
+  Target "foo" links to:
+
+    External::Library
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 11 - 5
Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt

@@ -1,11 +1,17 @@
-CMake Warning \(dev\) at CMP0028-WARN-iface.cmake:4 \(add_library\):
+CMake Warning \(dev\) at CMP0028-WARN-iface\.cmake:3 \(target_link_libraries\):
   Policy CMP0028 is not set: Double colon in target name means ALIAS or
   IMPORTED target.  Run "cmake --help-policy CMP0028" for policy details.
   Use the cmake_policy command to set the policy and suppress this warning.
 
-  Target "foo" links to target "External::Library" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+  The link interface of target "iface" contains:
+
+    External::Library
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
 This warning is for project developers.  Use -Wno-dev to suppress it.

+ 11 - 5
Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt

@@ -1,11 +1,17 @@
-CMake Warning \(dev\) at CMP0028-WARN.cmake:2 \(add_library\):
+CMake Warning \(dev\) at CMP0028-WARN\.cmake:3 \(target_link_libraries\):
   Policy CMP0028 is not set: Double colon in target name means ALIAS or
   IMPORTED target.  Run "cmake --help-policy CMP0028" for policy details.
   Use the cmake_policy command to set the policy and suppress this warning.
 
-  Target "foo" links to target "External::Library" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+  Target "foo" links to:
+
+    External::Library
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
 This warning is for project developers.  Use -Wno-dev to suppress it.

+ 10 - 4
Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt

@@ -1,6 +1,12 @@
-^CMake Error at CMP0079-link-NEW-bogus.cmake:[0-9]+ \(add_executable\):
-  Target "top" links to target "::@\(0xdeadbeef\)" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+^CMake Error at CMP0079-link-NEW-bogus\.cmake:6 \(set_property\):
+  Target "top" links to:
+
+    ::@\(0xdeadbeef\)
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
   CMakeLists\.txt:[0-9]+ \(include\)

+ 22 - 10
Tests/RunCMake/target_link_libraries/ConfigCase-stderr.txt

@@ -1,13 +1,25 @@
-^CMake Error at ConfigCase.cmake:[0-9]+ \(add_library\):
-  Target "impl" links to target "config::impl-Debug" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+^CMake Error at ConfigCase\.cmake:4 \(target_link_libraries\):
+  The link interface of target "iface" contains:
+
+    config::iface-Debug
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
 +
-CMake Error at ConfigCase.cmake:[0-9]+ \(add_library\):
-  Target "impl" links to target "config::iface-Debug" but the target was not
-  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
-  an ALIAS target is missing\?
+CMake Error at ConfigCase\.cmake:6 \(target_link_libraries\):
+  Target "impl" links to:
+
+    config::impl-Debug
+
+  but the target was not found.  Possible reasons include:
+(
+    \*[^
+]+)*
+
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)