summaryrefslogtreecommitdiffstats
path: root/Source/cmTarget.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmTarget.cxx')
-rw-r--r--Source/cmTarget.cxx3755
1 files changed, 3755 insertions, 0 deletions
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
new file mode 100644
index 0000000..bb44956
--- /dev/null
+++ b/Source/cmTarget.cxx
@@ -0,0 +1,3755 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmTarget.h"
+#include "cmake.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmOutputConverter.h"
+#include "cmGlobalGenerator.h"
+#include "cmComputeLinkInformation.h"
+#include "cmListFileCache.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmAlgorithms.h"
+#include <cmsys/RegularExpression.hxx>
+#include <map>
+#include <set>
+#include <stdlib.h> // required for atof
+#include <assert.h>
+#include <errno.h>
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include <cmsys/hash_set.hxx>
+#define UNORDERED_SET cmsys::hash_set
+#else
+#define UNORDERED_SET std::set
+#endif
+
+const char* cmTarget::GetTargetTypeName(TargetType targetType)
+{
+ switch( targetType )
+ {
+ case cmTarget::STATIC_LIBRARY:
+ return "STATIC_LIBRARY";
+ case cmTarget::MODULE_LIBRARY:
+ return "MODULE_LIBRARY";
+ case cmTarget::SHARED_LIBRARY:
+ return "SHARED_LIBRARY";
+ case cmTarget::OBJECT_LIBRARY:
+ return "OBJECT_LIBRARY";
+ case cmTarget::EXECUTABLE:
+ return "EXECUTABLE";
+ case cmTarget::UTILITY:
+ return "UTILITY";
+ case cmTarget::GLOBAL_TARGET:
+ return "GLOBAL_TARGET";
+ case cmTarget::INTERFACE_LIBRARY:
+ return "INTERFACE_LIBRARY";
+ case cmTarget::UNKNOWN_LIBRARY:
+ return "UNKNOWN_LIBRARY";
+ }
+ assert(0 && "Unexpected target type");
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+struct cmTarget::OutputInfo
+{
+ std::string OutDir;
+ std::string ImpDir;
+ std::string PdbDir;
+ bool empty() const
+ { return OutDir.empty() && ImpDir.empty() && PdbDir.empty(); }
+};
+
+//----------------------------------------------------------------------------
+class cmTargetInternals
+{
+public:
+ cmTargetInternals()
+ : Backtrace()
+ {
+ this->UtilityItemsDone = false;
+ }
+ cmTargetInternals(cmTargetInternals const&)
+ : Backtrace()
+ {
+ this->UtilityItemsDone = false;
+ }
+ ~cmTargetInternals();
+
+ // The backtrace when the target was created.
+ cmListFileBacktrace Backtrace;
+
+ typedef std::map<std::string, cmTarget::OutputInfo> OutputInfoMapType;
+ OutputInfoMapType OutputInfoMap;
+
+ typedef std::map<std::string, cmTarget::ImportInfo> ImportInfoMapType;
+ ImportInfoMapType ImportInfoMap;
+
+ struct HeadToLinkImplementationMap:
+ public std::map<cmTarget const*, cmOptionalLinkImplementation> {};
+ typedef std::map<std::string,
+ HeadToLinkImplementationMap> LinkImplMapType;
+ LinkImplMapType LinkImplMap;
+
+ typedef std::map<std::string, std::vector<cmSourceFile*> >
+ SourceFilesMapType;
+ SourceFilesMapType SourceFilesMap;
+
+ std::set<cmLinkItem> UtilityItems;
+ bool UtilityItemsDone;
+
+ class TargetPropertyEntry {
+ static cmLinkImplItem NoLinkImplItem;
+ public:
+ TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : ge(cge), LinkImplItem(item)
+ {}
+ const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
+ cmLinkImplItem const& LinkImplItem;
+ };
+ std::vector<std::string> IncludeDirectoriesEntries;
+ std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
+ std::vector<std::string> CompileOptionsEntries;
+ std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+ std::vector<std::string> CompileFeaturesEntries;
+ std::vector<cmListFileBacktrace> CompileFeaturesBacktraces;
+ std::vector<std::string> CompileDefinitionsEntries;
+ std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+ std::vector<TargetPropertyEntry*> SourceEntries;
+ std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries;
+
+ void AddInterfaceEntries(
+ cmTarget const* thisTarget, std::string const& config,
+ std::string const& prop, std::vector<TargetPropertyEntry*>& entries);
+};
+
+cmLinkImplItem cmTargetInternals::TargetPropertyEntry::NoLinkImplItem;
+
+//----------------------------------------------------------------------------
+cmTargetInternals::~cmTargetInternals()
+{
+}
+
+//----------------------------------------------------------------------------
+cmTarget::cmTarget()
+{
+ this->Makefile = 0;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LinkLibrariesForVS6Analyzed = false;
+#endif
+ this->HaveInstallRule = false;
+ this->DLLPlatform = false;
+ this->IsAndroid = false;
+ this->IsApple = false;
+ this->IsImportedTarget = false;
+ this->BuildInterfaceIncludesAppended = false;
+ this->DebugSourcesDone = false;
+ this->LinkImplementationLanguageIsContextDependent = true;
+}
+
+void cmTarget::SetType(TargetType type, const std::string& name)
+{
+ this->Name = name;
+ // only add dependency information for library targets
+ this->TargetTypeValue = type;
+ if(this->TargetTypeValue >= STATIC_LIBRARY
+ && this->TargetTypeValue <= MODULE_LIBRARY)
+ {
+ this->RecordDependencies = true;
+ }
+ else
+ {
+ this->RecordDependencies = false;
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::SetMakefile(cmMakefile* mf)
+{
+ // Set our makefile.
+ this->Makefile = mf;
+
+ // Check whether this is a DLL platform.
+ this->DLLPlatform = (this->Makefile->IsOn("WIN32") ||
+ this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"));
+
+ // Check whether we are targeting an Android platform.
+ this->IsAndroid =
+ strcmp(this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"),
+ "Android") == 0;
+
+ // Check whether we are targeting an Apple platform.
+ this->IsApple = this->Makefile->IsOn("APPLE");
+
+ // Setup default property values.
+ if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY)
+ {
+ this->SetPropertyDefault("ANDROID_API", 0);
+ this->SetPropertyDefault("ANDROID_API_MIN", 0);
+ this->SetPropertyDefault("ANDROID_ARCH", 0);
+ this->SetPropertyDefault("ANDROID_STL_TYPE", 0);
+ this->SetPropertyDefault("ANDROID_SKIP_ANT_STEP", 0);
+ this->SetPropertyDefault("ANDROID_PROCESS_MAX", 0);
+ this->SetPropertyDefault("ANDROID_PROGUARD", 0);
+ this->SetPropertyDefault("ANDROID_PROGUARD_CONFIG_PATH", 0);
+ this->SetPropertyDefault("ANDROID_SECURE_PROPS_PATH", 0);
+ this->SetPropertyDefault("ANDROID_NATIVE_LIB_DIRECTORIES", 0);
+ this->SetPropertyDefault("ANDROID_NATIVE_LIB_DEPENDENCIES", 0);
+ this->SetPropertyDefault("ANDROID_JAVA_SOURCE_DIR", 0);
+ this->SetPropertyDefault("ANDROID_JAR_DIRECTORIES", 0);
+ this->SetPropertyDefault("ANDROID_JAR_DEPENDENCIES", 0);
+ this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", 0);
+ this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", 0);
+ this->SetPropertyDefault("INSTALL_NAME_DIR", 0);
+ this->SetPropertyDefault("INSTALL_RPATH", "");
+ this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
+ this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
+ this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0);
+ this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0);
+ this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0);
+ this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", 0);
+ this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", 0);
+ this->SetPropertyDefault("Fortran_FORMAT", 0);
+ this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0);
+ this->SetPropertyDefault("GNUtoMS", 0);
+ this->SetPropertyDefault("OSX_ARCHITECTURES", 0);
+ this->SetPropertyDefault("AUTOMOC", 0);
+ this->SetPropertyDefault("AUTOUIC", 0);
+ this->SetPropertyDefault("AUTORCC", 0);
+ this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", 0);
+ this->SetPropertyDefault("AUTOUIC_OPTIONS", 0);
+ this->SetPropertyDefault("AUTORCC_OPTIONS", 0);
+ this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", 0);
+ this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", 0);
+ this->SetPropertyDefault("WIN32_EXECUTABLE", 0);
+ this->SetPropertyDefault("MACOSX_BUNDLE", 0);
+ this->SetPropertyDefault("MACOSX_RPATH", 0);
+ this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 0);
+ this->SetPropertyDefault("C_COMPILER_LAUNCHER", 0);
+ this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", 0);
+ this->SetPropertyDefault("C_STANDARD", 0);
+ this->SetPropertyDefault("C_STANDARD_REQUIRED", 0);
+ this->SetPropertyDefault("C_EXTENSIONS", 0);
+ this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", 0);
+ this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", 0);
+ this->SetPropertyDefault("CXX_STANDARD", 0);
+ this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0);
+ this->SetPropertyDefault("CXX_EXTENSIONS", 0);
+ this->SetPropertyDefault("LINK_SEARCH_START_STATIC", 0);
+ this->SetPropertyDefault("LINK_SEARCH_END_STATIC", 0);
+ }
+
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames;
+ mf->GetConfigurations(configNames);
+
+ // Setup per-configuration property default values.
+ if (this->GetType() != UTILITY)
+ {
+ const char* configProps[] = {
+ "ARCHIVE_OUTPUT_DIRECTORY_",
+ "LIBRARY_OUTPUT_DIRECTORY_",
+ "RUNTIME_OUTPUT_DIRECTORY_",
+ "PDB_OUTPUT_DIRECTORY_",
+ "COMPILE_PDB_OUTPUT_DIRECTORY_",
+ "MAP_IMPORTED_CONFIG_",
+ 0};
+ for(std::vector<std::string>::iterator ci = configNames.begin();
+ ci != configNames.end(); ++ci)
+ {
+ std::string configUpper = cmSystemTools::UpperCase(*ci);
+ for(const char** p = configProps; *p; ++p)
+ {
+ if (this->TargetTypeValue == INTERFACE_LIBRARY
+ && strcmp(*p, "MAP_IMPORTED_CONFIG_") != 0)
+ {
+ continue;
+ }
+ std::string property = *p;
+ property += configUpper;
+ this->SetPropertyDefault(property, 0);
+ }
+
+ // Initialize per-configuration name postfix property from the
+ // variable only for non-executable targets. This preserves
+ // compatibility with previous CMake versions in which executables
+ // did not support this variable. Projects may still specify the
+ // property directly.
+ if(this->TargetTypeValue != cmTarget::EXECUTABLE
+ && this->TargetTypeValue != cmTarget::INTERFACE_LIBRARY)
+ {
+ std::string property = cmSystemTools::UpperCase(*ci);
+ property += "_POSTFIX";
+ this->SetPropertyDefault(property, 0);
+ }
+ }
+ }
+
+ // Save the backtrace of target construction.
+ this->Internal->Backtrace = this->Makefile->GetBacktrace();
+
+ if (!this->IsImported())
+ {
+ // Initialize the INCLUDE_DIRECTORIES property based on the current value
+ // of the same directory property:
+ const cmStringRange parentIncludes =
+ this->Makefile->GetIncludeDirectoriesEntries();
+ const cmBacktraceRange parentIncludesBts =
+ this->Makefile->GetIncludeDirectoriesBacktraces();
+
+ this->Internal->IncludeDirectoriesEntries.insert(
+ this->Internal->IncludeDirectoriesEntries.end(),
+ parentIncludes.begin(), parentIncludes.end());
+ this->Internal->IncludeDirectoriesBacktraces.insert(
+ this->Internal->IncludeDirectoriesBacktraces.end(),
+ parentIncludesBts.begin(), parentIncludesBts.end());
+
+ const std::set<std::string> parentSystemIncludes =
+ this->Makefile->GetSystemIncludeDirectories();
+
+ this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
+ parentSystemIncludes.end());
+
+ const cmStringRange parentOptions =
+ this->Makefile->GetCompileOptionsEntries();
+ const cmBacktraceRange parentOptionsBts =
+ this->Makefile->GetCompileOptionsBacktraces();
+
+ this->Internal->CompileOptionsEntries.insert(
+ this->Internal->CompileOptionsEntries.end(),
+ parentOptions.begin(), parentOptions.end());
+ this->Internal->CompileOptionsBacktraces.insert(
+ this->Internal->CompileOptionsBacktraces.end(),
+ parentOptionsBts.begin(), parentOptionsBts.end());
+ }
+
+ if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY)
+ {
+ this->SetPropertyDefault("C_VISIBILITY_PRESET", 0);
+ this->SetPropertyDefault("CXX_VISIBILITY_PRESET", 0);
+ this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", 0);
+ }
+
+ if(this->TargetTypeValue == cmTarget::EXECUTABLE)
+ {
+ this->SetPropertyDefault("ANDROID_GUI", 0);
+ this->SetPropertyDefault("CROSSCOMPILING_EMULATOR", 0);
+ this->SetPropertyDefault("ENABLE_EXPORTS", 0);
+ }
+ if(this->TargetTypeValue == cmTarget::SHARED_LIBRARY
+ || this->TargetTypeValue == cmTarget::MODULE_LIBRARY)
+ {
+ this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
+ }
+ if(this->TargetTypeValue == cmTarget::SHARED_LIBRARY)
+ {
+ this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", 0);
+ }
+
+ if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY)
+ {
+ this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", 0);
+ }
+
+ // Record current policies for later use.
+ this->Makefile->RecordPolicies(this->PolicyMap);
+
+ if (this->TargetTypeValue == INTERFACE_LIBRARY)
+ {
+ // This policy is checked in a few conditions. The properties relevant
+ // to the policy are always ignored for INTERFACE_LIBRARY targets,
+ // so ensure that the conditions don't lead to nonsense.
+ this->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+ }
+
+ if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY)
+ {
+ this->SetPropertyDefault("JOB_POOL_COMPILE", 0);
+ this->SetPropertyDefault("JOB_POOL_LINK", 0);
+ }
+}
+
+void CreatePropertyGeneratorExpressions(
+ std::vector<std::string> const& entries,
+ std::vector<cmListFileBacktrace> const& backtraces,
+ std::vector<cmTargetInternals::TargetPropertyEntry*>& items)
+{
+ std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin();
+ for (std::vector<std::string>::const_iterator it = entries.begin();
+ it != entries.end(); ++it, ++btIt)
+ {
+ cmGeneratorExpression ge(*btIt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
+ items.push_back(new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AddUtility(const std::string& u, cmMakefile *makefile)
+{
+ if(this->Utilities.insert(u).second && makefile)
+ {
+ UtilityBacktraces.insert(std::make_pair(u, makefile->GetBacktrace()));
+ }
+}
+
+//----------------------------------------------------------------------------
+cmListFileBacktrace const* cmTarget::GetUtilityBacktrace(
+ const std::string& u) const
+{
+ std::map<std::string, cmListFileBacktrace>::const_iterator i =
+ this->UtilityBacktraces.find(u);
+ if(i == this->UtilityBacktraces.end()) return 0;
+
+ return &i->second;
+}
+
+//----------------------------------------------------------------------------
+std::set<cmLinkItem> const& cmTarget::GetUtilityItems() const
+{
+ if(!this->Internal->UtilityItemsDone)
+ {
+ this->Internal->UtilityItemsDone = true;
+ for(std::set<std::string>::const_iterator i = this->Utilities.begin();
+ i != this->Utilities.end(); ++i)
+ {
+ this->Internal->UtilityItems.insert(
+ cmLinkItem(*i, this->Makefile->FindTargetToUse(*i)));
+ }
+ }
+ return this->Internal->UtilityItems;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::FinishConfigure()
+{
+ // Erase any cached link information that might have been comptued
+ // on-demand during the configuration. This ensures that build
+ // system generation uses up-to-date information even if other cache
+ // invalidation code in this source file is buggy.
+ this->ClearLinkMaps();
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Do old-style link dependency analysis only for CM_USE_OLD_VS6.
+ if(this->Makefile->GetGlobalGenerator()->IsForVS6())
+ {
+ this->AnalyzeLibDependenciesForVS6(*this->Makefile);
+ }
+#endif
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::ClearLinkMaps()
+{
+ this->LinkImplementationLanguageIsContextDependent = true;
+ this->Internal->LinkImplMap.clear();
+ this->Internal->SourceFilesMap.clear();
+}
+
+//----------------------------------------------------------------------------
+cmListFileBacktrace const& cmTarget::GetBacktrace() const
+{
+ return this->Internal->Backtrace;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetSupportDirectory() const
+{
+ std::string dir = this->Makefile->GetCurrentBinaryDirectory();
+ dir += cmake::GetCMakeFilesDirectory();
+ dir += "/";
+ dir += this->Name;
+#if defined(__VMS)
+ dir += "_dir";
+#else
+ dir += ".dir";
+#endif
+ return dir;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsExecutableWithExports() const
+{
+ return (this->GetType() == cmTarget::EXECUTABLE &&
+ this->GetPropertyAsBool("ENABLE_EXPORTS"));
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsLinkable() const
+{
+ return (this->GetType() == cmTarget::STATIC_LIBRARY ||
+ this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY ||
+ this->GetType() == cmTarget::UNKNOWN_LIBRARY ||
+ this->GetType() == cmTarget::INTERFACE_LIBRARY ||
+ this->IsExecutableWithExports());
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HasImportLibrary() const
+{
+ return (this->DLLPlatform &&
+ (this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()));
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsFrameworkOnApple() const
+{
+ return (this->GetType() == cmTarget::SHARED_LIBRARY &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("FRAMEWORK"));
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsAppBundleOnApple() const
+{
+ return (this->GetType() == cmTarget::EXECUTABLE &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("MACOSX_BUNDLE"));
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsCFBundleOnApple() const
+{
+ return (this->GetType() == cmTarget::MODULE_LIBRARY &&
+ this->Makefile->IsOn("APPLE") &&
+ this->GetPropertyAsBool("BUNDLE"));
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsXCTestOnApple() const
+{
+ return (this->IsCFBundleOnApple() &&
+ this->GetPropertyAsBool("XCTEST"));
+}
+
+//----------------------------------------------------------------------------
+static bool processSources(cmTarget const* tgt,
+ const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries,
+ std::vector<std::string> &srcs,
+ UNORDERED_SET<std::string> &uniqueSrcs,
+ cmGeneratorExpressionDAGChecker *dagChecker,
+ std::string const& config, bool debugSources)
+{
+ cmMakefile *mf = tgt->GetMakefile();
+
+ bool contextDependent = false;
+
+ for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
+ it = entries.begin(), end = entries.end(); it != end; ++it)
+ {
+ cmLinkImplItem const& item = (*it)->LinkImplItem;
+ std::string const& targetName = item;
+ std::vector<std::string> entrySources;
+ cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(mf,
+ config,
+ false,
+ tgt,
+ tgt,
+ dagChecker),
+ entrySources);
+
+ if ((*it)->ge->GetHadContextSensitiveCondition())
+ {
+ contextDependent = true;
+ }
+
+ for(std::vector<std::string>::iterator i = entrySources.begin();
+ i != entrySources.end(); ++i)
+ {
+ std::string& src = *i;
+ cmSourceFile* sf = mf->GetOrCreateSource(src);
+ std::string e;
+ std::string fullPath = sf->GetFullPath(&e);
+ if(fullPath.empty())
+ {
+ if(!e.empty())
+ {
+ cmake* cm = mf->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, e,
+ tgt->GetBacktrace());
+ }
+ return contextDependent;
+ }
+
+ if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src.c_str()))
+ {
+ std::ostringstream err;
+ if (!targetName.empty())
+ {
+ err << "Target \"" << targetName << "\" contains relative "
+ "path in its INTERFACE_SOURCES:\n"
+ " \"" << src << "\"";
+ }
+ else
+ {
+ err << "Found relative path while evaluating sources of "
+ "\"" << tgt->GetName() << "\":\n \"" << src << "\"\n";
+ }
+ tgt->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, err.str());
+ return contextDependent;
+ }
+ src = fullPath;
+ }
+ std::string usedSources;
+ for(std::vector<std::string>::iterator
+ li = entrySources.begin(); li != entrySources.end(); ++li)
+ {
+ std::string src = *li;
+
+ if(uniqueSrcs.insert(src).second)
+ {
+ srcs.push_back(src);
+ if (debugSources)
+ {
+ usedSources += " * " + src + "\n";
+ }
+ }
+ }
+ if (!usedSources.empty())
+ {
+ mf->GetCMakeInstance()->IssueMessage(cmake::LOG,
+ std::string("Used sources for target ")
+ + tgt->GetName() + ":\n"
+ + usedSources, (*it)->ge->GetBacktrace());
+ }
+ }
+ return contextDependent;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetSourceFiles(std::vector<std::string> &files,
+ const std::string& config) const
+{
+ assert(this->GetType() != INTERFACE_LIBRARY);
+
+ if (!this->GetMakefile()->GetGlobalGenerator()->GetConfigureDoneCMP0026())
+ {
+ // At configure-time, this method can be called as part of getting the
+ // LOCATION property or to export() a file to be include()d. However
+ // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+ // for TARGET_OBJECTS instead for backwards compatibility with OLD
+ // behavior of CMP0024 and CMP0026 only.
+
+ typedef cmTargetInternals::TargetPropertyEntry
+ TargetPropertyEntry;
+ for(std::vector<TargetPropertyEntry*>::const_iterator
+ i = this->Internal->SourceEntries.begin();
+ i != this->Internal->SourceEntries.end(); ++i)
+ {
+ std::string entry = (*i)->ge->GetInput();
+
+ std::vector<std::string> items;
+ cmSystemTools::ExpandListArgument(entry, items);
+ for (std::vector<std::string>::const_iterator
+ li = items.begin(); li != items.end(); ++li)
+ {
+ if(cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+ (*li)[li->size() - 1] == '>')
+ {
+ continue;
+ }
+ files.push_back(*li);
+ }
+ }
+ return;
+ }
+
+ std::vector<std::string> debugProperties;
+ const char *debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp)
+ {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugSources = !this->DebugSourcesDone
+ && std::find(debugProperties.begin(),
+ debugProperties.end(),
+ "SOURCES")
+ != debugProperties.end();
+
+ if (this->GetMakefile()->GetGlobalGenerator()->GetConfigureDoneCMP0026())
+ {
+ this->DebugSourcesDone = true;
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(this->GetName(),
+ "SOURCES", 0, 0);
+
+ UNORDERED_SET<std::string> uniqueSrcs;
+ bool contextDependentDirectSources = processSources(this,
+ this->Internal->SourceEntries,
+ files,
+ uniqueSrcs,
+ &dagChecker,
+ config,
+ debugSources);
+
+ std::vector<cmTargetInternals::TargetPropertyEntry*>
+ linkInterfaceSourcesEntries;
+
+ this->Internal->AddInterfaceEntries(
+ this, config, "INTERFACE_SOURCES",
+ linkInterfaceSourcesEntries);
+
+ std::vector<std::string>::size_type numFilesBefore = files.size();
+ bool contextDependentInterfaceSources = processSources(this,
+ linkInterfaceSourcesEntries,
+ files,
+ uniqueSrcs,
+ &dagChecker,
+ config,
+ debugSources);
+
+ if (!contextDependentDirectSources
+ && !(contextDependentInterfaceSources && numFilesBefore < files.size()))
+ {
+ this->LinkImplementationLanguageIsContextDependent = false;
+ }
+
+ cmDeleteAll(linkInterfaceSourcesEntries);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files,
+ const std::string& config) const
+{
+
+ // Lookup any existing link implementation for this configuration.
+ std::string key = cmSystemTools::UpperCase(config);
+
+ if(!this->LinkImplementationLanguageIsContextDependent)
+ {
+ files = this->Internal->SourceFilesMap.begin()->second;
+ return;
+ }
+
+ cmTargetInternals::SourceFilesMapType::iterator
+ it = this->Internal->SourceFilesMap.find(key);
+ if(it != this->Internal->SourceFilesMap.end())
+ {
+ files = it->second;
+ }
+ else
+ {
+ std::vector<std::string> srcs;
+ this->GetSourceFiles(srcs, config);
+
+ std::set<cmSourceFile*> emitted;
+
+ for(std::vector<std::string>::const_iterator i = srcs.begin();
+ i != srcs.end(); ++i)
+ {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(*i);
+ if (emitted.insert(sf).second)
+ {
+ files.push_back(sf);
+ }
+ }
+ this->Internal->SourceFilesMap[key] = files;
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
+{
+ std::string srcFiles = cmJoin(srcs, ";");
+ if (!srcFiles.empty())
+ {
+ this->Internal->SourceFilesMap.clear();
+ this->LinkImplementationLanguageIsContextDependent = true;
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(srcFiles);
+ cge->SetEvaluateForBuildsystem(true);
+ this->Internal->SourceEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AddSources(std::vector<std::string> const& srcs)
+{
+ std::string srcFiles;
+ const char* sep = "";
+ for(std::vector<std::string>::const_iterator i = srcs.begin();
+ i != srcs.end(); ++i)
+ {
+ std::string filename = *i;
+ const char* src = filename.c_str();
+
+ if(!(src[0] == '$' && src[1] == '<'))
+ {
+ if(!filename.empty())
+ {
+ filename = this->ProcessSourceItemCMP0049(filename);
+ if(filename.empty())
+ {
+ return;
+ }
+ }
+ this->Makefile->GetOrCreateSource(filename);
+ }
+ srcFiles += sep;
+ srcFiles += filename;
+ sep = ";";
+ }
+ if (!srcFiles.empty())
+ {
+ this->Internal->SourceFilesMap.clear();
+ this->LinkImplementationLanguageIsContextDependent = true;
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(srcFiles);
+ cge->SetEvaluateForBuildsystem(true);
+ this->Internal->SourceEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
+{
+ std::string src = s;
+
+ // For backwards compatibility replace varibles in source names.
+ // This should eventually be removed.
+ this->Makefile->ExpandVariablesInString(src);
+ if (src != s)
+ {
+ std::ostringstream e;
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0049))
+ {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0049) << "\n";
+ break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ messageType = cmake::FATAL_ERROR;
+ }
+ if (!noMessage)
+ {
+ e << "Legacy variable expansion in source file \""
+ << s << "\" expanded to \"" << src << "\" in target \""
+ << this->GetName() << "\". This behavior will be removed in a "
+ "future version of CMake.";
+ this->Makefile->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR)
+ {
+ return "";
+ }
+ }
+ }
+ return src;
+}
+
+//----------------------------------------------------------------------------
+cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
+{
+ std::string src = this->ProcessSourceItemCMP0049(s);
+ if(!s.empty() && src.empty())
+ {
+ return 0;
+ }
+ return this->AddSource(src);
+}
+
+//----------------------------------------------------------------------------
+struct CreateLocation
+{
+ cmMakefile const* Makefile;
+
+ CreateLocation(cmMakefile const* mf)
+ : Makefile(mf)
+ {
+
+ }
+
+ cmSourceFileLocation operator()(const std::string& filename)
+ {
+ return cmSourceFileLocation(this->Makefile, filename);
+ }
+};
+
+//----------------------------------------------------------------------------
+struct LocationMatcher
+{
+ const cmSourceFileLocation& Needle;
+
+ LocationMatcher(const cmSourceFileLocation& needle)
+ : Needle(needle)
+ {
+
+ }
+
+ bool operator()(cmSourceFileLocation &loc)
+ {
+ return loc.Matches(this->Needle);
+ }
+};
+
+
+//----------------------------------------------------------------------------
+struct TargetPropertyEntryFinder
+{
+private:
+ const cmSourceFileLocation& Needle;
+public:
+ TargetPropertyEntryFinder(const cmSourceFileLocation& needle)
+ : Needle(needle)
+ {
+
+ }
+
+ bool operator()(cmTargetInternals::TargetPropertyEntry* entry)
+ {
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(entry->ge->GetInput(), files);
+ std::vector<cmSourceFileLocation> locations(files.size());
+ std::transform(files.begin(), files.end(), locations.begin(),
+ CreateLocation(this->Needle.GetMakefile()));
+
+ return std::find_if(locations.begin(), locations.end(),
+ LocationMatcher(this->Needle)) != locations.end();
+ }
+};
+
+//----------------------------------------------------------------------------
+cmSourceFile* cmTarget::AddSource(const std::string& src)
+{
+ cmSourceFileLocation sfl(this->Makefile, src);
+ if (std::find_if(this->Internal->SourceEntries.begin(),
+ this->Internal->SourceEntries.end(),
+ TargetPropertyEntryFinder(sfl))
+ == this->Internal->SourceEntries.end())
+ {
+ this->Internal->SourceFilesMap.clear();
+ this->LinkImplementationLanguageIsContextDependent = true;
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
+ cge->SetEvaluateForBuildsystem(true);
+ this->Internal->SourceEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+ if (cmGeneratorExpression::Find(src) != std::string::npos)
+ {
+ return 0;
+ }
+ return this->Makefile->GetOrCreateSource(src);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::MergeLinkLibraries( cmMakefile& mf,
+ const std::string& selfname,
+ const LinkLibraryVectorType& libs )
+{
+ // Only add on libraries we haven't added on before.
+ // Assumption: the global link libraries could only grow, never shrink
+ LinkLibraryVectorType::const_iterator i = libs.begin();
+ i += this->PrevLinkedLibraries.size();
+ for( ; i != libs.end(); ++i )
+ {
+ // This is equivalent to the target_link_libraries plain signature.
+ this->AddLinkLibrary( mf, selfname, i->first, i->second );
+ this->AppendProperty("INTERFACE_LINK_LIBRARIES",
+ this->GetDebugGeneratorExpressions(i->first, i->second).c_str());
+ }
+ this->PrevLinkedLibraries = libs;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AddLinkDirectory(const std::string& d)
+{
+ // Make sure we don't add unnecessary search directories.
+ if(this->LinkDirectoriesEmmitted.insert(d).second)
+ {
+ this->LinkDirectories.push_back(d);
+ }
+}
+
+//----------------------------------------------------------------------------
+const std::vector<std::string>& cmTarget::GetLinkDirectories() const
+{
+ return this->LinkDirectories;
+}
+
+//----------------------------------------------------------------------------
+cmTarget::LinkLibraryType cmTarget::ComputeLinkType(
+ const std::string& config) const
+{
+ // No configuration is always optimized.
+ if(config.empty())
+ {
+ return cmTarget::OPTIMIZED;
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+
+ // Check if any entry in the list matches this configuration.
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (std::find(debugConfigs.begin(), debugConfigs.end(), configUpper) !=
+ debugConfigs.end())
+ {
+ return cmTarget::DEBUG;
+ }
+ // The current configuration is not a debug configuration.
+ return cmTarget::OPTIMIZED;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::ClearDependencyInformation( cmMakefile& mf,
+ const std::string& target )
+{
+ // Clear the dependencies. The cache variable must exist iff we are
+ // recording dependency information for this target.
+ std::string depname = target;
+ depname += "_LIB_DEPENDS";
+ if (this->RecordDependencies)
+ {
+ mf.AddCacheDefinition(depname, "",
+ "Dependencies for target", cmState::STATIC);
+ }
+ else
+ {
+ if (mf.GetDefinition( depname ))
+ {
+ std::string message = "Target ";
+ message += target;
+ message += " has dependency information when it shouldn't.\n";
+ message += "Your cache is probably stale. Please remove the entry\n ";
+ message += depname;
+ message += "\nfrom the cache.";
+ cmSystemTools::Error( message.c_str() );
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::NameResolvesToFramework(const std::string& libname) const
+{
+ return this->Makefile->GetGlobalGenerator()->
+ NameResolvesToFramework(libname);
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value,
+ cmTarget::LinkLibraryType llt) const
+{
+ if (llt == GENERAL)
+ {
+ return value;
+ }
+
+ // Get the list of configurations considered to be DEBUG.
+ std::vector<std::string> debugConfigs =
+ this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+
+ std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
+
+ if (debugConfigs.size() > 1)
+ {
+ for(std::vector<std::string>::const_iterator
+ li = debugConfigs.begin() + 1; li != debugConfigs.end(); ++li)
+ {
+ configString += ",$<CONFIG:" + *li + ">";
+ }
+ configString = "$<OR:" + configString + ">";
+ }
+
+ if (llt == OPTIMIZED)
+ {
+ configString = "$<NOT:" + configString + ">";
+ }
+ return "$<" + configString + ":" + value + ">";
+}
+
+//----------------------------------------------------------------------------
+static std::string targetNameGenex(const std::string& lib)
+{
+ return "$<TARGET_NAME:" + lib + ">";
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
+ cmListFileContext const& lfc)
+{
+ bool ret = true;
+ if (!this->TLLCommands.empty())
+ {
+ if (this->TLLCommands.back().first != signature)
+ {
+ ret = false;
+ }
+ }
+ if (this->TLLCommands.empty() || this->TLLCommands.back().second != lfc)
+ {
+ this->TLLCommands.push_back(std::make_pair(signature, lfc));
+ }
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetTllSignatureTraces(std::ostringstream &s,
+ TLLSignature sig) const
+{
+ const char *sigString = (sig == cmTarget::KeywordTLLSignature ? "keyword"
+ : "plain");
+ s << "The uses of the " << sigString << " signature are here:\n";
+ typedef std::vector<std::pair<TLLSignature, cmListFileContext> > Container;
+ cmOutputConverter converter(this->GetMakefile()->GetStateSnapshot());
+ for(Container::const_iterator it = this->TLLCommands.begin();
+ it != this->TLLCommands.end(); ++it)
+ {
+ if (it->first == sig)
+ {
+ cmListFileContext lfc = it->second;
+ lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ s << " * " << lfc << std::endl;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AddLinkLibrary(cmMakefile& mf,
+ const std::string& target,
+ const std::string& lib,
+ LinkLibraryType llt)
+{
+ cmTarget *tgt = this->Makefile->FindTargetToUse(lib);
+ {
+ const bool isNonImportedTarget = tgt && !tgt->IsImported();
+
+ const std::string libName = (isNonImportedTarget && llt != GENERAL)
+ ? targetNameGenex(lib)
+ : lib;
+ this->AppendProperty("LINK_LIBRARIES",
+ this->GetDebugGeneratorExpressions(libName,
+ llt).c_str());
+ }
+
+ if (cmGeneratorExpression::Find(lib) != std::string::npos
+ || (tgt && tgt->GetType() == INTERFACE_LIBRARY)
+ || (target == lib ))
+ {
+ return;
+ }
+
+ cmTarget::LibraryID tmp;
+ tmp.first = lib;
+ tmp.second = llt;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LinkLibrariesForVS6.push_back( tmp );
+#endif
+ this->OriginalLinkLibraries.push_back(tmp);
+ this->ClearLinkMaps();
+
+ // Add the explicit dependency information for this target. This is
+ // simply a set of libraries separated by ";". There should always
+ // be a trailing ";". These library names are not canonical, in that
+ // they may be "-framework x", "-ly", "/path/libz.a", etc.
+ // We shouldn't remove duplicates here because external libraries
+ // may be purposefully duplicated to handle recursive dependencies,
+ // and we removing one instance will break the link line. Duplicates
+ // will be appropriately eliminated at emit time.
+ if(this->RecordDependencies)
+ {
+ std::string targetEntry = target;
+ targetEntry += "_LIB_DEPENDS";
+ std::string dependencies;
+ const char* old_val = mf.GetDefinition( targetEntry );
+ if( old_val )
+ {
+ dependencies += old_val;
+ }
+ switch (llt)
+ {
+ case cmTarget::GENERAL:
+ dependencies += "general";
+ break;
+ case cmTarget::DEBUG:
+ dependencies += "debug";
+ break;
+ case cmTarget::OPTIMIZED:
+ dependencies += "optimized";
+ break;
+ }
+ dependencies += ";";
+ dependencies += lib;
+ dependencies += ";";
+ mf.AddCacheDefinition( targetEntry, dependencies.c_str(),
+ "Dependencies for the target",
+ cmState::STATIC );
+ }
+
+}
+
+//----------------------------------------------------------------------------
+void
+cmTarget::AddSystemIncludeDirectories(const std::set<std::string> &incs)
+{
+ this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+}
+
+cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
+{
+ return cmMakeRange(this->Internal->IncludeDirectoriesEntries);
+}
+
+cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
+{
+ return cmMakeRange(this->Internal->IncludeDirectoriesBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileOptionsEntries() const
+{
+ return cmMakeRange(this->Internal->CompileOptionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
+{
+ return cmMakeRange(this->Internal->CompileOptionsBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileFeaturesEntries() const
+{
+ return cmMakeRange(this->Internal->CompileFeaturesEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
+{
+ return cmMakeRange(this->Internal->CompileFeaturesBacktraces);
+}
+
+cmStringRange cmTarget::GetCompileDefinitionsEntries() const
+{
+ return cmMakeRange(this->Internal->CompileDefinitionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
+{
+ return cmMakeRange(this->Internal->CompileDefinitionsBacktraces);
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+//----------------------------------------------------------------------------
+void
+cmTarget::AnalyzeLibDependenciesForVS6( const cmMakefile& mf )
+{
+ // There are two key parts of the dependency analysis: (1)
+ // determining the libraries in the link line, and (2) constructing
+ // the dependency graph for those libraries.
+ //
+ // The latter is done using the cache entries that record the
+ // dependencies of each library.
+ //
+ // The former is a more thorny issue, since it is not clear how to
+ // determine if two libraries listed on the link line refer to the a
+ // single library or not. For example, consider the link "libraries"
+ // /usr/lib/libtiff.so -ltiff
+ // Is this one library or two? The solution implemented here is the
+ // simplest (and probably the only practical) one: two libraries are
+ // the same if their "link strings" are identical. Thus, the two
+ // libraries above are considered distinct. This also means that for
+ // dependency analysis to be effective, the CMake user must specify
+ // libraries build by his project without using any linker flags or
+ // file extensions. That is,
+ // LINK_LIBRARIES( One Two )
+ // instead of
+ // LINK_LIBRARIES( -lOne ${binarypath}/libTwo.a )
+ // The former is probably what most users would do, but it never
+ // hurts to document the assumptions. :-) Therefore, in the analysis
+ // code, the "canonical name" of a library is simply its name as
+ // given to a LINK_LIBRARIES command.
+ //
+ // Also, we will leave the original link line intact; we will just add any
+ // dependencies that were missing.
+ //
+ // There is a problem with recursive external libraries
+ // (i.e. libraries with no dependency information that are
+ // recursively dependent). We must make sure that the we emit one of
+ // the libraries twice to satisfy the recursion, but we shouldn't
+ // emit it more times than necessary. In particular, we must make
+ // sure that handling this improbable case doesn't cost us when
+ // dealing with the common case of non-recursive libraries. The
+ // solution is to assume that the recursion is satisfied at one node
+ // of the dependency tree. To illustrate, assume libA and libB are
+ // extrenal and mutually dependent. Suppose libX depends on
+ // libA, and libY on libA and libX. Then
+ // TARGET_LINK_LIBRARIES( Y X A B A )
+ // TARGET_LINK_LIBRARIES( X A B A )
+ // TARGET_LINK_LIBRARIES( Exec Y )
+ // would result in "-lY -lX -lA -lB -lA". This is the correct way to
+ // specify the dependencies, since the mutual dependency of A and B
+ // is resolved *every time libA is specified*.
+ //
+ // Something like
+ // TARGET_LINK_LIBRARIES( Y X A B A )
+ // TARGET_LINK_LIBRARIES( X A B )
+ // TARGET_LINK_LIBRARIES( Exec Y )
+ // would result in "-lY -lX -lA -lB", and the mutual dependency
+ // information is lost. This is because in some case (Y), the mutual
+ // dependency of A and B is listed, while in another other case (X),
+ // it is not. Depending on which line actually emits A, the mutual
+ // dependency may or may not be on the final link line. We can't
+ // handle this pathalogical case cleanly without emitting extra
+ // libraries for the normal cases. Besides, the dependency
+ // information for X is wrong anyway: if we build an executable
+ // depending on X alone, we would not have the mutual dependency on
+ // A and B resolved.
+ //
+ // IMPROVEMENTS:
+ // -- The current algorithm will not always pick the "optimal" link line
+ // when recursive dependencies are present. It will instead break the
+ // cycles at an aribtrary point. The majority of projects won't have
+ // cyclic dependencies, so this is probably not a big deal. Note that
+ // the link line is always correct, just not necessary optimal.
+
+ {
+ // Expand variables in link library names. This is for backwards
+ // compatibility with very early CMake versions and should
+ // eventually be removed. This code was moved here from the end of
+ // old source list processing code which was called just before this
+ // method.
+ for(LinkLibraryVectorType::iterator p = this->LinkLibrariesForVS6.begin();
+ p != this->LinkLibrariesForVS6.end(); ++p)
+ {
+ this->Makefile->ExpandVariablesInString(p->first, true, true);
+ }
+ }
+
+ // The dependency map.
+ DependencyMap dep_map;
+
+ // 1. Build the dependency graph
+ //
+ for(LinkLibraryVectorType::reverse_iterator lib
+ = this->LinkLibrariesForVS6.rbegin();
+ lib != this->LinkLibrariesForVS6.rend(); ++lib)
+ {
+ this->GatherDependenciesForVS6( mf, *lib, dep_map);
+ }
+
+ // 2. Remove any dependencies that are already satisfied in the original
+ // link line.
+ //
+ for(LinkLibraryVectorType::iterator lib = this->LinkLibrariesForVS6.begin();
+ lib != this->LinkLibrariesForVS6.end(); ++lib)
+ {
+ for( LinkLibraryVectorType::iterator lib2 = lib;
+ lib2 != this->LinkLibrariesForVS6.end(); ++lib2)
+ {
+ this->DeleteDependencyForVS6( dep_map, *lib, *lib2);
+ }
+ }
+
+
+ // 3. Create the new link line by simply emitting any dependencies that are
+ // missing. Start from the back and keep adding.
+ //
+ std::set<DependencyMap::key_type> done, visited;
+ std::vector<DependencyMap::key_type> newLinkLibrariesForVS6;
+ for(LinkLibraryVectorType::reverse_iterator lib =
+ this->LinkLibrariesForVS6.rbegin();
+ lib != this->LinkLibrariesForVS6.rend(); ++lib)
+ {
+ // skip zero size library entries, this may happen
+ // if a variable expands to nothing.
+ if (!lib->first.empty())
+ {
+ this->EmitForVS6( *lib, dep_map, done, visited, newLinkLibrariesForVS6 );
+ }
+ }
+
+ // 4. Add the new libraries to the link line.
+ //
+ for( std::vector<DependencyMap::key_type>::reverse_iterator k =
+ newLinkLibrariesForVS6.rbegin();
+ k != newLinkLibrariesForVS6.rend(); ++k )
+ {
+ // get the llt from the dep_map
+ this->LinkLibrariesForVS6.push_back( std::make_pair(k->first,k->second) );
+ }
+ this->LinkLibrariesForVS6Analyzed = true;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::InsertDependencyForVS6( DependencyMap& depMap,
+ const LibraryID& lib,
+ const LibraryID& dep)
+{
+ depMap[lib].push_back(dep);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::DeleteDependencyForVS6( DependencyMap& depMap,
+ const LibraryID& lib,
+ const LibraryID& dep)
+{
+ // Make sure there is an entry in the map for lib. If so, delete all
+ // dependencies to dep. There may be repeated entries because of
+ // external libraries that are specified multiple times.
+ DependencyMap::iterator map_itr = depMap.find( lib );
+ if( map_itr != depMap.end() )
+ {
+ DependencyList& depList = map_itr->second;
+ DependencyList::iterator begin =
+ std::remove(depList.begin(), depList.end(), dep);
+ depList.erase(begin, depList.end());
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::EmitForVS6(const LibraryID lib,
+ const DependencyMap& dep_map,
+ std::set<LibraryID>& emitted,
+ std::set<LibraryID>& visited,
+ DependencyList& link_line )
+{
+ // It's already been emitted
+ if( emitted.find(lib) != emitted.end() )
+ {
+ return;
+ }
+
+ // Emit the dependencies only if this library node hasn't been
+ // visited before. If it has, then we have a cycle. The recursion
+ // that got us here should take care of everything.
+
+ if( visited.insert(lib).second )
+ {
+ if( dep_map.find(lib) != dep_map.end() ) // does it have dependencies?
+ {
+ const DependencyList& dep_on = dep_map.find( lib )->second;
+ DependencyList::const_reverse_iterator i;
+
+ // To cater for recursive external libraries, we must emit
+ // duplicates on this link line *unless* they were emitted by
+ // some other node, in which case we assume that the recursion
+ // was resolved then. We making the simplifying assumption that
+ // any duplicates on a single link line are on purpose, and must
+ // be preserved.
+
+ // This variable will keep track of the libraries that were
+ // emitted directly from the current node, and not from a
+ // recursive call. This way, if we come across a library that
+ // has already been emitted, we repeat it iff it has been
+ // emitted here.
+ std::set<DependencyMap::key_type> emitted_here;
+ for( i = dep_on.rbegin(); i != dep_on.rend(); ++i )
+ {
+ if( emitted_here.find(*i) != emitted_here.end() )
+ {
+ // a repeat. Must emit.
+ emitted.insert(*i);
+ link_line.push_back( *i );
+ }
+ else
+ {
+ // Emit only if no-one else has
+ if( emitted.find(*i) == emitted.end() )
+ {
+ // emit dependencies
+ this->EmitForVS6( *i, dep_map, emitted, visited, link_line );
+ // emit self
+ emitted.insert(*i);
+ emitted_here.insert(*i);
+ link_line.push_back( *i );
+ }
+ }
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GatherDependenciesForVS6( const cmMakefile& mf,
+ const LibraryID& lib,
+ DependencyMap& dep_map)
+{
+ // If the library is already in the dependency map, then it has
+ // already been fully processed.
+ if( dep_map.find(lib) != dep_map.end() )
+ {
+ return;
+ }
+
+ const char* deps = mf.GetDefinition( lib.first+"_LIB_DEPENDS" );
+ if( deps && strcmp(deps,"") != 0 )
+ {
+ // Make sure this library is in the map, even if it has an empty
+ // set of dependencies. This distinguishes the case of explicitly
+ // no dependencies with that of unspecified dependencies.
+ dep_map[lib];
+
+ // Parse the dependency information, which is a set of
+ // type, library pairs separated by ";". There is always a trailing ";".
+ cmTarget::LinkLibraryType llt = cmTarget::GENERAL;
+ std::string depline = deps;
+ std::string::size_type start = 0;
+ std::string::size_type end;
+ end = depline.find( ";", start );
+ while( end != std::string::npos )
+ {
+ std::string l = depline.substr( start, end-start );
+ if(!l.empty())
+ {
+ if (l == "debug")
+ {
+ llt = cmTarget::DEBUG;
+ }
+ else if (l == "optimized")
+ {
+ llt = cmTarget::OPTIMIZED;
+ }
+ else if (l == "general")
+ {
+ llt = cmTarget::GENERAL;
+ }
+ else
+ {
+ LibraryID lib2(l,llt);
+ this->InsertDependencyForVS6( dep_map, lib, lib2);
+ this->GatherDependenciesForVS6( mf, lib2, dep_map);
+ llt = cmTarget::GENERAL;
+ }
+ }
+ start = end+1; // skip the ;
+ end = depline.find( ";", start );
+ }
+ // cannot depend on itself
+ this->DeleteDependencyForVS6( dep_map, lib, lib);
+ }
+}
+#endif
+
+//----------------------------------------------------------------------------
+static bool whiteListedInterfaceProperty(const std::string& prop)
+{
+ if(cmHasLiteralPrefix(prop, "INTERFACE_"))
+ {
+ return true;
+ }
+ static UNORDERED_SET<std::string> builtIns;
+ if (builtIns.empty())
+ {
+ builtIns.insert("COMPATIBLE_INTERFACE_BOOL");
+ builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MAX");
+ builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MIN");
+ builtIns.insert("COMPATIBLE_INTERFACE_STRING");
+ builtIns.insert("EXPORT_NAME");
+ builtIns.insert("IMPORTED");
+ builtIns.insert("NAME");
+ builtIns.insert("TYPE");
+ }
+
+ if (builtIns.count(prop))
+ {
+ return true;
+ }
+
+ if (cmHasLiteralPrefix(prop, "MAP_IMPORTED_CONFIG_"))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::SetProperty(const std::string& prop, const char* value)
+{
+ if (this->GetType() == INTERFACE_LIBRARY
+ && !whiteListedInterfaceProperty(prop))
+ {
+ std::ostringstream e;
+ e << "INTERFACE_LIBRARY targets may only have whitelisted properties. "
+ "The property \"" << prop << "\" is not allowed.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ else if (prop == "NAME")
+ {
+ std::ostringstream e;
+ e << "NAME property is read-only\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ else if(prop == "INCLUDE_DIRECTORIES")
+ {
+ this->Internal->IncludeDirectoriesEntries.clear();
+ this->Internal->IncludeDirectoriesBacktraces.clear();
+ if (value)
+ {
+ this->Internal->IncludeDirectoriesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "COMPILE_OPTIONS")
+ {
+ this->Internal->CompileOptionsEntries.clear();
+ this->Internal->CompileOptionsBacktraces.clear();
+ if (value)
+ {
+ this->Internal->CompileOptionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "COMPILE_FEATURES")
+ {
+ this->Internal->CompileFeaturesEntries.clear();
+ this->Internal->CompileFeaturesBacktraces.clear();
+ if (value)
+ {
+ this->Internal->CompileFeaturesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "COMPILE_DEFINITIONS")
+ {
+ this->Internal->CompileDefinitionsEntries.clear();
+ this->Internal->CompileDefinitionsBacktraces.clear();
+ if (value)
+ {
+ this->Internal->CompileDefinitionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "EXPORT_NAME" && this->IsImported())
+ {
+ std::ostringstream e;
+ e << "EXPORT_NAME property can't be set on imported targets (\""
+ << this->Name << "\")\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ else if (prop == "LINK_LIBRARIES")
+ {
+ this->Internal->LinkImplementationPropertyEntries.clear();
+ if (value)
+ {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmValueWithOrigin entry(value, lfbt);
+ this->Internal->LinkImplementationPropertyEntries.push_back(entry);
+ }
+ }
+ else if (prop == "SOURCES")
+ {
+ if(this->IsImported())
+ {
+ std::ostringstream e;
+ e << "SOURCES property can't be set on imported targets (\""
+ << this->Name << "\")\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ this->Internal->SourceFilesMap.clear();
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ cmDeleteAll(this->Internal->SourceEntries);
+ this->Internal->SourceEntries.clear();
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+ this->Internal->SourceEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+ else
+ {
+ this->Properties.SetProperty(prop, value);
+ this->MaybeInvalidatePropertyCache(prop);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AppendProperty(const std::string& prop, const char* value,
+ bool asString)
+{
+ if (this->GetType() == INTERFACE_LIBRARY
+ && !whiteListedInterfaceProperty(prop))
+ {
+ std::ostringstream e;
+ e << "INTERFACE_LIBRARY targets may only have whitelisted properties. "
+ "The property \"" << prop << "\" is not allowed.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ else if (prop == "NAME")
+ {
+ std::ostringstream e;
+ e << "NAME property is read-only\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ else if(prop == "INCLUDE_DIRECTORIES")
+ {
+ if (value && *value)
+ {
+ this->Internal->IncludeDirectoriesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "COMPILE_OPTIONS")
+ {
+ if (value && *value)
+ {
+ this->Internal->CompileOptionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "COMPILE_FEATURES")
+ {
+ if (value && *value)
+ {
+ this->Internal->CompileFeaturesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "COMPILE_DEFINITIONS")
+ {
+ if (value && *value)
+ {
+ this->Internal->CompileDefinitionsEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ }
+ }
+ else if(prop == "EXPORT_NAME" && this->IsImported())
+ {
+ std::ostringstream e;
+ e << "EXPORT_NAME property can't be set on imported targets (\""
+ << this->Name << "\")\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ else if (prop == "LINK_LIBRARIES")
+ {
+ if (value && *value)
+ {
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmValueWithOrigin entry(value, lfbt);
+ this->Internal->LinkImplementationPropertyEntries.push_back(entry);
+ }
+ }
+ else if (prop == "SOURCES")
+ {
+ if(this->IsImported())
+ {
+ std::ostringstream e;
+ e << "SOURCES property can't be set on imported targets (\""
+ << this->Name << "\")\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ this->Internal->SourceFilesMap.clear();
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+ this->Internal->SourceEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+ else
+ {
+ this->Properties.AppendProperty(prop, value, asString);
+ this->MaybeInvalidatePropertyCache(prop);
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetExportName() const
+{
+ const char *exportName = this->GetProperty("EXPORT_NAME");
+
+ if (exportName && *exportName)
+ {
+ if (!cmGeneratorExpression::IsValidTargetName(exportName))
+ {
+ std::ostringstream e;
+ e << "EXPORT_NAME property \"" << exportName << "\" for \""
+ << this->GetName() << "\": is not valid.";
+ cmSystemTools::Error(e.str().c_str());
+ return "";
+ }
+ return exportName;
+ }
+ return this->GetName();
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AppendBuildInterfaceIncludes()
+{
+ if(this->GetType() != cmTarget::SHARED_LIBRARY &&
+ this->GetType() != cmTarget::STATIC_LIBRARY &&
+ this->GetType() != cmTarget::MODULE_LIBRARY &&
+ this->GetType() != cmTarget::INTERFACE_LIBRARY &&
+ !this->IsExecutableWithExports())
+ {
+ return;
+ }
+ if (this->BuildInterfaceIncludesAppended)
+ {
+ return;
+ }
+ this->BuildInterfaceIncludesAppended = true;
+
+ if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE"))
+ {
+ const char *binDir = this->Makefile->GetCurrentBinaryDirectory();
+ const char *srcDir = this->Makefile->GetCurrentSourceDirectory();
+ const std::string dirs = std::string(binDir ? binDir : "")
+ + std::string(binDir ? ";" : "")
+ + std::string(srcDir ? srcDir : "");
+ if (!dirs.empty())
+ {
+ this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+ ("$<BUILD_INTERFACE:" + dirs + ">").c_str());
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::InsertInclude(std::string const& entry,
+ cmListFileBacktrace const& bt,
+ bool before)
+{
+ std::vector<std::string>::iterator position =
+ before ? this->Internal->IncludeDirectoriesEntries.begin()
+ : this->Internal->IncludeDirectoriesEntries.end();
+
+ std::vector<cmListFileBacktrace>::iterator btPosition =
+ before ? this->Internal->IncludeDirectoriesBacktraces.begin()
+ : this->Internal->IncludeDirectoriesBacktraces.end();
+
+ this->Internal->IncludeDirectoriesEntries.insert(position, entry);
+ this->Internal->IncludeDirectoriesBacktraces.insert(btPosition, bt);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::InsertCompileOption(std::string const& entry,
+ cmListFileBacktrace const& bt,
+ bool before)
+{
+ std::vector<std::string>::iterator position =
+ before ? this->Internal->CompileOptionsEntries.begin()
+ : this->Internal->CompileOptionsEntries.end();
+
+ std::vector<cmListFileBacktrace>::iterator btPosition =
+ before ? this->Internal->CompileOptionsBacktraces.begin()
+ : this->Internal->CompileOptionsBacktraces.end();
+
+ this->Internal->CompileOptionsEntries.insert(position, entry);
+ this->Internal->CompileOptionsBacktraces.insert(btPosition, bt);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::InsertCompileDefinition(std::string const& entry,
+ cmListFileBacktrace const& bt)
+{
+ this->Internal->CompileDefinitionsEntries.push_back(entry);
+ this->Internal->CompileDefinitionsBacktraces.push_back(bt);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::MaybeInvalidatePropertyCache(const std::string& prop)
+{
+ // Wipe out maps caching information affected by this property.
+ if(this->IsImported() && cmHasLiteralPrefix(prop, "IMPORTED"))
+ {
+ this->Internal->ImportInfoMap.clear();
+ }
+ if(!this->IsImported() && cmHasLiteralPrefix(prop, "LINK_INTERFACE_"))
+ {
+ this->ClearLinkMaps();
+ }
+}
+
+//----------------------------------------------------------------------------
+static void cmTargetCheckLINK_INTERFACE_LIBRARIES(
+ const std::string& prop, const char* value, cmMakefile* context,
+ bool imported)
+{
+ // Look for link-type keywords in the value.
+ static cmsys::RegularExpression
+ keys("(^|;)(debug|optimized|general)(;|$)");
+ if(!keys.find(value))
+ {
+ return;
+ }
+
+ // Support imported and non-imported versions of the property.
+ const char* base = (imported?
+ "IMPORTED_LINK_INTERFACE_LIBRARIES" :
+ "LINK_INTERFACE_LIBRARIES");
+
+ // Report an error.
+ std::ostringstream e;
+ e << "Property " << prop << " may not contain link-type keyword \""
+ << keys.match(2) << "\". "
+ << "The " << base << " property has a per-configuration "
+ << "version called " << base << "_<CONFIG> which may be "
+ << "used to specify per-configuration rules.";
+ if(!imported)
+ {
+ e << " "
+ << "Alternatively, an IMPORTED library may be created, configured "
+ << "with a per-configuration location, and then named in the "
+ << "property value. "
+ << "See the add_library command's IMPORTED mode for details."
+ << "\n"
+ << "If you have a list of libraries that already contains the "
+ << "keyword, use the target_link_libraries command with its "
+ << "LINK_INTERFACE_LIBRARIES mode to set the property. "
+ << "The command automatically recognizes link-type keywords and sets "
+ << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG "
+ << "properties accordingly.";
+ }
+ context->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+//----------------------------------------------------------------------------
+static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value,
+ cmMakefile* context)
+{
+ // Look for link-type keywords in the value.
+ static cmsys::RegularExpression
+ keys("(^|;)(debug|optimized|general)(;|$)");
+ if(!keys.find(value))
+ {
+ return;
+ }
+
+ // Report an error.
+ std::ostringstream e;
+
+ e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type "
+ "keyword \"" << keys.match(2) << "\". The INTERFACE_LINK_LIBRARIES "
+ "property may contain configuration-sensitive generator-expressions "
+ "which may be used to specify per-configuration rules.";
+
+ context->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::CheckProperty(const std::string& prop,
+ cmMakefile* context) const
+{
+ // Certain properties need checking.
+ if(cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES"))
+ {
+ if(const char* value = this->GetProperty(prop))
+ {
+ cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, false);
+ }
+ }
+ if(cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES"))
+ {
+ if(const char* value = this->GetProperty(prop))
+ {
+ cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, true);
+ }
+ }
+ if(cmHasLiteralPrefix(prop, "INTERFACE_LINK_LIBRARIES"))
+ {
+ if(const char* value = this->GetProperty(prop))
+ {
+ cmTargetCheckINTERFACE_LINK_LIBRARIES(value, context);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::MarkAsImported()
+{
+ this->IsImportedTarget = true;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HaveWellDefinedOutputFiles() const
+{
+ return
+ this->GetType() == cmTarget::STATIC_LIBRARY ||
+ this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY ||
+ this->GetType() == cmTarget::EXECUTABLE;
+}
+
+//----------------------------------------------------------------------------
+cmTarget::OutputInfo const* cmTarget::GetOutputInfo(
+ const std::string& config) const
+{
+ // There is no output information for imported targets.
+ if(this->IsImported())
+ {
+ return 0;
+ }
+
+ // Only libraries and executables have well-defined output files.
+ if(!this->HaveWellDefinedOutputFiles())
+ {
+ std::string msg = "cmTarget::GetOutputInfo called for ";
+ msg += this->GetName();
+ msg += " which has type ";
+ msg += cmTarget::GetTargetTypeName(this->GetType());
+ this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ return 0;
+ }
+
+ // Lookup/compute/cache the output information for this configuration.
+ std::string config_upper;
+ if(!config.empty())
+ {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ typedef cmTargetInternals::OutputInfoMapType OutputInfoMapType;
+ OutputInfoMapType::iterator i =
+ this->Internal->OutputInfoMap.find(config_upper);
+ if(i == this->Internal->OutputInfoMap.end())
+ {
+ // Add empty info in map to detect potential recursion.
+ OutputInfo info;
+ OutputInfoMapType::value_type entry(config_upper, info);
+ i = this->Internal->OutputInfoMap.insert(entry).first;
+
+ // Compute output directories.
+ this->ComputeOutputDir(config, false, info.OutDir);
+ this->ComputeOutputDir(config, true, info.ImpDir);
+ if(!this->ComputePDBOutputDir("PDB", config, info.PdbDir))
+ {
+ info.PdbDir = info.OutDir;
+ }
+
+ // Now update the previously-prepared map entry.
+ i->second = info;
+ }
+ else if(i->second.empty())
+ {
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
+ this->GetBacktrace());
+ return 0;
+ }
+ return &i->second;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetDirectory(const std::string& config,
+ bool implib) const
+{
+ if (this->IsImported())
+ {
+ // Return the directory from which the target is imported.
+ return
+ cmSystemTools::GetFilenamePath(
+ this->ImportedGetFullPath(config, implib));
+ }
+ else if(OutputInfo const* info = this->GetOutputInfo(config))
+ {
+ // Return the directory in which the target will be built.
+ return implib? info->ImpDir : info->OutDir;
+ }
+ return "";
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetPDBDirectory(const std::string& config) const
+{
+ if(OutputInfo const* info = this->GetOutputInfo(config))
+ {
+ // Return the directory in which the target will be built.
+ return info->PdbDir;
+ }
+ return "";
+}
+
+//----------------------------------------------------------------------------
+const char* cmTarget::ImportedGetLocation(const std::string& config) const
+{
+ static std::string location;
+ assert(this->IsImported());
+ location = this->ImportedGetFullPath(config, false);
+ return location.c_str();
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetTargetVersion(int& major, int& minor) const
+{
+ int patch;
+ this->GetTargetVersion(false, major, minor, patch);
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetTargetVersion(bool soversion,
+ int& major, int& minor, int& patch) const
+{
+ // Set the default values.
+ major = 0;
+ minor = 0;
+ patch = 0;
+
+ assert(this->GetType() != INTERFACE_LIBRARY);
+
+ // Look for a VERSION or SOVERSION property.
+ const char* prop = soversion? "SOVERSION" : "VERSION";
+ if(const char* version = this->GetProperty(prop))
+ {
+ // Try to parse the version number and store the results that were
+ // successfully parsed.
+ int parsed_major;
+ int parsed_minor;
+ int parsed_patch;
+ switch(sscanf(version, "%d.%d.%d",
+ &parsed_major, &parsed_minor, &parsed_patch))
+ {
+ case 3: patch = parsed_patch; // no break!
+ case 2: minor = parsed_minor; // no break!
+ case 1: major = parsed_major; // no break!
+ default: break;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HandleLocationPropertyPolicy(cmMakefile* context) const
+{
+ if (this->IsImported())
+ {
+ return true;
+ }
+ std::ostringstream e;
+ const char *modal = 0;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch (context->GetPolicyStatus(cmPolicies::CMP0026))
+ {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0026) << "\n";
+ modal = "should";
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ modal = "may";
+ messageType = cmake::FATAL_ERROR;
+ }
+
+ if (modal)
+ {
+ e << "The LOCATION property " << modal << " not be read from target \""
+ << this->GetName() << "\". Use the target name directly with "
+ "add_custom_command, or use the generator expression $<TARGET_FILE>, "
+ "as appropriate.\n";
+ context->IssueMessage(messageType, e.str());
+ }
+
+ return messageType != cmake::FATAL_ERROR;
+}
+
+//----------------------------------------------------------------------------
+const char *cmTarget::GetProperty(const std::string& prop) const
+{
+ return this->GetProperty(prop, this->Makefile);
+}
+
+//----------------------------------------------------------------------------
+const char *cmTarget::GetProperty(const std::string& prop,
+ cmMakefile* context) const
+{
+ if (this->GetType() == INTERFACE_LIBRARY
+ && !whiteListedInterfaceProperty(prop))
+ {
+ std::ostringstream e;
+ e << "INTERFACE_LIBRARY targets may only have whitelisted properties. "
+ "The property \"" << prop << "\" is not allowed.";
+ context->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return 0;
+ }
+
+ // Watch for special "computed" properties that are dependent on
+ // other properties or variables. Always recompute them.
+ if(this->GetType() == cmTarget::EXECUTABLE ||
+ this->GetType() == cmTarget::STATIC_LIBRARY ||
+ this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY ||
+ this->GetType() == cmTarget::UNKNOWN_LIBRARY)
+ {
+ static const std::string propLOCATION = "LOCATION";
+ if(prop == propLOCATION)
+ {
+ if (!this->HandleLocationPropertyPolicy(context))
+ {
+ return 0;
+ }
+
+ // Set the LOCATION property of the target.
+ //
+ // For an imported target this is the location of an arbitrary
+ // available configuration.
+ //
+ if(this->IsImported())
+ {
+ this->Properties.SetProperty(
+ propLOCATION, this->ImportedGetFullPath("", false).c_str());
+ }
+ else
+ {
+ // For a non-imported target this is deprecated because it
+ // cannot take into account the per-configuration name of the
+ // target because the configuration type may not be known at
+ // CMake time.
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ gg->CreateGenerationObjects();
+ cmGeneratorTarget* gt = gg->GetGeneratorTarget(this);
+ this->Properties.SetProperty(propLOCATION,
+ gt->GetLocationForBuild());
+ }
+
+ }
+
+ // Support "LOCATION_<CONFIG>".
+ else if(cmHasLiteralPrefix(prop, "LOCATION_"))
+ {
+ if (!this->HandleLocationPropertyPolicy(context))
+ {
+ return 0;
+ }
+ const char* configName = prop.c_str() + 9;
+
+ if (this->IsImported())
+ {
+ this->Properties.SetProperty(
+ prop, this->ImportedGetFullPath(configName, false).c_str());
+ }
+ else
+ {
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ gg->CreateGenerationObjects();
+ cmGeneratorTarget* gt = gg->GetGeneratorTarget(this);
+ this->Properties.SetProperty(
+ prop, gt->GetFullPath(configName, false).c_str());
+ }
+ }
+ // Support "<CONFIG>_LOCATION".
+ else if(cmHasLiteralSuffix(prop, "_LOCATION"))
+ {
+ std::string configName(prop.c_str(), prop.size() - 9);
+ if(configName != "IMPORTED")
+ {
+ if (!this->HandleLocationPropertyPolicy(context))
+ {
+ return 0;
+ }
+ if (this->IsImported())
+ {
+ this->Properties.SetProperty(
+ prop, this->ImportedGetFullPath(configName, false).c_str());
+ }
+ else
+ {
+ cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ gg->CreateGenerationObjects();
+ cmGeneratorTarget* gt = gg->GetGeneratorTarget(this);
+ this->Properties.SetProperty(
+ prop, gt->GetFullPath(configName, false).c_str());
+ }
+ }
+ }
+ }
+ static UNORDERED_SET<std::string> specialProps;
+#define MAKE_STATIC_PROP(PROP) \
+ static const std::string prop##PROP = #PROP
+ MAKE_STATIC_PROP(LINK_LIBRARIES);
+ MAKE_STATIC_PROP(TYPE);
+ MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
+ MAKE_STATIC_PROP(COMPILE_FEATURES);
+ MAKE_STATIC_PROP(COMPILE_OPTIONS);
+ MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
+ MAKE_STATIC_PROP(IMPORTED);
+ MAKE_STATIC_PROP(NAME);
+ MAKE_STATIC_PROP(BINARY_DIR);
+ MAKE_STATIC_PROP(SOURCE_DIR);
+ MAKE_STATIC_PROP(SOURCES);
+#undef MAKE_STATIC_PROP
+ if(specialProps.empty())
+ {
+ specialProps.insert(propLINK_LIBRARIES);
+ specialProps.insert(propTYPE);
+ specialProps.insert(propINCLUDE_DIRECTORIES);
+ specialProps.insert(propCOMPILE_FEATURES);
+ specialProps.insert(propCOMPILE_OPTIONS);
+ specialProps.insert(propCOMPILE_DEFINITIONS);
+ specialProps.insert(propIMPORTED);
+ specialProps.insert(propNAME);
+ specialProps.insert(propBINARY_DIR);
+ specialProps.insert(propSOURCE_DIR);
+ specialProps.insert(propSOURCES);
+ }
+ if(specialProps.count(prop))
+ {
+ if(prop == propLINK_LIBRARIES)
+ {
+ if (this->Internal->LinkImplementationPropertyEntries.empty())
+ {
+ return 0;
+ }
+
+ static std::string output;
+ output = "";
+ std::string sep;
+ for (std::vector<cmValueWithOrigin>::const_iterator
+ it = this->Internal->LinkImplementationPropertyEntries.begin(),
+ end = this->Internal->LinkImplementationPropertyEntries.end();
+ it != end; ++it)
+ {
+ output += sep;
+ output += it->Value;
+ sep = ";";
+ }
+ return output.c_str();
+ }
+ // the type property returns what type the target is
+ else if (prop == propTYPE)
+ {
+ return cmTarget::GetTargetTypeName(this->GetType());
+ }
+ else if(prop == propINCLUDE_DIRECTORIES)
+ {
+ if (this->Internal->IncludeDirectoriesEntries.empty())
+ {
+ return 0;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";");
+ return output.c_str();
+ }
+ else if(prop == propCOMPILE_FEATURES)
+ {
+ if (this->Internal->CompileFeaturesEntries.empty())
+ {
+ return 0;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->CompileFeaturesEntries, ";");
+ return output.c_str();
+ }
+ else if(prop == propCOMPILE_OPTIONS)
+ {
+ if (this->Internal->CompileOptionsEntries.empty())
+ {
+ return 0;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->CompileOptionsEntries, ";");
+ return output.c_str();
+ }
+ else if(prop == propCOMPILE_DEFINITIONS)
+ {
+ if (this->Internal->CompileDefinitionsEntries.empty())
+ {
+ return 0;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
+ return output.c_str();
+ }
+ else if (prop == propIMPORTED)
+ {
+ return this->IsImported()?"TRUE":"FALSE";
+ }
+ else if (prop == propNAME)
+ {
+ return this->GetName().c_str();
+ }
+ else if (prop == propBINARY_DIR)
+ {
+ return this->GetMakefile()->GetCurrentBinaryDirectory();
+ }
+ else if (prop == propSOURCE_DIR)
+ {
+ return this->GetMakefile()->GetCurrentSourceDirectory();
+ }
+ else if(prop == propSOURCES)
+ {
+ if (this->Internal->SourceEntries.empty())
+ {
+ return 0;
+ }
+
+ std::ostringstream ss;
+ const char* sep = "";
+ typedef cmTargetInternals::TargetPropertyEntry
+ TargetPropertyEntry;
+ for(std::vector<TargetPropertyEntry*>::const_iterator
+ i = this->Internal->SourceEntries.begin();
+ i != this->Internal->SourceEntries.end(); ++i)
+ {
+ std::string entry = (*i)->ge->GetInput();
+
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(entry, files);
+ for (std::vector<std::string>::const_iterator
+ li = files.begin(); li != files.end(); ++li)
+ {
+ if(cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+ (*li)[li->size() - 1] == '>')
+ {
+ std::string objLibName = li->substr(17, li->size()-18);
+
+ if (cmGeneratorExpression::Find(objLibName) != std::string::npos)
+ {
+ ss << sep;
+ sep = ";";
+ ss << *li;
+ continue;
+ }
+
+ bool addContent = false;
+ bool noMessage = true;
+ std::ostringstream e;
+ cmake::MessageType messageType = cmake::AUTHOR_WARNING;
+ switch(context->GetPolicyStatus(cmPolicies::CMP0051))
+ {
+ case cmPolicies::WARN:
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
+ noMessage = false;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ addContent = true;
+ }
+ if (!noMessage)
+ {
+ e << "Target \"" << this->Name << "\" contains "
+ "$<TARGET_OBJECTS> generator expression in its sources list. "
+ "This content was not previously part of the SOURCES property "
+ "when that property was read at configure time. Code reading "
+ "that property needs to be adapted to ignore the generator "
+ "expression using the string(GENEX_STRIP) command.";
+ context->IssueMessage(messageType, e.str());
+ }
+ if (addContent)
+ {
+ ss << sep;
+ sep = ";";
+ ss << *li;
+ }
+ }
+ else if (cmGeneratorExpression::Find(*li) == std::string::npos)
+ {
+ ss << sep;
+ sep = ";";
+ ss << *li;
+ }
+ else
+ {
+ cmSourceFile *sf = this->Makefile->GetOrCreateSource(*li);
+ // Construct what is known about this source file location.
+ cmSourceFileLocation const& location = sf->GetLocation();
+ std::string sname = location.GetDirectory();
+ if(!sname.empty())
+ {
+ sname += "/";
+ }
+ sname += location.GetName();
+
+ ss << sep;
+ sep = ";";
+ // Append this list entry.
+ ss << sname;
+ }
+ }
+ }
+ this->Properties.SetProperty("SOURCES", ss.str().c_str());
+ }
+ }
+
+ const char *retVal = this->Properties.GetPropertyValue(prop);
+ if (!retVal)
+ {
+ const bool chain = this->GetMakefile()->GetState()->
+ IsPropertyChained(prop, cmProperty::TARGET);
+ if (chain)
+ {
+ return this->Makefile->GetProperty(prop, chain);
+ }
+ }
+ return retVal;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::GetPropertyAsBool(const std::string& prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+//----------------------------------------------------------------------------
+const char* cmTarget::GetSuffixVariableInternal(bool implib) const
+{
+ switch(this->GetType())
+ {
+ case cmTarget::STATIC_LIBRARY:
+ return "CMAKE_STATIC_LIBRARY_SUFFIX";
+ case cmTarget::SHARED_LIBRARY:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_SUFFIX"
+ : "CMAKE_SHARED_LIBRARY_SUFFIX");
+ case cmTarget::MODULE_LIBRARY:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_SUFFIX"
+ : "CMAKE_SHARED_MODULE_SUFFIX");
+ case cmTarget::EXECUTABLE:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_SUFFIX"
+ // Android GUI application packages store the native
+ // binary as a shared library.
+ : (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")?
+ "CMAKE_SHARED_LIBRARY_SUFFIX" : "CMAKE_EXECUTABLE_SUFFIX"));
+ default:
+ break;
+ }
+ return "";
+}
+
+
+//----------------------------------------------------------------------------
+const char* cmTarget::GetPrefixVariableInternal(bool implib) const
+{
+ switch(this->GetType())
+ {
+ case cmTarget::STATIC_LIBRARY:
+ return "CMAKE_STATIC_LIBRARY_PREFIX";
+ case cmTarget::SHARED_LIBRARY:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_PREFIX"
+ : "CMAKE_SHARED_LIBRARY_PREFIX");
+ case cmTarget::MODULE_LIBRARY:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_PREFIX"
+ : "CMAKE_SHARED_MODULE_PREFIX");
+ case cmTarget::EXECUTABLE:
+ return (implib
+ ? "CMAKE_IMPORT_LIBRARY_PREFIX"
+ // Android GUI application packages store the native
+ // binary as a shared library.
+ : (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")?
+ "CMAKE_SHARED_LIBRARY_PREFIX" : ""));
+ default:
+ break;
+ }
+ return "";
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HasMacOSXRpathInstallNameDir(const std::string& config) const
+{
+ bool install_name_is_rpath = false;
+ bool macosx_rpath = false;
+
+ if(!this->IsImportedTarget)
+ {
+ if(this->GetType() != cmTarget::SHARED_LIBRARY)
+ {
+ return false;
+ }
+ const char* install_name = this->GetProperty("INSTALL_NAME_DIR");
+ bool use_install_name =
+ this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
+ if(install_name && use_install_name &&
+ std::string(install_name) == "@rpath")
+ {
+ install_name_is_rpath = true;
+ }
+ else if(install_name && use_install_name)
+ {
+ return false;
+ }
+ if(!install_name_is_rpath)
+ {
+ macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
+ }
+ }
+ else
+ {
+ // Lookup the imported soname.
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+ {
+ if(!info->NoSOName && !info->SOName.empty())
+ {
+ if(info->SOName.find("@rpath/") == 0)
+ {
+ install_name_is_rpath = true;
+ }
+ }
+ else
+ {
+ std::string install_name;
+ cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
+ if(install_name.find("@rpath") != std::string::npos)
+ {
+ install_name_is_rpath = true;
+ }
+ }
+ }
+ }
+
+ if(!install_name_is_rpath && !macosx_rpath)
+ {
+ return false;
+ }
+
+ if(!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG"))
+ {
+ std::ostringstream w;
+ w << "Attempting to use";
+ if(macosx_rpath)
+ {
+ w << " MACOSX_RPATH";
+ }
+ else
+ {
+ w << " @rpath";
+ }
+ w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
+ w << " This could be because you are using a Mac OS X version";
+ w << " less than 10.5 or because CMake's platform configuration is";
+ w << " corrupt.";
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, w.str(), this->GetBacktrace());
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::MacOSXRpathInstallNameDirDefault() const
+{
+ // we can't do rpaths when unsupported
+ if(!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG"))
+ {
+ return false;
+ }
+
+ const char* macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
+ if(macosx_rpath_str)
+ {
+ return this->GetPropertyAsBool("MACOSX_RPATH");
+ }
+
+ cmPolicies::PolicyStatus cmp0042 = this->GetPolicyStatusCMP0042();
+
+ if(cmp0042 == cmPolicies::WARN)
+ {
+ this->Makefile->GetGlobalGenerator()->
+ AddCMP0042WarnTarget(this->GetName());
+ }
+
+ if(cmp0042 == cmPolicies::NEW)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsImportedSharedLibWithoutSOName(
+ const std::string& config) const
+{
+ if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
+ {
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+ {
+ return info->NoSOName;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmTarget::GetFullNameImported(const std::string& config, bool implib) const
+{
+ return cmSystemTools::GetFilenameName(
+ this->ImportedGetFullPath(config, implib));
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmTarget::ImportedGetFullPath(const std::string& config, bool implib) const
+{
+ std::string result;
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+ {
+ result = implib? info->ImportLibrary : info->Location;
+ }
+ if(result.empty())
+ {
+ result = this->GetName();
+ result += "-NOTFOUND";
+ }
+ return result;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::ComputeVersionedName(std::string& vName,
+ std::string const& prefix,
+ std::string const& base,
+ std::string const& suffix,
+ std::string const& name,
+ const char* version) const
+{
+ vName = this->IsApple? (prefix+base) : name;
+ if(version)
+ {
+ vName += ".";
+ vName += version;
+ }
+ vName += this->IsApple? suffix : std::string();
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HasImplibGNUtoMS() const
+{
+ return this->HasImportLibrary() && this->GetPropertyAsBool("GNUtoMS");
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::GetImplibGNUtoMS(std::string const& gnuName,
+ std::string& out, const char* newExt) const
+{
+ if(this->HasImplibGNUtoMS() &&
+ gnuName.size() > 6 && gnuName.substr(gnuName.size()-6) == ".dll.a")
+ {
+ out = gnuName.substr(0, gnuName.size()-6);
+ out += newExt? newExt : ".lib";
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::SetPropertyDefault(const std::string& property,
+ const char* default_value)
+{
+ // Compute the name of the variable holding the default value.
+ std::string var = "CMAKE_";
+ var += property;
+
+ if(const char* value = this->Makefile->GetDefinition(var))
+ {
+ this->SetProperty(property, value);
+ }
+ else if(default_value)
+ {
+ this->SetProperty(property, default_value);
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HaveInstallTreeRPATH() const
+{
+ const char* install_rpath = this->GetProperty("INSTALL_RPATH");
+ return (install_rpath && *install_rpath) &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
+}
+
+//----------------------------------------------------------------------------
+const char* cmTarget::GetOutputTargetType(bool implib) const
+{
+ switch(this->GetType())
+ {
+ case cmTarget::SHARED_LIBRARY:
+ if(this->DLLPlatform)
+ {
+ if(implib)
+ {
+ // A DLL import library is treated as an archive target.
+ return "ARCHIVE";
+ }
+ else
+ {
+ // A DLL shared library is treated as a runtime target.
+ return "RUNTIME";
+ }
+ }
+ else
+ {
+ // For non-DLL platforms shared libraries are treated as
+ // library targets.
+ return "LIBRARY";
+ }
+ case cmTarget::STATIC_LIBRARY:
+ // Static libraries are always treated as archive targets.
+ return "ARCHIVE";
+ case cmTarget::MODULE_LIBRARY:
+ if(implib)
+ {
+ // Module libraries are always treated as library targets.
+ return "ARCHIVE";
+ }
+ else
+ {
+ // Module import libraries are treated as archive targets.
+ return "LIBRARY";
+ }
+ case cmTarget::EXECUTABLE:
+ if(implib)
+ {
+ // Executable import libraries are treated as archive targets.
+ return "ARCHIVE";
+ }
+ else
+ {
+ // Executables are always treated as runtime targets.
+ return "RUNTIME";
+ }
+ default:
+ break;
+ }
+ return "";
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::ComputeOutputDir(const std::string& config,
+ bool implib, std::string& out) const
+{
+ bool usesDefaultOutputDir = false;
+ std::string conf = config;
+
+ // Look for a target property defining the target output directory
+ // based on the target type.
+ std::string targetTypeName = this->GetOutputTargetType(implib);
+ const char* propertyName = 0;
+ std::string propertyNameStr = targetTypeName;
+ if(!propertyNameStr.empty())
+ {
+ propertyNameStr += "_OUTPUT_DIRECTORY";
+ propertyName = propertyNameStr.c_str();
+ }
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(conf);
+ const char* configProp = 0;
+ std::string configPropStr = targetTypeName;
+ if(!configPropStr.empty())
+ {
+ configPropStr += "_OUTPUT_DIRECTORY_";
+ configPropStr += configUpper;
+ configProp = configPropStr.c_str();
+ }
+
+ // Select an output directory.
+ if(const char* config_outdir = this->GetProperty(configProp))
+ {
+ // Use the user-specified per-configuration output directory.
+ cmGeneratorExpression ge;
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(config_outdir);
+ out = cge->Evaluate(this->Makefile, config);
+
+ // Skip per-configuration subdirectory.
+ conf = "";
+ }
+ else if(const char* outdir = this->GetProperty(propertyName))
+ {
+ // Use the user-specified output directory.
+ cmGeneratorExpression ge;
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(outdir);
+ out = cge->Evaluate(this->Makefile, config);
+
+ // Skip per-configuration subdirectory if the value contained a
+ // generator expression.
+ if (out != outdir)
+ {
+ conf = "";
+ }
+ }
+ else if(this->GetType() == cmTarget::EXECUTABLE)
+ {
+ // Lookup the output path for executables.
+ out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
+ }
+ else if(this->GetType() == cmTarget::STATIC_LIBRARY ||
+ this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY)
+ {
+ // Lookup the output path for libraries.
+ out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
+ }
+ if(out.empty())
+ {
+ // Default to the current output directory.
+ usesDefaultOutputDir = true;
+ out = ".";
+ }
+
+ // Convert the output path to a full path in case it is
+ // specified as a relative path. Treat a relative path as
+ // relative to the current output directory for this makefile.
+ out = (cmSystemTools::CollapseFullPath
+ (out, this->Makefile->GetCurrentBinaryDirectory()));
+
+ // The generator may add the configuration's subdirectory.
+ if(!conf.empty())
+ {
+ bool iosPlatform = this->Makefile->PlatformIsAppleIos();
+ std::string suffix =
+ usesDefaultOutputDir && iosPlatform ? "${EFFECTIVE_PLATFORM_NAME}" : "";
+ this->Makefile->GetGlobalGenerator()->
+ AppendDirectoryForConfig("/", conf, suffix, out);
+ }
+
+ return usesDefaultOutputDir;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::ComputePDBOutputDir(const std::string& kind,
+ const std::string& config,
+ std::string& out) const
+{
+ // Look for a target property defining the target output directory
+ // based on the target type.
+ const char* propertyName = 0;
+ std::string propertyNameStr = kind;
+ if(!propertyNameStr.empty())
+ {
+ propertyNameStr += "_OUTPUT_DIRECTORY";
+ propertyName = propertyNameStr.c_str();
+ }
+ std::string conf = config;
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(conf);
+ const char* configProp = 0;
+ std::string configPropStr = kind;
+ if(!configPropStr.empty())
+ {
+ configPropStr += "_OUTPUT_DIRECTORY_";
+ configPropStr += configUpper;
+ configProp = configPropStr.c_str();
+ }
+
+ // Select an output directory.
+ if(const char* config_outdir = this->GetProperty(configProp))
+ {
+ // Use the user-specified per-configuration output directory.
+ out = config_outdir;
+
+ // Skip per-configuration subdirectory.
+ conf = "";
+ }
+ else if(const char* outdir = this->GetProperty(propertyName))
+ {
+ // Use the user-specified output directory.
+ out = outdir;
+ }
+ if(out.empty())
+ {
+ return false;
+ }
+
+ // Convert the output path to a full path in case it is
+ // specified as a relative path. Treat a relative path as
+ // relative to the current output directory for this makefile.
+ out = (cmSystemTools::CollapseFullPath
+ (out, this->Makefile->GetCurrentBinaryDirectory()));
+
+ // The generator may add the configuration's subdirectory.
+ if(!conf.empty())
+ {
+ this->Makefile->GetGlobalGenerator()->
+ AppendDirectoryForConfig("/", conf, "", out);
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::UsesDefaultOutputDir(const std::string& config,
+ bool implib) const
+{
+ std::string dir;
+ return this->ComputeOutputDir(config, implib, dir);
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetFrameworkVersion() const
+{
+ assert(this->GetType() != INTERFACE_LIBRARY);
+
+ if(const char* fversion = this->GetProperty("FRAMEWORK_VERSION"))
+ {
+ return fversion;
+ }
+ else if(const char* tversion = this->GetProperty("VERSION"))
+ {
+ return tversion;
+ }
+ else
+ {
+ return "A";
+ }
+}
+
+//----------------------------------------------------------------------------
+const char* cmTarget::GetExportMacro() const
+{
+ // Define the symbol for targets that export symbols.
+ if(this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY ||
+ this->IsExecutableWithExports())
+ {
+ if(const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL"))
+ {
+ this->ExportMacro = custom_export_name;
+ }
+ else
+ {
+ std::string in = this->GetName();
+ in += "_EXPORTS";
+ this->ExportMacro = cmSystemTools::MakeCindentifier(in);
+ }
+ return this->ExportMacro.c_str();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsNullImpliedByLinkLibraries(const std::string &p) const
+{
+ return this->LinkImplicitNullProperties.find(p)
+ != this->LinkImplicitNullProperties.end();
+}
+
+//----------------------------------------------------------------------------
+void
+cmTarget::GetObjectLibrariesCMP0026(std::vector<cmTarget*>& objlibs) const
+{
+ // At configure-time, this method can be called as part of getting the
+ // LOCATION property or to export() a file to be include()d. However
+ // there is no cmGeneratorTarget at configure-time, so search the SOURCES
+ // for TARGET_OBJECTS instead for backwards compatibility with OLD
+ // behavior of CMP0024 and CMP0026 only.
+ typedef cmTargetInternals::TargetPropertyEntry
+ TargetPropertyEntry;
+ for(std::vector<TargetPropertyEntry*>::const_iterator
+ i = this->Internal->SourceEntries.begin();
+ i != this->Internal->SourceEntries.end(); ++i)
+ {
+ std::string entry = (*i)->ge->GetInput();
+
+ std::vector<std::string> files;
+ cmSystemTools::ExpandListArgument(entry, files);
+ for (std::vector<std::string>::const_iterator
+ li = files.begin(); li != files.end(); ++li)
+ {
+ if(cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
+ (*li)[li->size() - 1] == '>')
+ {
+ std::string objLibName = li->substr(17, li->size()-18);
+
+ if (cmGeneratorExpression::Find(objLibName) != std::string::npos)
+ {
+ continue;
+ }
+ cmTarget *objLib = this->Makefile->FindTargetToUse(objLibName);
+ if(objLib)
+ {
+ objlibs.push_back(objLib);
+ }
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+cmTarget::ImportInfo const*
+cmTarget::GetImportInfo(const std::string& config) const
+{
+ // There is no imported information for non-imported targets.
+ if(!this->IsImported())
+ {
+ return 0;
+ }
+
+ // Lookup/compute/cache the import information for this
+ // configuration.
+ std::string config_upper;
+ if(!config.empty())
+ {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ else
+ {
+ config_upper = "NOCONFIG";
+ }
+ typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType;
+
+ ImportInfoMapType::const_iterator i =
+ this->Internal->ImportInfoMap.find(config_upper);
+ if(i == this->Internal->ImportInfoMap.end())
+ {
+ ImportInfo info;
+ this->ComputeImportInfo(config_upper, info);
+ ImportInfoMapType::value_type entry(config_upper, info);
+ i = this->Internal->ImportInfoMap.insert(entry).first;
+ }
+
+ if(this->GetType() == INTERFACE_LIBRARY)
+ {
+ return &i->second;
+ }
+ // If the location is empty then the target is not available for
+ // this configuration.
+ if(i->second.Location.empty() && i->second.ImportLibrary.empty())
+ {
+ return 0;
+ }
+
+ // Return the import information.
+ return &i->second;
+}
+
+bool cmTarget::GetMappedConfig(std::string const& desired_config,
+ const char** loc,
+ const char** imp,
+ std::string& suffix) const
+{
+ if (this->GetType() == INTERFACE_LIBRARY)
+ {
+ // This method attempts to find a config-specific LOCATION for the
+ // IMPORTED library. In the case of INTERFACE_LIBRARY, there is no
+ // LOCATION at all, so leaving *loc and *imp unchanged is the appropriate
+ // and valid response.
+ return true;
+ }
+
+ // Track the configuration-specific property suffix.
+ suffix = "_";
+ suffix += desired_config;
+
+ std::vector<std::string> mappedConfigs;
+ {
+ std::string mapProp = "MAP_IMPORTED_CONFIG_";
+ mapProp += desired_config;
+ if(const char* mapValue = this->GetProperty(mapProp))
+ {
+ cmSystemTools::ExpandListArgument(mapValue, mappedConfigs);
+ }
+ }
+
+ // If we needed to find one of the mapped configurations but did not
+ // On a DLL platform there may be only IMPORTED_IMPLIB for a shared
+ // library or an executable with exports.
+ bool allowImp = this->HasImportLibrary();
+
+ // If a mapping was found, check its configurations.
+ for(std::vector<std::string>::const_iterator mci = mappedConfigs.begin();
+ !*loc && !*imp && mci != mappedConfigs.end(); ++mci)
+ {
+ // Look for this configuration.
+ std::string mcUpper = cmSystemTools::UpperCase(*mci);
+ std::string locProp = "IMPORTED_LOCATION_";
+ locProp += mcUpper;
+ *loc = this->GetProperty(locProp);
+ if(allowImp)
+ {
+ std::string impProp = "IMPORTED_IMPLIB_";
+ impProp += mcUpper;
+ *imp = this->GetProperty(impProp);
+ }
+
+ // If it was found, use it for all properties below.
+ if(*loc || *imp)
+ {
+ suffix = "_";
+ suffix += mcUpper;
+ }
+ }
+
+ // If we needed to find one of the mapped configurations but did not
+ // then the target is not found. The project does not want any
+ // other configuration.
+ if(!mappedConfigs.empty() && !*loc && !*imp)
+ {
+ return false;
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations. Look for an exact-match.
+ if(!*loc && !*imp)
+ {
+ std::string locProp = "IMPORTED_LOCATION";
+ locProp += suffix;
+ *loc = this->GetProperty(locProp);
+ if(allowImp)
+ {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ *imp = this->GetProperty(impProp);
+ }
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations and no exact match.
+ if(!*loc && !*imp)
+ {
+ // The suffix computed above is not useful.
+ suffix = "";
+
+ // Look for a configuration-less location. This may be set by
+ // manually-written code.
+ *loc = this->GetProperty("IMPORTED_LOCATION");
+ if(allowImp)
+ {
+ *imp = this->GetProperty("IMPORTED_IMPLIB");
+ }
+ }
+
+ // If we have not yet found it then the project is willing to try
+ // any available configuration.
+ if(!*loc && !*imp)
+ {
+ std::vector<std::string> availableConfigs;
+ if(const char* iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS"))
+ {
+ cmSystemTools::ExpandListArgument(iconfigs, availableConfigs);
+ }
+ for(std::vector<std::string>::const_iterator
+ aci = availableConfigs.begin();
+ !*loc && !*imp && aci != availableConfigs.end(); ++aci)
+ {
+ suffix = "_";
+ suffix += cmSystemTools::UpperCase(*aci);
+ std::string locProp = "IMPORTED_LOCATION";
+ locProp += suffix;
+ *loc = this->GetProperty(locProp);
+ if(allowImp)
+ {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ *imp = this->GetProperty(impProp);
+ }
+ }
+ }
+ // If we have not yet found it then the target is not available.
+ if(!*loc && !*imp)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::ComputeImportInfo(std::string const& desired_config,
+ ImportInfo& info) const
+{
+ // This method finds information about an imported target from its
+ // properties. The "IMPORTED_" namespace is reserved for properties
+ // defined by the project exporting the target.
+
+ // Initialize members.
+ info.NoSOName = false;
+
+ const char* loc = 0;
+ const char* imp = 0;
+ std::string suffix;
+ if (!this->GetMappedConfig(desired_config, &loc, &imp, suffix))
+ {
+ return;
+ }
+
+ // Get the link interface.
+ {
+ std::string linkProp = "INTERFACE_LINK_LIBRARIES";
+ const char *propertyLibs = this->GetProperty(linkProp);
+
+ if (this->GetType() != INTERFACE_LIBRARY)
+ {
+ if(!propertyLibs)
+ {
+ linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
+ linkProp += suffix;
+ propertyLibs = this->GetProperty(linkProp);
+ }
+
+ if(!propertyLibs)
+ {
+ linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
+ propertyLibs = this->GetProperty(linkProp);
+ }
+ }
+ if(propertyLibs)
+ {
+ info.LibrariesProp = linkProp;
+ info.Libraries = propertyLibs;
+ }
+ }
+ if(this->GetType() == INTERFACE_LIBRARY)
+ {
+ return;
+ }
+
+ // A provided configuration has been chosen. Load the
+ // configuration's properties.
+
+ // Get the location.
+ if(loc)
+ {
+ info.Location = loc;
+ }
+ else
+ {
+ std::string impProp = "IMPORTED_LOCATION";
+ impProp += suffix;
+ if(const char* config_location = this->GetProperty(impProp))
+ {
+ info.Location = config_location;
+ }
+ else if(const char* location = this->GetProperty("IMPORTED_LOCATION"))
+ {
+ info.Location = location;
+ }
+ }
+
+ // Get the soname.
+ if(this->GetType() == cmTarget::SHARED_LIBRARY)
+ {
+ std::string soProp = "IMPORTED_SONAME";
+ soProp += suffix;
+ if(const char* config_soname = this->GetProperty(soProp))
+ {
+ info.SOName = config_soname;
+ }
+ else if(const char* soname = this->GetProperty("IMPORTED_SONAME"))
+ {
+ info.SOName = soname;
+ }
+ }
+
+ // Get the "no-soname" mark.
+ if(this->GetType() == cmTarget::SHARED_LIBRARY)
+ {
+ std::string soProp = "IMPORTED_NO_SONAME";
+ soProp += suffix;
+ if(const char* config_no_soname = this->GetProperty(soProp))
+ {
+ info.NoSOName = cmSystemTools::IsOn(config_no_soname);
+ }
+ else if(const char* no_soname = this->GetProperty("IMPORTED_NO_SONAME"))
+ {
+ info.NoSOName = cmSystemTools::IsOn(no_soname);
+ }
+ }
+
+ // Get the import library.
+ if(imp)
+ {
+ info.ImportLibrary = imp;
+ }
+ else if(this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->IsExecutableWithExports())
+ {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ if(const char* config_implib = this->GetProperty(impProp))
+ {
+ info.ImportLibrary = config_implib;
+ }
+ else if(const char* implib = this->GetProperty("IMPORTED_IMPLIB"))
+ {
+ info.ImportLibrary = implib;
+ }
+ }
+
+ // Get the link dependencies.
+ {
+ std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES";
+ linkProp += suffix;
+ if(const char* config_libs = this->GetProperty(linkProp))
+ {
+ info.SharedDeps = config_libs;
+ }
+ else if(const char* libs =
+ this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES"))
+ {
+ info.SharedDeps = libs;
+ }
+ }
+
+ // Get the link languages.
+ if(this->LinkLanguagePropagatesToDependents())
+ {
+ std::string linkProp = "IMPORTED_LINK_INTERFACE_LANGUAGES";
+ linkProp += suffix;
+ if(const char* config_libs = this->GetProperty(linkProp))
+ {
+ info.Languages = config_libs;
+ }
+ else if(const char* libs =
+ this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES"))
+ {
+ info.Languages = libs;
+ }
+ }
+
+ // Get the cyclic repetition count.
+ if(this->GetType() == cmTarget::STATIC_LIBRARY)
+ {
+ std::string linkProp = "IMPORTED_LINK_INTERFACE_MULTIPLICITY";
+ linkProp += suffix;
+ if(const char* config_reps = this->GetProperty(linkProp))
+ {
+ sscanf(config_reps, "%u", &info.Multiplicity);
+ }
+ else if(const char* reps =
+ this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY"))
+ {
+ sscanf(reps, "%u", &info.Multiplicity);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmTargetInternals::AddInterfaceEntries(
+ cmTarget const* thisTarget, std::string const& config,
+ std::string const& prop, std::vector<TargetPropertyEntry*>& entries)
+{
+ if(cmLinkImplementationLibraries const* impl =
+ thisTarget->GetLinkImplementationLibraries(config))
+ {
+ for (std::vector<cmLinkImplItem>::const_iterator
+ it = impl->Libraries.begin(), end = impl->Libraries.end();
+ it != end; ++it)
+ {
+ if(it->Target)
+ {
+ std::string genex =
+ "$<TARGET_PROPERTY:" + *it + "," + prop + ">";
+ cmGeneratorExpression ge(it->Backtrace);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
+ cge->SetEvaluateForBuildsystem(true);
+ entries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge, *it));
+ }
+ }
+ }
+}
+
+cmOptionalLinkImplementation&
+cmTarget::GetLinkImplMap(std::string const& config) const
+{
+ // Populate the link implementation for this configuration.
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ return Internal->LinkImplMap[CONFIG][this];
+}
+
+//----------------------------------------------------------------------------
+cmLinkImplementationLibraries const*
+cmTarget::GetLinkImplementationLibraries(const std::string& config) const
+{
+ return this->GetLinkImplementationLibrariesInternal(config, this);
+}
+
+//----------------------------------------------------------------------------
+cmLinkImplementationLibraries const*
+cmTarget::GetLinkImplementationLibrariesInternal(const std::string& config,
+ cmTarget const* head) const
+{
+ // There is no link implementation for imported targets.
+ if(this->IsImported())
+ {
+ return 0;
+ }
+
+ // Populate the link implementation libraries for this configuration.
+ std::string CONFIG = cmSystemTools::UpperCase(config);
+ cmTargetInternals::HeadToLinkImplementationMap& hm =
+ this->Internal->LinkImplMap[CONFIG];
+
+ // If the link implementation does not depend on the head target
+ // then return the one we computed first.
+ if(!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition)
+ {
+ return &hm.begin()->second;
+ }
+
+ cmOptionalLinkImplementation& impl = hm[head];
+ if(!impl.LibrariesDone)
+ {
+ impl.LibrariesDone = true;
+ this->ComputeLinkImplementationLibraries(config, impl, head);
+ }
+ return &impl;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::ComputeLinkImplementationLibraries(
+ const std::string& config,
+ cmOptionalLinkImplementation& impl,
+ cmTarget const* head) const
+{
+ // Collect libraries directly linked in this configuration.
+ for (std::vector<cmValueWithOrigin>::const_iterator
+ le = this->Internal->LinkImplementationPropertyEntries.begin(),
+ end = this->Internal->LinkImplementationPropertyEntries.end();
+ le != end; ++le)
+ {
+ std::vector<std::string> llibs;
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(),
+ "LINK_LIBRARIES", 0, 0);
+ cmGeneratorExpression ge(le->Backtrace);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> const cge =
+ ge.Parse(le->Value);
+ std::string const evaluated =
+ cge->Evaluate(this->Makefile, config, false, head, &dagChecker);
+ cmSystemTools::ExpandListArgument(evaluated, llibs);
+ if(cge->GetHadHeadSensitiveCondition())
+ {
+ impl.HadHeadSensitiveCondition = true;
+ }
+
+ for(std::vector<std::string>::const_iterator li = llibs.begin();
+ li != llibs.end(); ++li)
+ {
+ // Skip entries that resolve to the target itself or are empty.
+ std::string name = this->CheckCMP0004(*li);
+ if(name == this->GetName() || name.empty())
+ {
+ if(name == this->GetName())
+ {
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ std::ostringstream e;
+ switch(this->GetPolicyStatusCMP0038())
+ {
+ case cmPolicies::WARN:
+ {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0038) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ }
+ break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+
+ if(!noMessage)
+ {
+ e << "Target \"" << this->GetName() << "\" links to itself.";
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ messageType, e.str(), this->GetBacktrace());
+ if (messageType == cmake::FATAL_ERROR)
+ {
+ return;
+ }
+ }
+ }
+ continue;
+ }
+
+ // The entry is meant for this configuration.
+ impl.Libraries.push_back(
+ cmLinkImplItem(name, this->FindTargetToLink(name),
+ le->Backtrace, evaluated != le->Value));
+ }
+
+ std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
+ for (std::set<std::string>::const_iterator it = seenProps.begin();
+ it != seenProps.end(); ++it)
+ {
+ if (!this->GetProperty(*it))
+ {
+ this->LinkImplicitNullProperties.insert(*it);
+ }
+ }
+ cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
+ }
+
+ cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
+ cmTarget::LinkLibraryVectorType const& oldllibs =
+ this->GetOriginalLinkLibraries();
+ for(cmTarget::LinkLibraryVectorType::const_iterator li = oldllibs.begin();
+ li != oldllibs.end(); ++li)
+ {
+ if(li->second != cmTarget::GENERAL && li->second != linkType)
+ {
+ std::string name = this->CheckCMP0004(li->first);
+ if(name == this->GetName() || name.empty())
+ {
+ continue;
+ }
+ // Support OLD behavior for CMP0003.
+ impl.WrongConfigLibraries.push_back(
+ cmLinkItem(name, this->FindTargetToLink(name)));
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+cmTarget const* cmTarget::FindTargetToLink(std::string const& name) const
+{
+ cmTarget const* tgt = this->Makefile->FindTargetToUse(name);
+
+ // Skip targets that will not really be linked. This is probably a
+ // name conflict between an external library and an executable
+ // within the project.
+ if(tgt && tgt->GetType() == cmTarget::EXECUTABLE &&
+ !tgt->IsExecutableWithExports())
+ {
+ tgt = 0;
+ }
+
+ if(tgt && tgt->GetType() == cmTarget::OBJECT_LIBRARY)
+ {
+ std::ostringstream e;
+ e << "Target \"" << this->GetName() << "\" links to "
+ "OBJECT library \"" << tgt->GetName() << "\" but this is not "
+ "allowed. "
+ "One may link only to STATIC or SHARED libraries, or to executables "
+ "with the ENABLE_EXPORTS property set.";
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ tgt = 0;
+ }
+
+ // Return the target found, if any.
+ return tgt;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::CheckCMP0004(std::string const& item) const
+{
+ // Strip whitespace off the library names because we used to do this
+ // in case variables were expanded at generate time. We no longer
+ // do the expansion but users link to libraries like " ${VAR} ".
+ std::string lib = item;
+ std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
+ if(pos != lib.npos)
+ {
+ lib = lib.substr(pos, lib.npos);
+ }
+ pos = lib.find_last_not_of(" \t\r\n");
+ if(pos != lib.npos)
+ {
+ lib = lib.substr(0, pos+1);
+ }
+ if(lib != item)
+ {
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ switch(this->GetPolicyStatusCMP0004())
+ {
+ case cmPolicies::WARN:
+ {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0004) << "\n"
+ << "Target \"" << this->GetName() << "\" links to item \""
+ << item << "\" which has leading or trailing whitespace.";
+ cm->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
+ this->GetBacktrace());
+ }
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::NEW:
+ {
+ std::ostringstream e;
+ e << "Target \"" << this->GetName() << "\" links to item \""
+ << item << "\" which has leading or trailing whitespace. "
+ << "This is now an error according to policy CMP0004.";
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ {
+ std::ostringstream e;
+ e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0004) << "\n"
+ << "Target \"" << this->GetName() << "\" links to item \""
+ << item << "\" which has leading or trailing whitespace.";
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ }
+ break;
+ }
+ }
+ return lib;
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer::cmTargetInternalPointer()
+{
+ this->Pointer = new cmTargetInternals;
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer
+::cmTargetInternalPointer(cmTargetInternalPointer const& r)
+{
+ // Ideally cmTarget instances should never be copied. However until
+ // we can make a sweep to remove that, this copy constructor avoids
+ // allowing the resources (Internals) to be copied.
+ this->Pointer = new cmTargetInternals(*r.Pointer);
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer::~cmTargetInternalPointer()
+{
+ cmDeleteAll(this->Pointer->SourceEntries);
+ delete this->Pointer;
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer&
+cmTargetInternalPointer::operator=(cmTargetInternalPointer const& r)
+{
+ if(this == &r) { return *this; } // avoid warning on HP about self check
+ // Ideally cmTarget instances should never be copied. However until
+ // we can make a sweep to remove that, this copy constructor avoids
+ // allowing the resources (Internals) to be copied.
+ cmTargetInternals* oldPointer = this->Pointer;
+ this->Pointer = new cmTargetInternals(*r.Pointer);
+ delete oldPointer;
+ return *this;
+}