Procházet zdrojové kódy

ENH: Simple specification of link interfaces

Create an INTERFACE option to the target_link_libraries command to help
set the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG
properties.  This will help users specify link interfaces using
variables from Find*.cmake modules that include the 'debug' and
'optimized' keywords.
Brad King před 17 roky
rodič
revize
e322d288af

+ 73 - 4
Source/cmTargetLinkLibrariesCommand.cxx

@@ -40,17 +40,39 @@ bool cmTargetLinkLibrariesCommand
     return true;
     }
 
+  // Lookup the target for which libraries are specified.
+  this->Target =
+    this->Makefile->GetCMakeInstance()
+    ->GetGlobalGenerator()->FindTarget(0, args[0].c_str());
+  if(!this->Target)
+    {
+    cmOStringStream e;
+    e << "Cannot specify link libraries for target \"" << args[0] << "\" "
+      << "which is not built by this project.";
+    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    return true;
+    }
+
   // Keep track of link configuration specifiers.
   cmTarget::LinkLibraryType llt = cmTarget::GENERAL;
   bool haveLLT = false;
 
+  // Start with primary linking and switch to link interface
+  // specification when the keyword is encountered.
+  this->DoingInterface = 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 == "INTERFACE")
+      {
+      this->DoingInterface = true;
+      }
+    else if(*i == "debug")
       {
       if(haveLLT)
         {
@@ -81,8 +103,7 @@ bool cmTargetLinkLibrariesCommand
       {
       // The link type was specified by the previous argument.
       haveLLT = false;
-      this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),
-                                              i->c_str(), llt);
+      this->HandleLibrary(i->c_str(), llt);
       }
     else
       {
@@ -108,7 +129,7 @@ bool cmTargetLinkLibrariesCommand
           llt = cmTarget::OPTIMIZED;
           }
         }
-      this->Makefile->AddLinkLibraryForTarget(args[0].c_str(),i->c_str(),llt);
+      this->HandleLibrary(i->c_str(), llt);
       }
     } 
 
@@ -122,6 +143,15 @@ bool cmTargetLinkLibrariesCommand
     cmSystemTools::SetFatalErrorOccured();
     }
 
+  // If the INTERFACE option was given, make sure the
+  // LINK_INTERFACE_LIBRARIES property exists.  This allows the
+  // command to be used to specify an empty link interface.
+  if(this->DoingInterface &&
+     !this->Target->GetProperty("LINK_INTERFACE_LIBRARIES"))
+    {
+    this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
+    }
+
   return true;
 }
 
@@ -137,3 +167,42 @@ cmTargetLinkLibrariesCommand
     << "The first specifier will be ignored.";
   this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
 }
+
+//----------------------------------------------------------------------------
+void
+cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
+                                            cmTarget::LinkLibraryType llt)
+{
+  // Handle normal case first.
+  if(!this->DoingInterface)
+    {
+    this->Makefile
+      ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
+    return;
+    }
+
+  // Include this library in the link interface for the target.
+  if(llt == cmTarget::DEBUG)
+    {
+    // Put in only the DEBUG configuration interface.
+    this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES_DEBUG", lib);
+    }
+  else if(llt == cmTarget::OPTIMIZED)
+    {
+    // Put in only the non-DEBUG configuration interface.
+    this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib);
+
+    // Make sure the DEBUG configuration interface exists so that this
+    // one will not be used as a fall-back.
+    if(!this->Target->GetProperty("LINK_INTERFACE_LIBRARIES_DEBUG"))
+      {
+      this->Target->SetProperty("LINK_INTERFACE_LIBRARIES_DEBUG", "");
+      }
+    }
+  else
+    {
+    // Put in both the DEBUG and non-DEBUG configuration interfaces.
+    this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib);
+    this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES_DEBUG", lib);
+    }
+}

+ 38 - 8
Source/cmTargetLinkLibrariesCommand.h

@@ -64,23 +64,53 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
-      "  target_link_libraries(target library1\n"
-      "                        <debug | optimized | general> library2\n"
-      "                        ...)\n"
+      "  target_link_libraries(<target> [INTERFACE]\n"
+      "                        [[debug|optimized|general] <lib>] ...)\n"
       "Specify a list of libraries to be linked into the specified target.  "
-      "The debug and optimized strings may be used to indicate that "
-      "the next library listed is to be used only for that specific "
-      "type of build. general indicates it is used for all build types "
-      "and is assumed if not specified.\n"
       "If any library name matches that of a target in the current project "
       "a dependency will automatically be added in the build system to make "
-      "sure the library being linked is up-to-date before the target links.";
+      "sure the library being linked is up-to-date before the target links."
+      "\n"
+      "A \"debug\", \"optimized\", or \"general\" keyword indicates that "
+      "the library immediately following it is to be used only for the "
+      "corresponding build configuration.  "
+      "The \"debug\" keyword corresponds to the Debug configuration.  "
+      "The \"optimized\" keyword corresponds to all other configurations.  "
+      "The \"general\" keyword corresponds to all configurations, and is "
+      "purely optional (assumed if omitted).  "
+      "Higher granularity may be achieved for per-configuration rules "
+      "by creating and linking to IMPORTED library targets.  "
+      "See the IMPORTED mode of the add_library command for more "
+      "information.  "
+      "\n"
+      "Library dependencies are transitive by default.  "
+      "When this target is linked into another target then the libraries "
+      "linked to this target will appear on the link line for the other "
+      "target too.  "
+      "See the LINK_INTERFACE_LIBRARIES target property to override the "
+      "set of transitive link dependencies for a target."
+      "\n"
+      "The INTERFACE option tells the command to append the libraries "
+      "to the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG "
+      "target properties instead of using them for linking.  "
+      "Libraries specified as \"debug\" are appended to the "
+      "the LINK_INTERFACE_LIBRARIES_DEBUG property.  "
+      "Libraries specified as \"optimized\" are appended to the "
+      "the LINK_INTERFACE_LIBRARIES property.  "
+      "Libraries specified as \"general\" (or without any keyword) are "
+      "appended to both properties."
+      ;
     }
   
   cmTypeMacro(cmTargetLinkLibrariesCommand, cmCommand);
 private:
   void LinkLibraryTypeSpecifierWarning(int left, int right);
   static const char* LinkLibraryTypeNames[3];
+
+  cmTarget* Target;
+  bool DoingInterface;
+
+  void HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt);
 };