From e322d288af7a2e9f413a703e07399976377c7dd0 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 11 Aug 2008 16:23:02 -0400 Subject: [PATCH] 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. --- Source/cmTargetLinkLibrariesCommand.cxx | 77 +++++++++++++++++++++++-- Source/cmTargetLinkLibrariesCommand.h | 46 ++++++++++++--- 2 files changed, 111 insertions(+), 12 deletions(-) diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 73bb5a5b3..21acf8075 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/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::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); + } +} diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index ccf86ad80..6a9c0f4d4 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -64,23 +64,53 @@ public: virtual const char* GetFullDocumentation() { return - " target_link_libraries(target library1\n" - " library2\n" - " ...)\n" + " target_link_libraries( [INTERFACE]\n" + " [[debug|optimized|general] ] ...)\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); };