Browse Source

ENH: Tolerate repeated link library types

The "debug", "optimized", and "general" link library type specifier
arguments to the target_link_library commands are sometimes repeated in
user code due to variable expansion and other complications.  Instead of
silently accepting the duplicates and trying to link to a bogus library
like "optimized.lib", warn and ignore the earlier specifiers.
Brad King 17 years ago
parent
commit
40fc9174e2
2 changed files with 62 additions and 26 deletions
  1. 60 26
      Source/cmTargetLinkLibrariesCommand.cxx
  2. 2 0
      Source/cmTargetLinkLibrariesCommand.h

+ 60 - 26
Source/cmTargetLinkLibrariesCommand.cxx

@@ -16,6 +16,13 @@
 =========================================================================*/
 #include "cmTargetLinkLibrariesCommand.h"
 
+const char* cmTargetLinkLibrariesCommand::LinkLibraryTypeNames[3] =
+{
+  "general",
+  "debug",
+  "optimized"
+};
+
 // cmTargetLinkLibrariesCommand
 bool cmTargetLinkLibrariesCommand
 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
@@ -32,57 +39,60 @@ bool cmTargetLinkLibrariesCommand
     {
     return true;
     }
+
+  // Keep track of link configuration specifiers.
+  cmTarget::LinkLibraryType llt = cmTarget::GENERAL;
+  bool haveLLT = false;
+
   // add libraries, nothe that there is an optional prefix 
   // of debug and optimized than can be used
   std::vector<std::string>::const_iterator i = args.begin();
   
   for(++i; i != args.end(); ++i)
     {
-    if (*i == "debug")
+    if(*i == "debug")
       {
-      ++i;
-      if(i == args.end())
+      if(haveLLT)
         {
-        this->SetError
-          ("The \"debug\" argument must be followed by a library");
-        return false;
+        this->LinkLibraryTypeSpecifierWarning(llt, cmTarget::DEBUG);
         }
-      this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),i->c_str(),
-                                          cmTarget::DEBUG);
+      llt = cmTarget::DEBUG;
+      haveLLT = true;
       }
-    else if (*i == "optimized")
+    else if(*i == "optimized")
       {
-      ++i;
-      if(i == args.end())
+      if(haveLLT)
         {
-        this->SetError(
-          "The \"optimized\" argument must be followed by a library");
-        return false;
+        this->LinkLibraryTypeSpecifierWarning(llt, cmTarget::OPTIMIZED);
         }
-      this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),i->c_str(),
-                                 cmTarget::OPTIMIZED);
+      llt = cmTarget::OPTIMIZED;
+      haveLLT = true;
       }
-    else if (*i == "general")
+    else if(*i == "general")
       {
-      ++i;
-      if(i == args.end())
+      if(haveLLT)
         {
-        this->SetError(
-          "The \"general\" argument must be followed by a library");
-        return false;
+        this->LinkLibraryTypeSpecifierWarning(llt, cmTarget::GENERAL);
         }
-      this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),i->c_str(),
-                                 cmTarget::GENERAL);
+      llt = cmTarget::GENERAL;
+      haveLLT = true;
+      }
+    else if(haveLLT)
+      {
+      // The link type was specified by the previous argument.
+      haveLLT = false;
+      this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),
+                                              i->c_str(), llt);
       }
     else
       {
-      // make sure the type is correct if it is currently general.  So if you
+      // Lookup old-style cache entry if type is unspecified.  So if you
       // do a target_link_libraries(foo optimized bar) it will stay optimized
       // and not use the lookup.  As there maybe the case where someone has
       // specifed that a library is both debug and optimized.  (this check is
       // only there for backwards compatibility when mixing projects built
       // with old versions of CMake and new)
-      cmTarget::LinkLibraryType llt = cmTarget::GENERAL;
+      llt = cmTarget::GENERAL;
       std::string linkType = args[0];
       linkType += "_LINK_TYPE";
       const char* linkTypeString = 
@@ -101,5 +111,29 @@ bool cmTargetLinkLibrariesCommand
       this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),i->c_str(),llt);
       }
     } 
+
+  // Make sure the last argument was not a library type specifier.
+  if(haveLLT)
+    {
+    cmOStringStream e;
+    e << "The \"" << this->LinkLibraryTypeNames[llt]
+      << "\" argument must be followed by a library.";
+    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    }
+
   return true;
 }
+
+//----------------------------------------------------------------------------
+void
+cmTargetLinkLibrariesCommand
+::LinkLibraryTypeSpecifierWarning(int left, int right)
+{
+  cmOStringStream w;
+  w << "Link library type specifier \""
+    << this->LinkLibraryTypeNames[left] << "\" is followed by specifier \""
+    << this->LinkLibraryTypeNames[right] << "\" instead of a library name.  "
+    << "The first specifier will be ignored.";
+  this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+}

+ 2 - 0
Source/cmTargetLinkLibrariesCommand.h

@@ -79,6 +79,8 @@ public:
   
   cmTypeMacro(cmTargetLinkLibrariesCommand, cmCommand);
 private:
+  void LinkLibraryTypeSpecifierWarning(int left, int right);
+  static const char* LinkLibraryTypeNames[3];
 };