summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2008-01-28 08:38:36 -0500
committerBrad King <brad.king@kitware.com>2008-01-28 08:38:36 -0500
commit5594ad488576a77d9c6b8c3c1999a04fb4e6867d (patch)
treef22726476b6eaaf3832e48c185fe3c112601db17
parenta7cb9d1120c0555f1da67dd585bd1b4fd16d389d (diff)
downloadcmake-5594ad488576a77d9c6b8c3c1999a04fb4e6867d.tar.gz
ENH: Updated exporting and importing of targets to support libraries and configurations.
- Created cmExportFileGenerator hierarchy to implement export file generation - Installed exports use per-config import files loaded by a central one. - Include soname of shared libraries in import information - Renamed PREFIX to NAMESPACE in INSTALL(EXPORT) and EXPORT() commands - Move addition of CMAKE_INSTALL_PREFIX to destinations to install generators - Import files compute the installation prefix relative to their location when loaded - Add mapping of importer configurations to importee configurations - Rename IMPORT targets to IMPORTED targets to distinguish from windows import libraries - Scope IMPORTED targets within directories to isolate them - Place all properties created by import files in the IMPORTED namespace - Document INSTALL(EXPORT) and EXPORT() commands. - Document IMPORTED signature of add_executable and add_library - Enable finding of imported targets in cmComputeLinkDepends
-rw-r--r--Source/CMakeLists.txt6
-rw-r--r--Source/cmAddDependenciesCommand.cxx2
-rw-r--r--Source/cmAddExecutableCommand.cxx56
-rw-r--r--Source/cmAddExecutableCommand.h18
-rw-r--r--Source/cmAddLibraryCommand.cxx45
-rw-r--r--Source/cmAddLibraryCommand.h21
-rw-r--r--Source/cmComputeLinkDepends.cxx93
-rw-r--r--Source/cmComputeLinkDepends.h5
-rw-r--r--Source/cmComputeLinkInformation.cxx28
-rw-r--r--Source/cmExportBuildFileGenerator.cxx117
-rw-r--r--Source/cmExportBuildFileGenerator.h55
-rw-r--r--Source/cmExportCommand.cxx197
-rw-r--r--Source/cmExportCommand.h31
-rw-r--r--Source/cmExportFileGenerator.cxx281
-rw-r--r--Source/cmExportFileGenerator.h96
-rw-r--r--Source/cmExportInstallFileGenerator.cxx259
-rw-r--r--Source/cmExportInstallFileGenerator.h122
-rw-r--r--Source/cmGetPropertyCommand.cxx4
-rw-r--r--Source/cmGetTargetPropertyCommand.cxx4
-rw-r--r--Source/cmGlobalGenerator.cxx37
-rw-r--r--Source/cmGlobalGenerator.h7
-rw-r--r--Source/cmGlobalVisualStudio6Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx3
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx3
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx6
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx8
-rw-r--r--Source/cmIncludeExternalMSProjectCommand.cxx3
-rw-r--r--Source/cmInstallCommand.cxx96
-rw-r--r--Source/cmInstallCommand.h47
-rw-r--r--Source/cmInstallCommandArguments.cxx28
-rw-r--r--Source/cmInstallCommandArguments.h4
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx3
-rw-r--r--Source/cmInstallExportGenerator.cxx325
-rw-r--r--Source/cmInstallExportGenerator.h84
-rw-r--r--Source/cmInstallFilesCommand.cxx5
-rw-r--r--Source/cmInstallFilesGenerator.cxx2
-rw-r--r--Source/cmInstallGenerator.cxx39
-rw-r--r--Source/cmInstallGenerator.h12
-rw-r--r--Source/cmInstallProgramsCommand.cxx5
-rw-r--r--Source/cmInstallTargetGenerator.cxx21
-rw-r--r--Source/cmInstallTargetGenerator.h3
-rw-r--r--Source/cmLocalGenerator.cxx12
-rw-r--r--Source/cmLocalVisualStudio6Generator.cxx3
-rw-r--r--Source/cmMakefile.cxx87
-rw-r--r--Source/cmMakefile.h18
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx4
-rw-r--r--Source/cmMakefileTargetGenerator.cxx4
-rw-r--r--Source/cmSetPropertyCommand.cxx4
-rw-r--r--Source/cmSetTargetPropertiesCommand.cxx4
-rw-r--r--Source/cmTarget.cxx580
-rw-r--r--Source/cmTarget.h45
52 files changed, 2212 insertions, 734 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 63ecda36cf..9608224943 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -121,6 +121,12 @@ SET(SRCS
cmExprLexer.cxx
cmExprParser.cxx
cmExprParserHelper.cxx
+ cmExportBuildFileGenerator.h
+ cmExportBuildFileGenerator.cxx
+ cmExportFileGenerator.h
+ cmExportFileGenerator.cxx
+ cmExportInstallFileGenerator.h
+ cmExportInstallFileGenerator.cxx
cmExtraEclipseCDT4Generator.cxx
cmExtraEclipseCDT4Generator.h
cmFileTimeComparison.cxx
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
index eccf7d6881..4f1e05bc5a 100644
--- a/Source/cmAddDependenciesCommand.cxx
+++ b/Source/cmAddDependenciesCommand.cxx
@@ -32,7 +32,7 @@ bool cmAddDependenciesCommand
cmTarget* target =
this->GetMakefile()->GetLocalGenerator()->
- GetGlobalGenerator()->FindTarget(0, target_name.c_str(), false);
+ GetGlobalGenerator()->FindTarget(0, target_name.c_str());
if(target)
{
std::vector<std::string>::const_iterator s = args.begin();
diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx
index 9914e171de..cea12bc343 100644
--- a/Source/cmAddExecutableCommand.cxx
+++ b/Source/cmAddExecutableCommand.cxx
@@ -51,7 +51,7 @@ bool cmAddExecutableCommand
++s;
excludeFromAll = true;
}
- else if(*s == "IMPORT")
+ else if(*s == "IMPORTED")
{
++s;
importTarget = true;
@@ -61,12 +61,60 @@ bool cmAddExecutableCommand
break;
}
}
-
- if (importTarget)
+
+ // Special modifiers are not allowed with IMPORTED signature.
+ if(importTarget && (use_win32 || use_macbundle || excludeFromAll))
+ {
+ if(use_win32)
+ {
+ this->SetError("may not be given WIN32 for an IMPORTED target.");
+ }
+ else if(use_macbundle)
+ {
+ this->SetError(
+ "may not be given MACOSX_BUNDLE for an IMPORTED target.");
+ }
+ else // if(excludeFromAll)
+ {
+ this->SetError(
+ "may not be given EXCLUDE_FROM_ALL for an IMPORTED target.");
+ }
+ return false;
+ }
+
+ // Check for an existing target with this name.
+ cmTarget* existing = this->Makefile->FindTargetToUse(exename.c_str());
+ if(importTarget)
{
- this->Makefile->AddNewTarget(cmTarget::EXECUTABLE, exename.c_str(), true);
+ // Make sure the target does not already exist.
+ if(existing)
+ {
+ cmOStringStream e;
+ e << "cannot create imported target \"" << exename
+ << "\" because another target with the same name already exists.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Create the imported target.
+ this->Makefile->AddImportedTarget(exename.c_str(), cmTarget::EXECUTABLE);
return true;
}
+ else
+ {
+ // Make sure the target does not conflict with an imported target.
+ // This should really enforce global name uniqueness for targets
+ // built within the project too, but that may break compatiblity
+ // with projects in which it was accidentally working.
+ if(existing && existing->IsImported())
+ {
+ cmOStringStream e;
+ e << "cannot create target \"" << exename
+ << "\" because an imported target with the same name already exists.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
if (s == args.end())
{
diff --git a/Source/cmAddExecutableCommand.h b/Source/cmAddExecutableCommand.h
index daedc82ab1..4ac11cc505 100644
--- a/Source/cmAddExecutableCommand.h
+++ b/Source/cmAddExecutableCommand.h
@@ -90,6 +90,24 @@ public:
"If EXCLUDE_FROM_ALL is given the target will not be built by default. "
"It will be built only if the user explicitly builds the target or "
"another target that requires the target depends on it."
+ "\n"
+ "The add_executable command can also create IMPORTED executable "
+ "targets using this signature:\n"
+ " add_executable(<name> IMPORTED)\n"
+ "An IMPORTED executable target references an executable file located "
+ "outside the project. "
+ "No rules are generated to build it. "
+ "The target name has scope in the directory in which it is created "
+ "and below. "
+ "It may be referenced like any target built within the project. "
+ "IMPORTED executables are useful for convenient reference from "
+ "commands like add_custom_command. "
+ "Details about the imported executable are specified by setting "
+ "properties whose names begin in \"IMPORTED_\". "
+ "The most important such property is IMPORTED_LOCATION "
+ "(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) "
+ "which specifies the location of the main executable file on disk. "
+ "See documentation of the IMPORTED_* properties for more information."
;
}
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
index 4cc7e7ae3f..9406a35846 100644
--- a/Source/cmAddLibraryCommand.cxx
+++ b/Source/cmAddLibraryCommand.cxx
@@ -46,6 +46,7 @@ bool cmAddLibraryCommand
// If the second argument is "SHARED" or "STATIC", then it controls
// the type of library. Otherwise, it is treated as a source or
// source list name. There may be two keyword arguments, check for them
+ bool haveSpecifiedType = false;
while ( s != args.end() )
{
std::string libType = *s;
@@ -53,23 +54,26 @@ bool cmAddLibraryCommand
{
++s;
type = cmTarget::STATIC_LIBRARY;
+ haveSpecifiedType = true;
}
else if(libType == "SHARED")
{
++s;
type = cmTarget::SHARED_LIBRARY;
+ haveSpecifiedType = true;
}
else if(libType == "MODULE")
{
++s;
type = cmTarget::MODULE_LIBRARY;
+ haveSpecifiedType = true;
}
else if(*s == "EXCLUDE_FROM_ALL")
{
++s;
excludeFromAll = true;
}
- else if(*s == "IMPORT")
+ else if(*s == "IMPORTED")
{
++s;
importTarget = true;
@@ -98,11 +102,46 @@ bool cmAddLibraryCommand
type = cmTarget::STATIC_LIBRARY;
}
- if (importTarget)
+ // The IMPORTED signature requires a type to be specified explicitly.
+ if(importTarget && !haveSpecifiedType)
{
- this->Makefile->AddNewTarget(type, libName.c_str(), true);
+ this->SetError("called with IMPORTED argument but no library type.");
+ return false;
+ }
+
+ // Check for an existing target with this name.
+ cmTarget* existing = this->Makefile->FindTargetToUse(libName.c_str());
+ if(importTarget)
+ {
+ // Make sure the target does not already exist.
+ if(existing)
+ {
+ cmOStringStream e;
+ e << "cannot create imported target \"" << libName
+ << "\" because another target with the same name already exists.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Create the imported target.
+ this->Makefile->AddImportedTarget(libName.c_str(), type);
return true;
}
+ else
+ {
+ // Make sure the target does not conflict with an imported target.
+ // This should really enforce global name uniqueness for targets
+ // built within the project too, but that may break compatiblity
+ // with projects in which it was accidentally working.
+ if(existing && existing->IsImported())
+ {
+ cmOStringStream e;
+ e << "cannot create target \"" << libName
+ << "\" because an imported target with the same name already exists.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
if (s == args.end())
{
diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h
index 6b0f7a494b..9b95b86ff1 100644
--- a/Source/cmAddLibraryCommand.h
+++ b/Source/cmAddLibraryCommand.h
@@ -73,7 +73,26 @@ public:
"to STATIC.\n"
"If EXCLUDE_FROM_ALL is given the target will not be built by default. "
"It will be built only if the user explicitly builds the target or "
- "another target that requires the target depends on it.";
+ "another target that requires the target depends on it."
+ "\n"
+ "The add_library command can also create IMPORTED library "
+ "targets using this signature:\n"
+ " add_library(<name> <SHARED|STATIC|MODULE> IMPORTED)\n"
+ "An IMPORTED library target references a library file located "
+ "outside the project. "
+ "No rules are generated to build it. "
+ "The target name has scope in the directory in which it is created "
+ "and below. "
+ "It may be referenced like any target built within the project. "
+ "IMPORTED libraries are useful for convenient reference from "
+ "commands like target_link_libraries. "
+ "Details about the imported library are specified by setting "
+ "properties whose names begin in \"IMPORTED_\". "
+ "The most important such property is IMPORTED_LOCATION "
+ "(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) "
+ "which specifies the location of the main library file on disk. "
+ "See documentation of the IMPORTED_* properties for more information."
+ ;
}
cmTypeMacro(cmAddLibraryCommand, cmCommand);
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 6056431093..b4cb92eb66 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -158,7 +158,7 @@ std::vector<cmComputeLinkDepends::LinkEntry> const&
cmComputeLinkDepends::Compute()
{
// Follow the link dependencies of the target to be linked.
- this->AddLinkEntries(-1, this->Target->GetOriginalLinkLibraries());
+ this->AddTargetLinkEntries(-1, this->Target->GetOriginalLinkLibraries());
// Complete the breadth-first search of dependencies.
while(!this->BFSQueue.empty())
@@ -222,8 +222,7 @@ int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
int index = lei->second;
LinkEntry& entry = this->EntryList[index];
entry.Item = item;
- entry.Target =
- this->GlobalGenerator->FindTarget(0, entry.Item.c_str(), false);
+ entry.Target = this->Makefile->FindTargetToUse(entry.Item.c_str());
// If the item has dependencies queue it to follow them.
if(entry.Target)
@@ -264,8 +263,15 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
if(entry.Target)
{
// Follow the target dependencies.
- this->AddLinkEntries(depender_index,
- entry.Target->GetOriginalLinkLibraries());
+ if(entry.Target->IsImported())
+ {
+ this->AddImportedLinkEntries(depender_index, entry.Target);
+ }
+ else
+ {
+ this->AddTargetLinkEntries(depender_index,
+ entry.Target->GetOriginalLinkLibraries());
+ }
}
else
{
@@ -274,6 +280,18 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
}
}
+//----------------------------------------------------------------------------
+void cmComputeLinkDepends::AddImportedLinkEntries(int depender_index,
+ cmTarget* target)
+{
+ if(std::vector<std::string> const* libs =
+ target->GetImportedLinkLibraries(this->Config))
+ {
+ this->AddLinkEntries(depender_index, *libs);
+ }
+}
+
+//----------------------------------------------------------------------------
void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
const char* value)
{
@@ -283,39 +301,49 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
std::vector<std::string> deplist;
cmSystemTools::ExpandListArgument(value, deplist);
- // Construct the vector of type/value pairs from the variable.
- LinkLibraryVectorType libs;
- cmTarget::LinkLibraryType linkType = cmTarget::GENERAL;
+ // Compute which library configuration to link.
+ cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
+ if(this->Config && cmSystemTools::UpperCase(this->Config) == "DEBUG")
+ {
+ linkType = cmTarget::DEBUG;
+ }
+
+ // Look for entries meant for this configuration.
+ std::vector<std::string> actual_libs;
+ cmTarget::LinkLibraryType llt = cmTarget::GENERAL;
for(std::vector<std::string>::const_iterator di = deplist.begin();
di != deplist.end(); ++di)
{
if(*di == "debug")
{
- linkType = cmTarget::DEBUG;
+ llt = cmTarget::DEBUG;
}
else if(*di == "optimized")
{
- linkType = cmTarget::OPTIMIZED;
+ llt = cmTarget::OPTIMIZED;
}
else if(*di == "general")
{
- linkType = cmTarget::GENERAL;
+ llt = cmTarget::GENERAL;
}
else if(!di->empty())
{
- cmTarget::LibraryID lib(*di, linkType);
- libs.push_back(lib);
+ if(llt == cmTarget::GENERAL || llt == linkType)
+ {
+ actual_libs.push_back(*di);
+ }
linkType = cmTarget::GENERAL;
}
}
// Add the entries from this list.
- this->AddLinkEntries(depender_index, libs);
+ this->AddLinkEntries(depender_index, actual_libs);
}
//----------------------------------------------------------------------------
-void cmComputeLinkDepends::AddLinkEntries(int depender_index,
- LinkLibraryVectorType const& libs)
+void
+cmComputeLinkDepends::AddTargetLinkEntries(int depender_index,
+ LinkLibraryVectorType const& libs)
{
// Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
@@ -324,23 +352,42 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
linkType = cmTarget::DEBUG;
}
+ // Look for entries meant for this configuration.
+ std::vector<std::string> actual_libs;
+ for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
+ li != libs.end(); ++li)
+ {
+ if(li->second == cmTarget::GENERAL || li->second == linkType)
+ {
+ actual_libs.push_back(li->first);
+ }
+ }
+
+ // Add these entries.
+ this->AddLinkEntries(depender_index, actual_libs);
+}
+
+//----------------------------------------------------------------------------
+void
+cmComputeLinkDepends::AddLinkEntries(int depender_index,
+ std::vector<std::string> const& libs)
+{
// Track inferred dependency sets implied by this list.
std::map<int, DependSet> dependSets;
- // Loop over the libraries linked directly by the target.
- for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
+ // Loop over the libraries linked directly by the depender.
+ for(std::vector<std::string>::const_iterator li = libs.begin();
li != libs.end(); ++li)
{
- // Skip entries that will resolve to the target getting linked.
- // Skip libraries not meant for the current configuration.
- if(li->first == this->Target->GetName() || li->first.empty() ||
- !(li->second == cmTarget::GENERAL || li->second == linkType))
+ // Skip entries that will resolve to the target getting linked or
+ // are empty.
+ if(*li == this->Target->GetName() || li->empty())
{
continue;
}
// Add a link entry for this item.
- int dependee_index = this->AddLinkEntry(li->first);
+ int dependee_index = this->AddLinkEntry(*li);
// The depender must come before the dependee.
if(depender_index >= 0)
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 646adca04f..881d50fc26 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -66,9 +66,12 @@ private:
typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType;
int AddLinkEntry(std::string const& item);
+ void AddImportedLinkEntries(int depender_index, cmTarget* target);
void AddVarLinkEntries(int depender_index, const char* value);
+ void AddTargetLinkEntries(int depender_index,
+ LinkLibraryVectorType const& libs);
void AddLinkEntries(int depender_index,
- LinkLibraryVectorType const& libs);
+ std::vector<std::string> const& libs);
// One entry for each unique item.
std::vector<LinkEntry> EntryList;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 1ec1ba3298..4d0d93a86f 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -301,11 +301,8 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
{
// Compute the proper name to use to link this library.
const char* config = this->Config;
- bool implib = this->UseImportLibrary;
- bool impexe = (tgt &&
- tgt->GetType() == cmTarget::EXECUTABLE &&
- tgt->GetPropertyAsBool("ENABLE_EXPORTS"));
- if(impexe && !implib && !this->LoaderFlag)
+ bool impexe = (tgt && tgt->IsExecutableWithExports());
+ if(impexe && !this->UseImportLibrary && !this->LoaderFlag)
{
// Skip linking to executables on platforms with no import
// libraries or loader flags.
@@ -325,13 +322,18 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
// platform. Add it now.
std::string linkItem;
linkItem = this->LoaderFlag;
- std::string exe = tgt->GetFullPath(config, implib);
+ std::string exe = tgt->GetFullPath(config, this->UseImportLibrary);
linkItem += exe;
this->Items.push_back(Item(linkItem, true));
this->Depends.push_back(exe);
}
else
{
+ // Decide whether to use an import library.
+ bool implib =
+ (this->UseImportLibrary &&
+ (impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
+
// Pass the full path to the target file.
std::string lib = tgt->GetFullPath(config, implib);
this->Depends.push_back(lib);
@@ -950,18 +952,8 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
// Try to get the soname of the library. Only files with this name
// could possibly conflict.
- std::string soName;
- const char* soname = 0;
- if(!target->IsImported())
- {
- std::string name;
- std::string realName;
- std::string impName;
- std::string pdbName;
- target->GetLibraryNames(name, soName, realName, impName, pdbName,
- this->Config);
- soname = soName.c_str();
- }
+ std::string soName = target->GetSOName(this->Config);
+ const char* soname = soName.empty()? 0 : soName.c_str();
// Add the library runtime entry.
this->AddLibraryRuntimeInfo(fullPath, soname);
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
new file mode 100644
index 0000000000..0412c905a0
--- /dev/null
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -0,0 +1,117 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmExportBuildFileGenerator.h"
+
+//----------------------------------------------------------------------------
+bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ // Create all the imported targets.
+ for(std::vector<cmTarget*>::const_iterator
+ tei = this->Exports->begin();
+ tei != this->Exports->end(); ++tei)
+ {
+ cmTarget* te = *tei;
+ this->ExportedTargets.insert(te);
+ this->GenerateImportTargetCode(os, te);
+ }
+
+ // Generate import file content for each configuration.
+ for(std::vector<std::string>::const_iterator
+ ci = this->Configurations.begin();
+ ci != this->Configurations.end(); ++ci)
+ {
+ this->GenerateImportConfig(os, ci->c_str());
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportBuildFileGenerator
+::GenerateImportTargetsConfig(std::ostream& os,
+ const char* config, std::string const& suffix)
+{
+ for(std::vector<cmTarget*>::const_iterator
+ tei = this->Exports->begin();
+ tei != this->Exports->end(); ++tei)
+ {
+ // Collect import properties for this target.
+ cmTarget* target = *tei;
+ ImportPropertyMap properties;
+ this->SetImportLocationProperty(config, suffix, target, properties);
+ if(!properties.empty())
+ {
+ // Get the rest of the target details.
+ this->SetImportDetailProperties(config, suffix,
+ target, properties);
+
+ // TOOD: PUBLIC_HEADER_LOCATION
+ // this->GenerateImportProperty(config, te->HeaderGenerator,
+ // properties);
+
+ // Generate code in the export file.
+ this->GenerateImportPropertyCode(os, config, target, properties);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportBuildFileGenerator
+::SetImportLocationProperty(const char* config, std::string const& suffix,
+ cmTarget* target, ImportPropertyMap& properties)
+{
+ // Get the makefile in which to lookup target information.
+ cmMakefile* mf = target->GetMakefile();
+
+ // Add the main target file.
+ {
+ std::string prop = "IMPORTED_LOCATION";
+ prop += suffix;
+ std::string value = target->GetFullPath(config, false);
+ properties[prop] = value;
+ }
+
+ // Check whether this is a DLL platform.
+ bool dll_platform =
+ (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW"));
+
+ // Add the import library for windows DLLs.
+ if(dll_platform &&
+ (target->GetType() == cmTarget::SHARED_LIBRARY ||
+ target->IsExecutableWithExports()) &&
+ mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"))
+ {
+ std::string prop = "IMPORTED_IMPLIB";
+ prop += suffix;
+ std::string value = target->GetFullPath(config, true);
+ properties[prop] = value;
+ }
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportBuildFileGenerator
+::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
+{
+ cmOStringStream e;
+ e << "WARNING: EXPORT(...) includes target " << target->GetName()
+ << " which links to target \"" << dep
+ << "\" that is not in the export set.";
+ cmSystemTools::Message(e.str().c_str());
+}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
new file mode 100644
index 0000000000..0bb79cc2a4
--- /dev/null
+++ b/Source/cmExportBuildFileGenerator.h
@@ -0,0 +1,55 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmExportBuildFileGenerator_h
+#define cmExportBuildFileGenerator_h
+
+#include "cmExportFileGenerator.h"
+
+/** \class cmExportBuildFileGenerator
+ * \brief Generate a file exporting targets from a build tree.
+ *
+ * cmExportBuildFileGenerator generates a file exporting targets from
+ * a build tree. A single file exports information for all
+ * configurations built.
+ *
+ * This is used to implement the EXPORT() command.
+ */
+class cmExportBuildFileGenerator: public cmExportFileGenerator
+{
+public:
+ /** Set the list of targets to export. */
+ void SetExports(std::vector<cmTarget*> const* exports)
+ { this->Exports = exports; }
+
+protected:
+ // Implement virtual methods from the superclass.
+ virtual bool GenerateMainFile(std::ostream& os);
+ virtual void GenerateImportTargetsConfig(std::ostream& os,
+ const char* config,
+ std::string const& suffix);
+ virtual void ComplainAboutMissingTarget(cmTarget* target, const char* dep);
+
+ /** Fill in properties indicating built file locations. */
+ void SetImportLocationProperty(const char* config,
+ std::string const& suffix,
+ cmTarget* target,
+ ImportPropertyMap& properties);
+
+ std::vector<cmTarget*> const* Exports;
+};
+
+#endif
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 3dca7d8cfc..70c024e5c7 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -20,14 +20,13 @@
#include "cmGeneratedFileStream.h"
#include "cmake.h"
-#include <cmsys/auto_ptr.hxx>
+#include "cmExportBuildFileGenerator.h"
cmExportCommand::cmExportCommand()
:cmCommand()
,ArgumentGroup()
,Targets(&Helper, "TARGETS")
-,Append(&Helper, "APPEND", &ArgumentGroup)
-,Prefix(&Helper, "PREFIX", &ArgumentGroup)
+,Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
,Filename(&Helper, "FILE", &ArgumentGroup)
{
// at first TARGETS
@@ -53,151 +52,131 @@ bool cmExportCommand
if (!unknownArgs.empty())
{
this->SetError("Unknown arguments.");
- cmSystemTools::SetFatalErrorOccured();
return false;
}
if (this->Targets.WasFound() == false)
{
this->SetError("TARGETS option missing.");
- cmSystemTools::SetFatalErrorOccured();
return false;
}
-
- if ( !this->Makefile->CanIWriteThisFile(this->Filename.GetString().c_str()) )
+ if(!this->Filename.WasFound())
{
- std::string e = "attempted to write a file: " + this->Filename.GetString()
- + " into a source directory.";
- this->SetError(e.c_str());
- cmSystemTools::SetFatalErrorOccured();
+ this->SetError("FILE <filename> option missing.");
return false;
}
- if((this->Targets.GetVector().empty())||(this->Filename.GetString().empty()))
+ // Make sure the file has a .cmake extension.
+ if(cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString())
+ != ".cmake")
{
- return true;
+ cmOStringStream e;
+ e << "FILE option given filename \"" << this->Filename.GetString()
+ << "\" which does not have an extension of \".cmake\".\n";
+ this->SetError(e.str().c_str());
+ return false;
}
- // Use copy-if-different if not appending.
- cmsys::auto_ptr<std::ofstream> foutPtr;
- if(this->Append.IsEnabled())
+ // Get the file to write.
+ std::string fname = this->Filename.GetString();
+ if(cmSystemTools::FileIsFullPath(fname.c_str()))
{
- cmsys::auto_ptr<std::ofstream> ap(
- new std::ofstream(this->Filename.GetString().c_str(), std::ios::app));
- foutPtr = ap;
+ if(!this->Makefile->CanIWriteThisFile(fname.c_str()))
+ {
+ cmOStringStream e;
+ e << "FILE option given filename \"" << fname
+ << "\" which is in the source tree.\n";
+ this->SetError(e.str().c_str());
+ return false;
+ }
}
else
{
- cmsys::auto_ptr<cmGeneratedFileStream> ap(
- new cmGeneratedFileStream(this->Filename.GetString().c_str(), true));
- ap->SetCopyIfDifferent(true);
- foutPtr = ap;
+ // Interpret relative paths with respect to the current build dir.
+ fname = this->Makefile->GetCurrentOutputDirectory();
+ fname += "/";
+ fname += this->Filename.GetString();
}
- std::ostream& fout = *foutPtr.get();
- if (!fout)
+ // If no targets are to be exported we are done.
+ if(this->Targets.GetVector().empty())
{
- cmSystemTools::Error("Error Writing ", this->Filename.GetString().c_str());
- cmSystemTools::ReportLastSystemError("");
return true;
}
- // the following code may move into an "export generator"
- // Compute the set of configurations.
- std::vector<std::string> configurationTypes;
- if(const char* types =
- this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
- {
- cmSystemTools::ExpandListArgument(types, configurationTypes);
- }
- if(configurationTypes.empty())
- {
- const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
- if (config!=0)
- {
- configurationTypes.push_back(config);
- }
- }
-
- for(std::vector<std::string>::const_iterator
+ // Collect the targets to be exported.
+ std::vector<cmTarget*> targets;
+ for(std::vector<std::string>::const_iterator
currentTarget = this->Targets.GetVector().begin();
currentTarget != this->Targets.GetVector().end();
++currentTarget)
{
- cmTarget* target = this->Makefile->GetLocalGenerator()->
- GetGlobalGenerator()->FindTarget(0, currentTarget->c_str(), true);
- if (target == 0)
+ if(cmTarget* target =
+ this->Makefile->GetLocalGenerator()->
+ GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))
+ {
+ if((target->GetType() == cmTarget::EXECUTABLE) ||
+ (target->GetType() == cmTarget::STATIC_LIBRARY) ||
+ (target->GetType() == cmTarget::SHARED_LIBRARY) ||
+ (target->GetType() == cmTarget::MODULE_LIBRARY))
+ {
+ targets.push_back(target);
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "given target \"" << *currentTarget
+ << "\" which is not an executable or library.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
+ else
{
- std::string e = "detected unknown target: " + *currentTarget;
- this->SetError(e.c_str());
- cmSystemTools::SetFatalErrorOccured();
+ cmOStringStream e;
+ e << "given target \"" << *currentTarget
+ << "\" which is not built by this project.";
+ this->SetError(e.str().c_str());
return false;
}
}
- for(std::vector<std::string>::const_iterator
- currentTarget = this->Targets.GetVector().begin();
- currentTarget != this->Targets.GetVector().end();
- ++currentTarget)
+ // Setup export file generation.
+ cmExportBuildFileGenerator ebfg;
+ ebfg.SetExportFile(fname.c_str());
+ ebfg.SetNamespace(this->Namespace.GetCString());
+ ebfg.SetExports(&targets);
+
+ // Compute the set of configurations exported.
+ if(const char* types =
+ this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
{
- // Look for a CMake target with the given name, which is an executable
- // and which can be run
- cmTarget* target = this->Makefile->GetLocalGenerator()->
- GetGlobalGenerator()->FindTarget(0, currentTarget->c_str(), true);
- if ((target != 0)
- && ((target->GetType() == cmTarget::EXECUTABLE)
- || (target->GetType() == cmTarget::STATIC_LIBRARY)
- || (target->GetType() == cmTarget::SHARED_LIBRARY)
- || (target->GetType() == cmTarget::MODULE_LIBRARY)))
+ std::vector<std::string> configurationTypes;
+ cmSystemTools::ExpandListArgument(types, configurationTypes);
+ for(std::vector<std::string>::const_iterator
+ ci = configurationTypes.begin();
+ ci != configurationTypes.end(); ++ci)
{
- switch (target->GetType())
- {
- case cmTarget::EXECUTABLE:
- fout << "ADD_EXECUTABLE("
- << this->Prefix.GetString().c_str() << currentTarget->c_str()
- << " IMPORT )\n";
- break;
- case cmTarget::STATIC_LIBRARY:
- fout << "ADD_LIBRARY("
- << this->Prefix.GetString().c_str() << currentTarget->c_str()
- << " STATIC IMPORT )\n";
- break;
- case cmTarget::SHARED_LIBRARY:
- fout << "ADD_LIBRARY("
- << this->Prefix.GetString().c_str() << currentTarget->c_str()
- << " SHARED IMPORT )\n";
- break;
- case cmTarget::MODULE_LIBRARY:
- fout << "ADD_LIBRARY("
- << this->Prefix.GetString().c_str() << currentTarget->c_str()
- << " MODULE IMPORT )\n";
- break;
- default: // should never happen
- break;
- }
-
- fout << "SET_TARGET_PROPERTIES(" << this->Prefix.GetString().c_str()
- << currentTarget->c_str() << " PROPERTIES \n"
- <<" LOCATION \""<< target->GetLocation(0)<<"\"\n";
- for(std::vector<std::string>::const_iterator
- currentConfig = configurationTypes.begin();
- currentConfig != configurationTypes.end();
- ++currentConfig)
- {
- if (!currentConfig->empty())
- {
- const char* loc = target->GetLocation(currentConfig->c_str());
- if (loc && *loc)
- {
- fout << " " << currentConfig->c_str()
- << "_LOCATION \"" << loc << "\"\n";
- }
- }
- }
- fout << " )\n\n";
+ ebfg.AddConfiguration(ci->c_str());
}
}
+ else if(const char* config =
+ this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"))
+ {
+ ebfg.AddConfiguration(config);
+ }
+ else
+ {
+ ebfg.AddConfiguration("");
+ }
+
+ // Generate the import file.
+ if(!ebfg.GenerateImportFile())
+ {
+ this->SetError("could not write export file.");
+ return false;
+ }
return true;
}
diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h
index c79f46d20b..f42450118a 100644
--- a/Source/cmExportCommand.h
+++ b/Source/cmExportCommand.h
@@ -55,7 +55,7 @@ public:
virtual const char* GetTerseDocumentation()
{
return
- "Write out the dependency information for all targets of a project.";
+ "Export targets from the build tree for use by outside projects.";
}
/**
@@ -64,15 +64,23 @@ public:
virtual const char* GetFullDocumentation()
{
return
- " export(TARGETS tgt1 ... tgtN [PREFIX <prefix>] FILE <filename> "
- "[APPEND])\n"
- "Create a file that can be included into a CMake listfile with the "
- "INCLUDE command. The file will contain a number of SET commands "
- "that will set all the variables needed for library dependency "
- "information. This should be the last command in the top level "
- "CMakeLists.txt file of the project. If the APPEND option is "
- "specified, the SET commands will be appended to the given file "
- "instead of replacing it.";
+ " export(TARGETS [target1 [target2 [...]]] [NAMESPACE <namespace>]\n"
+ " FILE <filename>)\n"
+ "Create a file <filename> that may be included by outside projects to "
+ "import targets from the current project's build tree. "
+ "This is useful during cross-compiling to build utility executables "
+ "that can run on the host platform in one project and then import "
+ "them into another project being compiled for the target platform. "
+ "If the NAMESPACE option is given the <namespace> string will be "
+ "prepended to all target names written to the file. "
+ "If a library target is included in the export but "
+ "a target to which it links is not included the behavior is "
+ "unspecified."
+ "\n"
+ "The file created by this command is specific to the build tree and "
+ "should never be installed. "
+ "See the install(EXPORT) command to export targets from an "
+ "installation tree.";
}
cmTypeMacro(cmExportCommand, cmCommand);
@@ -80,8 +88,7 @@ public:
private:
cmCommandArgumentGroup ArgumentGroup;
cmCAStringVector Targets;
- cmCAEnabler Append;
- cmCAString Prefix;
+ cmCAString Namespace;
cmCAString Filename;
};
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
new file mode 100644
index 0000000000..ec4bc33469
--- /dev/null
+++ b/Source/cmExportFileGenerator.cxx
@@ -0,0 +1,281 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmExportFileGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::AddConfiguration(const char* config)
+{
+ this->Configurations.push_back(config);
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::SetExportFile(const char* mainFile)
+{
+ this->MainImportFile = mainFile;
+ this->FileDir =
+ cmSystemTools::GetFilenamePath(this->MainImportFile);
+ this->FileBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile);
+ this->FileExt =
+ cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
+}
+
+//----------------------------------------------------------------------------
+bool cmExportFileGenerator::GenerateImportFile()
+{
+ // Open the output file to generate it.
+ cmGeneratedFileStream exportFileStream(this->MainImportFile.c_str(), true);
+ if(!exportFileStream)
+ {
+ std::string se = cmSystemTools::GetLastSystemError();
+ cmOStringStream e;
+ e << "cannot write to file \"" << this->MainImportFile
+ << "\": " << se;
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ std::ostream& os = exportFileStream;
+
+ // Start with the import file header.
+ this->GenerateImportHeaderCode(os);
+
+ // Create all the imported targets.
+ bool result = this->GenerateMainFile(os);
+
+ // End with the import file footer.
+ this->GenerateImportFooterCode(os);
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::GenerateImportConfig(std::ostream& os,
+ const char* config)
+{
+ // Construct the property configuration suffix.
+ std::string suffix = "_";
+ if(config && *config)
+ {
+ suffix += cmSystemTools::UpperCase(config);
+ }
+ else
+ {
+ suffix += "NOCONFIG";
+ }
+
+ // Generate the per-config target information.
+ this->GenerateImportTargetsConfig(os, config, suffix);
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportFileGenerator
+::SetImportDetailProperties(const char* config, std::string const& suffix,
+ cmTarget* target, ImportPropertyMap& properties)
+{
+ // Get the makefile in which to lookup target information.
+ cmMakefile* mf = target->GetMakefile();
+
+ // Add the soname for unix shared libraries.
+ if(target->GetType() == cmTarget::SHARED_LIBRARY ||
+ target->GetType() == cmTarget::MODULE_LIBRARY)
+ {
+ // Check whether this is a DLL platform.
+ bool dll_platform =
+ (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW"));
+ if(!dll_platform)
+ {
+ std::string soname = target->GetSOName(config);
+ std::string prop = "IMPORTED_SONAME";
+ prop += suffix;
+ properties[prop] = soname;
+ }
+ }
+
+ // Add the transitive link dependencies for this configuration.
+ {
+ // Compute which library configuration to link.
+ cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
+ if(config && cmSystemTools::UpperCase(config) == "DEBUG")
+ {
+ linkType = cmTarget::DEBUG;
+ }
+
+ // Construct the property value.
+ cmTarget::LinkLibraryVectorType const& libs =
+ target->GetOriginalLinkLibraries();
+ std::string link_libs;
+ const char* sep = "";
+ for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
+ li != libs.end(); ++li)
+ {
+ // Skip entries that will resolve to the target itself, are empty,
+ // or are not meant for this configuration.
+ if(li->first == target->GetName() || li->first.empty() ||
+ !(li->second == cmTarget::GENERAL || li->second == linkType))
+ {
+ continue;
+ }
+
+ // Separate this from the previous entry.
+ link_libs += sep;
+ sep = ";";
+
+ // Append this entry.
+ if(cmTarget* tgt = mf->FindTargetToUse(li->first.c_str()))
+ {
+ // This is a target. Make sure it is included in the export.
+ if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end())
+ {
+ // The target is in the export. Append it with the export
+ // namespace.
+ link_libs += this->Namespace;
+ link_libs += li->first;
+ }
+ else
+ {
+ // The target is not in the export. This is probably
+ // user-error. Warn but add it anyway.
+ this->ComplainAboutMissingTarget(target, li->first.c_str());
+ link_libs += li->first;
+ }
+ }
+ else
+ {
+ // Append the raw name.
+ link_libs += li->first;
+ }
+ }
+
+ // Store the property.
+ std::string prop = "IMPORTED_LINK_LIBRARIES";
+ prop += suffix;
+ properties[prop] = link_libs;
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
+ const char* config)
+{
+ os << "#----------------------------------------------------------------\n"
+ << "# Generated CMake target import file";
+ if(config)
+ {
+ os << " for configuration \"" << config << "\".\n";
+ }
+ else
+ {
+ os << ".\n";
+ }
+ os << "#----------------------------------------------------------------\n"
+ << "\n";
+ this->GenerateImportVersionCode(os);
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
+{
+ os << "# Commands beyond this point should not need to know the version.\n"
+ << "SET(CMAKE_IMPORT_FILE_VERSION)\n";
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
+{
+ // Store an import file format version. This will let us change the
+ // format later while still allowing old import files to work.
+ os << "# Commands may need to know the format version.\n"
+ << "SET(CMAKE_IMPORT_FILE_VERSION 1)\n"
+ << "\n";
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportFileGenerator
+::GenerateImportTargetCode(std::ostream& os, cmTarget* target)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+ targetName += target->GetName();
+
+ // Create the imported target.
+ os << "# Create imported target " << targetName << "\n";
+ switch(target->GetType())
+ {
+ case cmTarget::EXECUTABLE:
+ os << "ADD_EXECUTABLE(" << targetName << " IMPORTED)\n";
+ break;
+ case cmTarget::STATIC_LIBRARY:
+ os << "ADD_LIBRARY(" << targetName << " STATIC IMPORTED)\n";
+ break;
+ case cmTarget::SHARED_LIBRARY:
+ os << "ADD_LIBRARY(" << targetName << " SHARED IMPORTED)\n";
+ break;
+ case cmTarget::MODULE_LIBRARY:
+ os << "ADD_LIBRARY(" << targetName << " MODULE IMPORTED)\n";
+ break;
+ default: // should never happen
+ break;
+ }
+ if(target->IsExecutableWithExports())
+ {
+ os << "SET_PROPERTY(TARGET " << targetName
+ << " PROPERTY IMPORTED_ENABLE_EXPORTS 1)\n";
+ }
+ os << "\n";
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportFileGenerator
+::GenerateImportPropertyCode(std::ostream& os, const char* config,
+ cmTarget* target,
+ ImportPropertyMap const& properties)
+{
+ // Construct the imported target name.
+ std::string targetName = this->Namespace;
+ targetName += target->GetName();
+
+ // Set the import properties.
+ os << "# Import target \"" << targetName << "\" for configuration \""
+ << config << "\"\n";
+ os << "SET_PROPERTY(TARGET " << targetName
+ << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
+ if(config && *config)
+ {
+ os << cmSystemTools::UpperCase(config);
+ }
+ else
+ {
+ os << "NOCONFIG";
+ }
+ os << ")\n";
+ os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n";
+ for(ImportPropertyMap::const_iterator pi = properties.begin();
+ pi != properties.end(); ++pi)
+ {
+ os << " " << pi->first << " \"" << pi->second << "\"\n";
+ }
+ os << " )\n"
+ << "\n";
+}
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
new file mode 100644
index 0000000000..22592d72af
--- /dev/null
+++ b/Source/cmExportFileGenerator.h
@@ -0,0 +1,96 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmExportFileGenerator_h
+#define cmExportFileGenerator_h
+
+#include "cmCommand.h"
+
+/** \class cmExportFileGenerator
+ * \brief Generate a file exporting targets from a build or install tree.
+ *
+ * cmExportFileGenerator is the superclass for
+ * cmExportBuildFileGenerator and cmExportInstallFileGenerator. It
+ * contains common code generation routines for the two kinds of
+ * export implementations.
+ */
+class cmExportFileGenerator
+{
+public:
+ /** Set the full path to the export file to generate. */
+ void SetExportFile(const char* mainFile);
+
+ /** Set the namespace in which to place exported target names. */
+ void SetNamespace(const char* ns) { this->Namespace = ns; }
+
+ /** Add a configuration to be exported. */
+ void AddConfiguration(const char* config);
+
+ /** Actually generate the export file. Returns whether there was an
+ error. */
+ bool GenerateImportFile();
+protected:
+
+ typedef std::map<cmStdString, cmStdString> ImportPropertyMap;
+
+ // Generate per-configuration target information to the given output
+ // stream.
+ void GenerateImportConfig(std::ostream& os, const char* config);
+
+ // Methods to implement export file code generation.
+ void GenerateImportHeaderCode(std::ostream& os, const char* config = 0);
+ void GenerateImportFooterCode(std::ostream& os);
+ void GenerateImportVersionCode(std::ostream& os);
+ void GenerateImportTargetCode(std::ostream& os, cmTarget* target);
+ void GenerateImportPropertyCode(std::ostream& os, const char* config,
+ cmTarget* target,
+ ImportPropertyMap const& properties);
+
+ // Collect properties with detailed information about targets beyond
+ // their location on disk.
+ void SetImportDetailProperties(const char* config,
+ std::string const& suffix, cmTarget* target,
+ ImportPropertyMap& properties);
+
+ /** Each subclass knows how to generate its kind of export file. */
+ virtual bool GenerateMainFile(std::ostream& os) = 0;
+
+ /** Each subclass knows where the target files are located. */
+ virtual void GenerateImportTargetsConfig(std::ostream& os,
+ const char* config,
+ std::string const& suffix) = 0;
+
+ /** Each subclass knows how to complain about a target that is
+ missing from an export set. */
+ virtual void ComplainAboutMissingTarget(cmTarget*, const char* dep) = 0;
+
+ // The namespace in which the exports are placed in the generated file.
+ std::string Namespace;
+
+ // The set of configurations to export.
+ std::vector<std::string> Configurations;
+
+ // The file to generate.
+ std::string MainImportFile;
+ std::string FileDir;
+ std::string FileBase;
+ std::string FileExt;
+
+ // The set of targets included in the export.
+ std::set<cmTarget*> ExportedTargets;
+};
+
+#endif
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
new file mode 100644
index 0000000000..8266a9605a
--- /dev/null
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -0,0 +1,259 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmExportInstallFileGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallTargetGenerator.h"
+
+//----------------------------------------------------------------------------
+cmExportInstallFileGenerator
+::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
+ InstallExportGenerator(iegen)
+{
+}
+
+//----------------------------------------------------------------------------
+bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
+{
+ // Create all the imported targets.
+ for(std::vector<cmTargetExport*>::const_iterator
+ tei = this->ExportSet->begin();
+ tei != this->ExportSet->end(); ++tei)
+ {
+ cmTargetExport* te = *tei;
+ this->ExportedTargets.insert(te->Target);
+ this->GenerateImportTargetCode(os, te->Target);
+ }
+
+ // Now load per-configuration properties for them.
+ os << "# Load information for each installed configuration.\n"
+ << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
+ << "FILE(GLOB CONFIG_FILES \"${_DIR}/"
+ << this->FileBase << "-*" << this->FileExt << "\")\n"
+ << "FOREACH(f ${CONFIG_FILES})\n"
+ << " INCLUDE(${f})\n"
+ << "ENDFOREACH(f)\n"
+ << "\n";
+
+ // Generate an import file for each configuration.
+ bool result = true;
+ for(std::vector<std::string>::const_iterator
+ ci = this->Configurations.begin();
+ ci != this->Configurations.end(); ++ci)
+ {
+ if(!this->GenerateImportFileConfig(ci->c_str()))
+ {
+ result = false;
+ }
+ }
+ return result;
+}
+
+//----------------------------------------------------------------------------
+bool
+cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config)
+{
+ // Skip configurations not enabled for this export.
+ if(!this->InstallExportGenerator->InstallsForConfig(config))
+ {
+ return true;
+ }
+
+ // Construct the name of the file to generate.
+ std::string fileName = this->FileDir;
+ fileName += "/";
+ fileName += this->FileBase;
+ fileName += "-";
+ if(config && *config)
+ {
+ fileName += cmSystemTools::LowerCase(config);
+ }
+ else
+ {
+ fileName += "noconfig";
+ }
+ fileName += this->FileExt;
+
+ // Open the output file to generate it.
+ cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
+ if(!exportFileStream)
+ {
+ std::string se = cmSystemTools::GetLastSystemError();
+ cmOStringStream e;
+ e << "cannot write to file \"" << fileName.c_str()
+ << "\": " << se;
+ cmSystemTools::Error(e.str().c_str());
+ return false;
+ }
+ std::ostream& os = exportFileStream;
+
+ // Start with the import file header.
+ this->GenerateImportHeaderCode(os, config);
+
+ // Generate the per-config target information.
+ this->GenerateImportConfig(os, config);
+
+ // End with the import file footer.
+ this->GenerateImportFooterCode(os);
+
+ // Record this per-config import file.
+ this->ConfigImportFiles[config] = fileName;
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportInstallFileGenerator
+::GenerateImportTargetsConfig(std::ostream& os,
+ const char* config, std::string const& suffix)
+{
+ // Add code to compute the installation prefix relative to the
+ // import file location.
+ const char* installDest = this->InstallExportGenerator->GetDestination();
+ if(!cmSystemTools::FileIsFullPath(installDest))
+ {
+ std::string dest = installDest;
+ os << "# Compute the installation prefix relative to this file.\n"
+ << "GET_FILENAME_COMPONENT(_IMPORT_PREFIX "
+ << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
+ while(!dest.empty())
+ {
+ os <<
+ "GET_FILENAME_COMPONENT(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
+ dest = cmSystemTools::GetFilenamePath(dest);
+ }
+ os << "\n";
+
+ // Import location properties may reference this variable.
+ this->ImportPrefix = "${_IMPORT_PREFIX}/";
+ }
+
+ // Add each target in the set to the export.
+ for(std::vector<cmTargetExport*>::const_iterator
+ tei = this->ExportSet->begin();
+ tei != this->ExportSet->end(); ++tei)
+ {
+ // Collect import properties for this target.
+ cmTargetExport* te = *tei;
+ ImportPropertyMap properties;
+ this->SetImportLocationProperty(config, suffix,
+ te->ArchiveGenerator, properties);
+ this->SetImportLocationProperty(config, suffix,
+ te->LibraryGenerator, properties);
+ this->SetImportLocationProperty(config, suffix,
+ te->RuntimeGenerator, properties);
+
+ // TODO: Frameworks?
+ // TODO: Bundles?
+
+ // If any file location was set for the target add it to the
+ // import file.
+ if(!properties.empty())
+ {
+ // Get the rest of the target details.
+ this->SetImportDetailProperties(config, suffix,
+ te->Target, properties);
+
+ // TOOD: PUBLIC_HEADER_LOCATION
+ // this->GenerateImportProperty(config, te->HeaderGenerator,
+ // properties);
+
+ // Generate code in the export file.
+ this->GenerateImportPropertyCode(os, config, te->Target, properties);
+ }
+ }
+
+ // Cleanup the import prefix variable.
+ if(!this->ImportPrefix.empty())
+ {
+ os << "# Cleanup temporary variables.\n"
+ << "SET(_IMPORT_PREFIX)\n"
+ << "\n";
+ }
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportInstallFileGenerator
+::SetImportLocationProperty(const char* config, std::string const& suffix,
+ cmInstallTargetGenerator* itgen,
+ ImportPropertyMap& properties)
+{
+ // Skip rules that do not match this configuration.
+ if(!(itgen && itgen->InstallsForConfig(config)))
+ {
+ return;
+ }
+
+ {
+ // Construct the property name.
+ std::string prop = (itgen->IsImportLibrary()?
+ "IMPORTED_IMPLIB" : "IMPORTED_LOCATION");
+ prop += suffix;
+
+ // Construct the installed location of the target.
+ std::string dest = itgen->GetDestination();
+ std::string value;
+ if(!cmSystemTools::FileIsFullPath(dest.c_str()))
+ {
+ // The target is installed relative to the installation prefix.
+ if(this->ImportPrefix.empty())
+ {
+ this->ComplainAboutImportPrefix(itgen);
+ }
+ value = this->ImportPrefix;
+ }
+ value += dest;
+ value += "/";
+
+ // Append the installed file name.
+ value += itgen->GetInstallFilename(config);
+
+ // Store the property.
+ properties[prop] = value;
+ }
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportInstallFileGenerator
+::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
+{
+ const char* installDest = this->InstallExportGenerator->GetDestination();
+ cmOStringStream e;
+ e << "INSTALL(EXPORT \"" << this->Name << "\") given absolute "
+ << "DESTINATION \"" << installDest << "\" but the export "
+ << "references an installation of target \""
+ << itgen->GetTarget()->GetName() << "\" which has relative "
+ << "DESTINATION \"" << itgen->GetDestination() << "\".";
+ cmSystemTools::Error(e.str().c_str());
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportInstallFileGenerator
+::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
+{
+ cmOStringStream e;
+ e << "WARNING: INSTALL(EXPORT \"" << this->Name << "\" ...) "
+ << "includes target " << target->GetName()
+ << " which links to target \"" << dep
+ << "\" that is not in the export set.";
+ cmSystemTools::Message(e.str().c_str());
+}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
new file mode 100644
index 0000000000..ecae0b7c25
--- /dev/null
+++ b/Source/cmExportInstallFileGenerator.h
@@ -0,0 +1,122 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmExportInstallFileGenerator_h
+#define cmExportInstallFileGenerator_h
+
+#include "cmExportFileGenerator.h"
+
+class cmInstallExportGenerator;
+class cmInstallFilesGenerator;
+class cmInstallTargetGenerator;
+class cmTargetExport;
+
+/** \class cmExportInstallFileGenerator
+ * \brief Generate a file exporting targets from an install tree.
+ *
+ * cmExportInstallFileGenerator generates files exporting targets from
+ * install an installation tree. The files are placed in a temporary
+ * location for installation by cmInstallExportGenerator. One main
+ * file is generated that creates the imported targets and loads
+ * per-configuration files. Target locations and settings for each
+ * configuration are written to these per-configuration files. After
+ * installation the main file loads the configurations that have been
+ * installed.
+ *
+ * This is used to implement the INSTALL(EXPORT) command.
+ */
+class cmExportInstallFileGenerator: public cmExportFileGenerator
+{
+public:
+ /** Construct with the export installer that will install the
+ files. */
+ cmExportInstallFileGenerator(cmInstallExportGenerator* iegen);
+
+ /** Set the name of the export associated with the files. This is
+ the name given to the install(EXPORT) command mode. */
+ void SetName(const char* name) { this->Name = name; }
+
+ /** Set the set of targets to be exported. These are the targets
+ associated with the export name. */
+ void SetExportSet(std::vector<cmTargetExport*> const* eSet)
+ { this->ExportSet = eSet; }
+
+ /** Get the per-config file generated for each configuraiton. This
+ maps from the configuration name to the file temporary location
+ for installation. */
+ std::map<cmStdString, cmStdString> const& GetConfigImportFiles()
+ { return this->ConfigImportFiles; }
+protected:
+
+ // Implement virtual methods from the superclass.
+ virtual bool GenerateMainFile(std::ostream& os);
+ virtual void GenerateImportTargetsConfig(std::ostream& os,
+ const char* config,
+ std::string const& suffix);
+ virtual void ComplainAboutMissingTarget(cmTarget* target, const char* dep);
+
+ /** Generate a per-configuration file for the targets. */
+ bool GenerateImportFileConfig(const char* config);
+
+ /** Fill in properties indicating installed file locations. */
+ void SetImportLocationProperty(const char* config,
+ std::string const& suffix,
+ cmInstallTargetGenerator* itgen,
+ ImportPropertyMap& properties);
+
+ void ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen);
+
+ cmInstallExportGenerator* InstallExportGenerator;
+ std::string Name;
+ std::vector<cmTargetExport*> const* ExportSet;
+
+ std::string ImportPrefix;
+
+ // The import file generated for each configuration.
+ std::map<cmStdString, cmStdString> ConfigImportFiles;
+};
+
+/*
+ cmTargetExport is used in cmGlobalGenerator to collect the install
+ generators for targets associated with an export.
+*/
+class cmTargetExport
+{
+public:
+ cmTargetExport(cmTarget* tgt,
+ cmInstallTargetGenerator* archive,
+ cmInstallTargetGenerator* runtime,
+ cmInstallTargetGenerator* library,
+ cmInstallTargetGenerator* framework,
+ cmInstallTargetGenerator* bundle,
+ cmInstallFilesGenerator* headers
+ ) : Target(tgt), ArchiveGenerator(archive),
+ RuntimeGenerator(runtime), LibraryGenerator(library),
+ FrameworkGenerator(framework), BundleGenerator(bundle),
+ HeaderGenerator(headers) {}
+
+ cmTarget* Target;
+ cmInstallTargetGenerator* ArchiveGenerator;
+ cmInstallTargetGenerator* RuntimeGenerator;
+ cmInstallTargetGenerator* LibraryGenerator;
+ cmInstallTargetGenerator* FrameworkGenerator;
+ cmInstallTargetGenerator* BundleGenerator;
+ cmInstallFilesGenerator* HeaderGenerator;
+private:
+ cmTargetExport();
+};
+
+#endif
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
index 0a37b97495..7622cf231a 100644
--- a/Source/cmGetPropertyCommand.cxx
+++ b/Source/cmGetPropertyCommand.cxx
@@ -260,9 +260,7 @@ bool cmGetPropertyCommand::HandleTargetMode()
return false;
}
- if(cmTarget* target =
- this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
- ->FindTarget(0, this->Name.c_str(), true))
+ if(cmTarget* target = this->Makefile->FindTargetToUse(this->Name.c_str()))
{
return this->StoreResult(target->GetProperty(this->PropertyName.c_str()));
}
diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx
index 963e16ad5a..97b4d7f506 100644
--- a/Source/cmGetTargetPropertyCommand.cxx
+++ b/Source/cmGetTargetPropertyCommand.cxx
@@ -28,9 +28,7 @@ bool cmGetTargetPropertyCommand
std::string var = args[0].c_str();
const char* targetName = args[1].c_str();
- cmTarget *tgt = this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
- ->FindTarget(0, targetName, true);
- if (tgt)
+ if(cmTarget* tgt = this->Makefile->FindTargetToUse(targetName))
{
cmTarget& target = *tgt;
const char *prop = target.GetProperty(args[2].c_str());
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 448d4575c4..6c1af53212 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -25,7 +25,7 @@
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmVersion.h"
-#include "cmInstallExportGenerator.h"
+#include "cmExportInstallFileGenerator.h"
#include <cmsys/Directory.hxx>
@@ -693,7 +693,6 @@ void cmGlobalGenerator::Configure()
this->LocalGenerators.clear();
this->TargetDependencies.clear();
this->TotalTargets.clear();
- this->ImportedTotalTargets.clear();
this->LocalGeneratorToTargetMap.clear();
this->ProjectMap.clear();
@@ -1321,9 +1320,8 @@ cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir)
//----------------------------------------------------------------------------
-cmTarget* cmGlobalGenerator::FindTarget(const char* project,
- const char* name,
- bool useImportedTargets)
+cmTarget*
+cmGlobalGenerator::FindTarget(const char* project, const char* name)
{
// if project specific
if(project)
@@ -1331,8 +1329,7 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project,
std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project];
for(unsigned int i = 0; i < gens->size(); ++i)
{
- cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name,
- useImportedTargets);
+ cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name);
if(ret)
{
return ret;
@@ -1348,16 +1345,6 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project,
{
return i->second;
}
-
- if ( useImportedTargets )
- {
- std::map<cmStdString,cmTarget *>::iterator importedTarget =
- this->ImportedTotalTargets.find ( name );
- if ( importedTarget != this->ImportedTotalTargets.end() )
- {
- return importedTarget->second;
- }
- }
}
return 0;
}
@@ -1370,7 +1357,7 @@ bool cmGlobalGenerator::NameResolvesToFramework(const std::string& libname)
return true;
}
- if(cmTarget* tgt = this->FindTarget(0, libname.c_str(), true))
+ if(cmTarget* tgt = this->FindTarget(0, libname.c_str()))
{
if(tgt->GetType() == cmTarget::SHARED_LIBRARY &&
tgt->GetPropertyAsBool("FRAMEWORK"))
@@ -1758,12 +1745,12 @@ cmGlobalGenerator::ConsiderTargetDepends(cmTarget const* depender,
{
// Check the target's makefile first.
cmTarget const* dependee =
- depender->GetMakefile()->FindTarget(dependee_name, false);
+ depender->GetMakefile()->FindTarget(dependee_name);
// Then search globally.
if(!dependee)
{
- dependee = this->FindTarget(0, dependee_name, false);
+ dependee = this->FindTarget(0, dependee_name);
}
// If not found then skip then the dependee.
@@ -1842,14 +1829,8 @@ cmGlobalGenerator
void cmGlobalGenerator::AddTarget(cmTargets::value_type &v)
{
- if (v.second.IsImported())
- {
- this->ImportedTotalTargets[v.first] = &v.second;
- }
- else
- {
- this->TotalTargets[v.first] = &v.second;
- }
+ assert(!v.second.IsImported());
+ this->TotalTargets[v.first] = &v.second;
}
void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index dfbf1ad211..4654a410ae 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -186,9 +186,7 @@ public:
void FindMakeProgram(cmMakefile*);
///! Find a target by name by searching the local generators.
- cmTarget* FindTarget(const char* project,
- const char* name,
- bool useImportedTargets);
+ cmTarget* FindTarget(const char* project, const char* name);
/** Determine if a name resolves to a framework on disk or a built target
that is a framework. */
@@ -297,9 +295,8 @@ private:
std::map<cmStdString, cmStdString> ExtensionToLanguage;
std::map<cmStdString, int> LanguageToLinkerPreference;
- // this is used to improve performance
+ // this is used to improve performance
std::map<cmStdString,cmTarget *> TotalTargets;
- std::map<cmStdString,cmTarget *> ImportedTotalTargets;
cmExternalMakefileProjectGenerator* ExtraGenerator;
diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx
index f7b4137b92..723ac7cf05 100644
--- a/Source/cmGlobalVisualStudio6Generator.cxx
+++ b/Source/cmGlobalVisualStudio6Generator.cxx
@@ -399,7 +399,7 @@ void cmGlobalVisualStudio6Generator::WriteProject(std::ostream& fout,
if(j->first != dspname)
{
// is the library part of this DSW ? If so add dependency
- if(this->FindTarget(0, j->first.c_str(), false))
+ if(this->FindTarget(0, j->first.c_str()))
{
fout << "Begin Project Dependency\n";
fout << "Project_Dep_Name " << j->first.c_str() << "\n";
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index 2c35a418f0..48efee19a2 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -338,8 +338,7 @@ cmGlobalVisualStudio71Generator
if(j->first != dspname)
{
// is the library part of this SLN ? If so add dependency
- if(this->FindTarget(this->CurrentProject.c_str(),
- j->first.c_str(), false))
+ if(this->FindTarget(this->CurrentProject.c_str(), j->first.c_str()))
{
fout << "\t\t{" << this->GetGUID(j->first.c_str()) << "} = {"
<< this->GetGUID(j->first.c_str()) << "}\n";
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 1b95e2ac6b..f3dcc60f31 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -611,8 +611,7 @@ cmGlobalVisualStudio7Generator
if(j->first != dspname)
{
// is the library part of this SLN ? If so add dependency
- if(this->FindTarget(this->CurrentProject.c_str(),
- j->first.c_str(), false))
+ if(this->FindTarget(this->CurrentProject.c_str(), j->first.c_str()))
{
std::string guid = this->GetGUID(j->first.c_str());
if(guid.size() == 0)
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index 31b3ab4686..7a394595da 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -138,7 +138,7 @@ void cmGlobalVisualStudio8Generator::Generate()
mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
no_working_directory, no_depends,
noCommandLines);
- cmTarget* tgt = mf->FindTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false);
+ cmTarget* tgt = mf->FindTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
if(!tgt)
{
cmSystemTools::Error("Error adding target "
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 2319b047b2..b824590cb2 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -270,7 +270,7 @@ cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target)
target.GetUtilities().begin();
ui != target.GetUtilities().end(); ++ui)
{
- if(cmTarget* depTarget = this->FindTarget(0, ui->c_str(), false))
+ if(cmTarget* depTarget = this->FindTarget(0, ui->c_str()))
{
if(depTarget->GetType() == cmTarget::STATIC_LIBRARY ||
depTarget->GetType() == cmTarget::SHARED_LIBRARY ||
@@ -315,7 +315,7 @@ cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget& target)
this->CreateGUID(altNameStr.c_str());
// The intermediate target should depend on the original target.
- if(cmTarget* alt = this->FindTarget(0, altNameStr.c_str(), false))
+ if(cmTarget* alt = this->FindTarget(0, altNameStr.c_str()))
{
alt->AddUtility(target.GetName());
}
@@ -371,7 +371,7 @@ cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target,
{
// The depender is a target that links. Lookup the dependee to
// see if it provides an alternative dependency name.
- if(cmTarget* depTarget = this->FindTarget(0, name, false))
+ if(cmTarget* depTarget = this->FindTarget(0, name))
{
// Check for an alternative name created by FixUtilityDepends.
if(const char* altName =
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index cc7e7f8cfe..19394f253a 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -279,7 +279,7 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
no_working_directory,
"echo", "Build all projects");
- cmTarget* allbuild = mf->FindTarget("ALL_BUILD", false);
+ cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
// Add XCODE depend helper
std::string dir = mf->GetCurrentOutputDirectory();
@@ -1346,7 +1346,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string pnprefix;
std::string pnbase;
std::string pnsuffix;
- target.GetFullName(pnprefix, pnbase, pnsuffix, configName);
+ target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
// Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME",
@@ -2046,7 +2046,7 @@ void cmGlobalXCodeGenerator
{
// Add this dependency.
cmTarget* t = this->FindTarget(this->CurrentProject.c_str(),
- lib->first.c_str(), false);
+ lib->first.c_str());
cmXCodeObject* dptarget = this->FindXCodeTarget(t);
if(dptarget)
{
@@ -2062,7 +2062,7 @@ void cmGlobalXCodeGenerator
i != cmtarget->GetUtilities().end(); ++i)
{
cmTarget* t = this->FindTarget(this->CurrentProject.c_str(),
- i->c_str(), false);
+ i->c_str());
// if the target is in this project then make target depend
// on it. It may not be in this project if this is a sub
// project from the top.
diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx
index d1f2a78aea..2ab46c830e 100644
--- a/Source/cmIncludeExternalMSProjectCommand.cxx
+++ b/Source/cmIncludeExternalMSProjectCommand.cxx
@@ -51,8 +51,7 @@ bool cmIncludeExternalMSProjectCommand
// Create a target instance for this utility.
cmTarget* target=this->Makefile->AddNewTarget(cmTarget::UTILITY,
- utility_name.c_str(),
- false);
+ utility_name.c_str());
target->SetProperty("EXCLUDE_FROM_ALL","FALSE");
std::vector<std::string> no_outputs;
cmCustomCommandLines commandLines;
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 915cd4b3f7..6c742b9484 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -300,7 +300,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
++targetIt)
{
// Lookup this target in the current directory.
- if(cmTarget* target=this->Makefile->FindTarget(targetIt->c_str(), false))
+ if(cmTarget* target=this->Makefile->FindTarget(targetIt->c_str()))
{
// Found the target. Check its type.
if(target->GetType() != cmTarget::EXECUTABLE &&
@@ -489,7 +489,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// library. Install it to the archive destination if it
// exists.
if(dll_platform && !archiveArgs.GetDestination().empty() &&
- target.GetPropertyAsBool("ENABLE_EXPORTS"))
+ target.IsExecutableWithExports())
{
// The import library uses the ARCHIVE properties.
archiveGenerator = CreateInstallTargetGenerator(target,
@@ -1069,13 +1069,9 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
return false;
}
- // Compute destination path.
- std::string dest;
- cmInstallCommandArguments::ComputeDestination(destination, dest);
-
// Create the directory install generator.
this->Makefile->AddInstallGenerator(
- new cmInstallDirectoryGenerator(dirs, dest.c_str(),
+ new cmInstallDirectoryGenerator(dirs, destination,
permissions_file.c_str(),
permissions_dir.c_str(),
configurations,
@@ -1095,12 +1091,12 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
{
// This is the EXPORT mode.
cmInstallCommandArguments ica;
- cmCAStringVector exports(&ica.Parser, "EXPORT");
- cmCAString prefix(&ica.Parser, "PREFIX", &ica.ArgumentGroup);
+ cmCAString exp(&ica.Parser, "EXPORT");
+ cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
- exports.Follows(0);
+ exp.Follows(0);
- ica.ArgumentGroup.Follows(&exports);
+ ica.ArgumentGroup.Follows(&exp);
std::vector<std::string> unknownArgs;
ica.Parse(&args, &unknownArgs);
@@ -1118,44 +1114,66 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
return false;
}
- std::string cmakeDir = this->Makefile->GetHomeOutputDirectory();
- cmakeDir += cmake::GetCMakeFilesDirectory();
- for(std::vector<std::string>::const_iterator
- exportIt = exports.GetVector().begin();
- exportIt != exports.GetVector().end();
- ++exportIt)
+ // Make sure there is a destination.
+ if(ica.GetDestination().empty())
{
- const std::vector<cmTargetExport*>* exportSet = this->
- Makefile->GetLocalGenerator()->GetGlobalGenerator()->
- GetExportSet(exportIt->c_str());
- if (exportSet == 0)
- {
- cmOStringStream e;
- e << "EXPORT given unknown export name \"" << exportIt->c_str() << "\".";
- this->SetError(e.str().c_str());
- return false;
- }
+ // A destination is required.
+ cmOStringStream e;
+ e << args[0] << " given no DESTINATION!";
+ this->SetError(e.str().c_str());
+ return false;
+ }
- // Create the export install generator.
- cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
- ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
- ica.GetConfigurations(),0 , filename.GetCString(),
- prefix.GetCString(), cmakeDir.c_str());
+ // Check the file name.
+ std::string fname = filename.GetString();
+ if(fname.find_first_of(":/\\") != fname.npos)
+ {
+ cmOStringStream e;
+ e << args[0] << " given invalid export file name \"" << fname << "\". "
+ << "The FILE argument may not contain a path. "
+ << "Specify the path in the DESTINATION argument.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
- if (exportGenerator->SetExportSet(exportIt->c_str(),exportSet))
- {
- this->Makefile->AddInstallGenerator(exportGenerator);
- }
- else
+ // Check the file extension.
+ if(!fname.empty() &&
+ cmSystemTools::GetFilenameLastExtension(fname) != ".cmake")
+ {
+ cmOStringStream e;
+ e << args[0] << " given invalid export file name \"" << fname << "\". "
+ << "The FILE argument must specify a name ending in \".cmake\".";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Construct the file name.
+ if(fname.empty())
+ {
+ fname = exp.GetString();
+ fname += ".cmake";
+
+ if(fname.find_first_of(":/\\") != fname.npos)
{
cmOStringStream e;
- e << "EXPORT failed, maybe a target is exported more than once.";
+ e << args[0] << " given export name \"" << exp.GetString() << "\". "
+ << "This name cannot be safely converted to a file name. "
+ << "Specify a different export name or use the FILE option to set "
+ << "a file name explicitly.";
this->SetError(e.str().c_str());
- delete exportGenerator;
return false;
}
}
+ // Create the export install generator.
+ cmInstallExportGenerator* exportGenerator =
+ new cmInstallExportGenerator(
+ exp.GetCString(), ica.GetDestination().c_str(),
+ ica.GetPermissions().c_str(), ica.GetConfigurations(),
+ ica.GetComponent().c_str(), fname.c_str(),
+ name_space.GetCString(), this->Makefile);
+ this->Makefile->AddInstallGenerator(exportGenerator);
+
return true;
}
diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h
index f0f69e0493..0f5eb16fa6 100644
--- a/Source/cmInstallCommand.h
+++ b/Source/cmInstallCommand.h
@@ -98,7 +98,7 @@ public:
"file to be installed does not exist. "
"\n"
"The TARGETS signature:\n"
- " install(TARGETS targets...\n"
+ " install(TARGETS targets... [EXPORT <export-name>]\n"
" [[ARCHIVE|LIBRARY|RUNTIME]\n"
" [DESTINATION <dir>]\n"
" [PERMISSIONS permissions...]\n"
@@ -145,6 +145,12 @@ public:
"On non-DLL platforms mySharedLib will be installed to <prefix>/lib "
"and /some/full/path."
"\n"
+ "The EXPORT option associates the installed target files with an "
+ "export called <export-name>. "
+ "It must appear before any RUNTIME, LIBRARY, or ARCHIVE options. "
+ "See documentation of the install(EXPORT ...) signature below for "
+ "details."
+ "\n"
"Installing a target with EXCLUDE_FROM_ALL set to true has "
"undefined behavior."
"\n"
@@ -248,6 +254,45 @@ public:
"For example, the code\n"
" install(CODE \"MESSAGE(\\\"Sample install message.\\\")\")\n"
"will print a message during installation.\n"
+ ""
+ "The EXPORT signature:\n"
+ " install(EXPORT <export-name> DESTINATION <dir>\n"
+ " [NAMESPACE <namespace>] [FILE <name>.cmake]\n"
+ " [PERMISSIONS permissions...]\n"
+ " [CONFIGURATIONS [Debug|Release|...]]\n"
+ " [COMPONENT <component>])\n"
+ "The EXPORT form generates and installs a CMake file containing code "
+ "to import targets from the installation tree into another project. "
+ "Target installations are associated with the export <export-name> "
+ "using the EXPORT option of the install(TARGETS ...) signature "
+ "documented above. The NAMESPACE option will prepend <namespace> to "
+ "the target names as they are written to the import file. "
+ "By default the generated file will be called <export-name>.cmake but "
+ "the FILE option may be used to specify a different name. The value "
+ "given to the FILE option must be a file name with the \".cmake\" "
+ "extension. "
+ "If a CONFIGURATIONS option is given then the file will only be "
+ "installed when one of the named configurations is installed. "
+ "Additionally, the generated import file will reference only the "
+ "matching target configurations. "
+ "If a COMPONENT option is specified that does not match that given "
+ "to the targets associated with <export-name> the behavior is "
+ "undefined. "
+ "If a library target is included in the export but "
+ "a target to which it links is not included the behavior is "
+ "unspecified."
+ "\n"
+ "The EXPORT form is useful to help outside projects use targets built "
+ "and installed by the current project. For example, the code\n"
+ " install(TARGETS myexe EXPORT myproj DESTINATION bin)\n"
+ " install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj)\n"
+ "will install the executable myexe to <prefix>/bin and code to import "
+ "it in the file \"<prefix>/lib/myproj/myproj.cmake\". "
+ "An outside project may load this file with the include command "
+ "and reference the myexe executable from the installation tree using "
+ "the imported target name mp_myexe as if the target were built "
+ "in its own tree."
+ "\n"
"NOTE: This command supercedes the INSTALL_TARGETS command and the "
"target properties PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT. "
"It also replaces the FILES forms of the INSTALL_FILES and "
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
index 9cba5bf896..506954c8b0 100644
--- a/Source/cmInstallCommandArguments.cxx
+++ b/Source/cmInstallCommandArguments.cxx
@@ -44,9 +44,9 @@ cmInstallCommandArguments::cmInstallCommandArguments()
const std::string& cmInstallCommandArguments::GetDestination() const
{
- if (!this->AbsDestination.empty())
+ if (!this->DestinationString.empty())
{
- return this->AbsDestination;
+ return this->DestinationString;
}
if (this->GenericArguments!=0)
{
@@ -128,8 +128,8 @@ bool cmInstallCommandArguments::Finalize()
{
return false;
}
- this->ComputeDestination(this->Destination.GetString(),this->AbsDestination);
-
+ this->DestinationString = this->Destination.GetString();
+ cmSystemTools::ConvertToUnixSlashes(this->DestinationString);
return true;
}
@@ -174,23 +174,3 @@ bool cmInstallCommandArguments::CheckPermissions(
// This is not a valid permission.
return false;
}
-
-//----------------------------------------------------------------------------
-void cmInstallCommandArguments::ComputeDestination(const std::string& inDest,
- std::string& absDest)
-{
- if((inDest.size()>0) && !(cmSystemTools::FileIsFullPath(inDest.c_str())))
- {
- // Relative paths are treated with respect to the installation prefix.
- absDest = "${CMAKE_INSTALL_PREFIX}/";
- absDest += inDest;
- }
- else
- {
- // Full paths are absolute.
- absDest = inDest;
- }
- // Format the path nicely. Note this also removes trailing slashes.
- cmSystemTools::ConvertToUnixSlashes(absDest);
-}
-
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
index 430e5378df..7fc35a0c18 100644
--- a/Source/cmInstallCommandArguments.h
+++ b/Source/cmInstallCommandArguments.h
@@ -43,8 +43,6 @@ class cmInstallCommandArguments
// once HandleDirectoryMode() is also switched to using
// cmInstallCommandArguments then these two functions can become non-static
// private member functions without arguments
- static void ComputeDestination(const std::string& inDest,
- std::string& absDest);
static bool CheckPermissions(const std::string& onePerm,
std::string& perm);
cmCommandArgumentsHelper Parser;
@@ -57,7 +55,7 @@ class cmInstallCommandArguments
cmCAStringVector Configurations;
cmCAEnabler Optional;
- std::string AbsDestination;
+ std::string DestinationString;
std::string PermissionsString;
cmInstallCommandArguments* GenericArguments;
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index 350a4fdd28..110e6b6284 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -48,8 +48,7 @@ cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
bool not_optional = false;
const char* no_properties = 0;
const char* no_rename = 0;
- this->AddInstallRule(os, this->Destination.c_str(),
- cmTarget::INSTALL_DIRECTORY,
+ this->AddInstallRule(os, cmTarget::INSTALL_DIRECTORY,
this->Directories,
not_optional, no_properties,
this->FilePermissions.c_str(),
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index ed04ebcedb..81971aaac1 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -14,259 +14,198 @@
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
+#include "cmInstallExportGenerator.h"
#include <stdio.h>
+#include "cmake.h"
#include "cmInstallTargetGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmTarget.h"
+#include "cmMakefile.h"
+#include "cmLocalGenerator.h"
+#include "cmGlobalGenerator.h"
-#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
+#include "cmExportInstallFileGenerator.h"
+
+//----------------------------------------------------------------------------
cmInstallExportGenerator::cmInstallExportGenerator(
+ const char* name,
const char* destination,
const char* file_permissions,
std::vector<std::string> const& configurations,
const char* component,
- const char* filename, const char* prefix, const char* tempOutputDir)
+ const char* filename, const char* name_space,
+ cmMakefile* mf)
:cmInstallGenerator(destination, configurations, component)
+ ,Name(name)
,FilePermissions(file_permissions)
- ,Filename(filename)
- ,Prefix(prefix)
- ,TempOutputDir(tempOutputDir)
+ ,FileName(filename)
+ ,Namespace(name_space)
+ ,Makefile(mf)
+{
+ this->EFGen = new cmExportInstallFileGenerator(this);
+}
+
+//----------------------------------------------------------------------------
+cmInstallExportGenerator::~cmInstallExportGenerator()
{
+ delete this->EFGen;
}
-/* Helper function which adds the install locations from the generator
-to the properties for this target.
-*/
-bool cmInstallExportGenerator::AddInstallLocations(cmTargetWithProperties* twp,
- cmInstallTargetGenerator* generator,
- const char* prefix)
+//----------------------------------------------------------------------------
+void cmInstallExportGenerator::ComputeTempDir()
{
- if (generator == 0) // nothing to do
+ // Choose a temporary directory in which to generate the import
+ // files to be installed.
+ this->TempDir = this->Makefile->GetCurrentOutputDirectory();
+ this->TempDir += cmake::GetCMakeFilesDirectory();
+ this->TempDir += "/Export";
+ if(this->Destination.empty())
{
- return true;
+ return;
}
-
- if (prefix == 0)
+ else
{
- prefix = "";
+ this->TempDir += "/";
}
- const std::vector<std::string>& configs = generator->GetConfigurations();
- if (configs.empty())
+ // Enforce a maximum length.
+ bool useMD5 = false;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ std::string::size_type const max_total_len = 250;
+#else
+ std::string::size_type const max_total_len = 1000;
+#endif
+ if(this->TempDir.size() < max_total_len)
{
- std::string propertyName = prefix;
- propertyName += "LOCATION";
- // check that this property doesn't exist yet and add it then
- if (twp->Properties.find(propertyName.c_str()) == twp->Properties.end())
+ // Keep the total path length below the limit.
+ std::string::size_type max_len = max_total_len - this->TempDir.size();
+ if(this->Destination.size() > max_len)
{
- std::string destinationFilename = generator->GetDestination();
- destinationFilename += "/";
- destinationFilename += generator->GetInstallFilename(0);
- twp->Properties[propertyName.c_str()] = destinationFilename;
- }
- else
- {
- return false;
+ useMD5 = true;
}
}
else
{
- for(std::vector<std::string>::const_iterator configIt = configs.begin();
- configIt != configs.end();
- ++configIt)
- {
- std::string propertyName = configIt->c_str();
- propertyName += "_";
- propertyName += prefix;
- propertyName += "LOCATION";
- // check that this property doesn't exist yet and add it then
- if (twp->Properties.find(propertyName.c_str()) == twp->Properties.end())
- {
- std::string destinationFilename = generator->GetDestination();
- destinationFilename += "/";
- destinationFilename +=generator->GetInstallFilename(configIt->c_str());
- twp->Properties[propertyName.c_str()] = destinationFilename;
- }
- else
- {
- return false;
- }
- }
- }
- return true;
-}
-
-
-bool cmInstallExportGenerator::AddInstallLocations(cmTargetWithProperties* twp,
- cmInstallFilesGenerator* generator,
- const char* propertyName)
-{
- if (generator == 0) // nothing to do
- {
- return true;
+ useMD5 = true;
}
-
- if ((propertyName == 0) || (*propertyName == '\0'))
+ if(useMD5)
{
- return false;
+ // Replace the destination path with a hash to keep it short.
+ this->TempDir +=
+ cmSystemTools::ComputeStringMD5(this->Destination.c_str());
}
-
- // check that this property doesn't exist yet and add it then
- if (twp->Properties.find(propertyName) == twp->Properties.end())
+ else
{
- twp->Properties[propertyName] = generator->GetDestination();
- return true;
+ std::string dest = this->Destination;
+ // Avoid unix full paths.
+ if(dest[0] == '/')
+ {
+ dest[0] = '_';
+ }
+ // Avoid windows full paths by removing colons.
+ cmSystemTools::ReplaceString(dest, ":", "_");
+ // Avoid relative paths that go up the tree.
+ cmSystemTools::ReplaceString(dest, "../", "__/");
+ // Avoid spaces.
+ cmSystemTools::ReplaceString(dest, " ", "_");
+ this->TempDir += dest;
}
-
- return false;
}
-
-bool cmInstallExportGenerator::SetExportSet(const char* name,
- const std::vector<cmTargetExport*>* set)
+//----------------------------------------------------------------------------
+void cmInstallExportGenerator::GenerateScript(std::ostream& os)
{
- if ((name == 0) || (*name == 0) || (set==0))
+ // Get the export set requested.
+ ExportSet const* exportSet =
+ this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
+ ->GetExportSet(this->Name.c_str());
+
+ // Skip empty sets.
+ if(!exportSet)
{
- return false;
+ cmOStringStream e;
+ e << "INSTALL(EXPORT) given unknown export \"" << this->Name << "\"";
+ cmSystemTools::Error(e.str().c_str());
+ return;
}
- this->Name = name;
-
- /* iterate over all targets in the set.
- If a cmTargetWithProperties with the same name already exists in this
- generator, add the new properties to it. If the property already exists,
- fail with an error.
- If no cmTargetWithProperties exists, create a new one.
- */
- for(std::vector<cmTargetExport*>::const_iterator it=set->begin();
- it != set->end();
- ++it)
+ // Create the temporary directory in which to store the files.
+ this->ComputeTempDir();
+ cmSystemTools::MakeDirectory(this->TempDir.c_str());
+
+ // Construct a temporary location for the file.
+ this->MainImportFile = this->TempDir;
+ this->MainImportFile += "/";
+ this->MainImportFile += this->FileName;
+
+ // Generate the import file for this export set.
+ this->EFGen->SetName(this->Name.c_str());
+ this->EFGen->SetExportSet(exportSet);
+ this->EFGen->SetExportFile(this->MainImportFile.c_str());
+ this->EFGen->SetNamespace(this->Namespace.c_str());
+ if(this->ConfigurationTypes->empty())
{
- std::string targetName = (*it)->Target->GetName();
-
- cmTargetWithProperties* targetWithProps = 0;
- for(unsigned int i=0; i<this->Targets.size(); i++)
- {
- if (targetName == this->Targets[i]->Target->GetName())
- {
- targetWithProps = this->Targets[i];
- break;
- }
- }
-
- if (targetWithProps == 0)
+ if(this->ConfigurationName && *this->ConfigurationName)
{
- targetWithProps = new cmTargetWithProperties((*it)->Target);
- this->Targets.push_back(targetWithProps);
+ this->EFGen->AddConfiguration(this->ConfigurationName);
}
-
- if (this->AddInstallLocations(targetWithProps, (*it)->ArchiveGenerator,
- "ARCHIVE_") == false)
- {
- return false;
- }
- if (this->AddInstallLocations(targetWithProps, (*it)->RuntimeGenerator,
- "") == false)
- {
- return false;
- }
- if (this->AddInstallLocations(targetWithProps, (*it)->LibraryGenerator,
- "LIBRARY_") == false)
+ else
{
- return false;
+ this->EFGen->AddConfiguration("");
}
- if (this->AddInstallLocations(targetWithProps, (*it)->HeaderGenerator,
- "PUBLIC_HEADER_LOCATION") == false)
+ }
+ else
+ {
+ for(std::vector<std::string>::const_iterator
+ ci = this->ConfigurationTypes->begin();
+ ci != this->ConfigurationTypes->end(); ++ci)
{
- return false;
+ this->EFGen->AddConfiguration(ci->c_str());
}
}
+ this->EFGen->GenerateImportFile();
- return true;
+ // Perform the main install script generation.
+ this->cmInstallGenerator::GenerateScript(os);
}
-void cmInstallExportGenerator::GenerateScript(std::ostream& os)
+//----------------------------------------------------------------------------
+void
+cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
+ Indent const& indent)
{
- // for the case that somebody exports the same set with the same file name
- // to different locations make the temp filename unique
- char buf[64];
- sprintf(buf, "%p", this);
- this->ExportFilename = this->TempOutputDir;
- this->ExportFilename += "/";
- this->ExportFilename += this->Filename;
- this->ExportFilename += ".";
- this->ExportFilename += buf;
-
- cmGeneratedFileStream exportFileStream(this->ExportFilename.c_str());
- if(!exportFileStream)
+ // Create the main install rules first.
+ this->cmInstallGenerator::GenerateScriptConfigs(os, indent);
+
+ // Now create a configuration-specific install rule for the import
+ // file of each configuration.
+ std::vector<std::string> files;
+ for(std::map<cmStdString, cmStdString>::const_iterator
+ i = this->EFGen->GetConfigImportFiles().begin();
+ i != this->EFGen->GetConfigImportFiles().end(); ++i)
{
- return;
+ files.push_back(i->second);
+ std::string config_test = this->CreateConfigTest(i->first.c_str());
+ os << indent << "IF(" << config_test << ")\n";
+ this->AddInstallRule(os, cmTarget::INSTALL_FILES, files, false, 0,
+ this->FilePermissions.c_str(), 0, 0, 0,
+ indent.Next());
+ os << indent << "ENDIF(" << config_test << ")\n";
+ files.clear();
}
-
- /* for every target add the IMPORT statements and set the properties
- of the target. */
- for(std::vector<cmTargetWithProperties*>::const_iterator
- targetIt = this->Targets.begin();
- targetIt != this->Targets.end();
- ++targetIt)
- {
- switch ((*targetIt)->Target->GetType())
- {
- case cmTarget::EXECUTABLE:
- exportFileStream << "ADD_EXECUTABLE(" << this->Prefix.c_str()
- << (*targetIt)->Target->GetName()
- << " IMPORT )\n";
- break;
- case cmTarget::STATIC_LIBRARY:
- exportFileStream << "ADD_LIBRARY(" << this->Prefix.c_str()
- << (*targetIt)->Target->GetName()
- << " STATIC IMPORT )\n";
- break;
- case cmTarget::SHARED_LIBRARY:
- exportFileStream << "ADD_LIBRARY(" << this->Prefix.c_str()
- << (*targetIt)->Target->GetName()
- << " SHARED IMPORT )\n";
- break;
- case cmTarget::MODULE_LIBRARY:
- exportFileStream << "ADD_LIBRARY(" << this->Prefix.c_str()
- << (*targetIt)->Target->GetName()
- << " MODULE IMPORT )\n";
- break;
- default: // should never happen
- break;
- }
-
- exportFileStream << "SET_TARGET_PROPERTIES ( " << this->Prefix.c_str()
- << (*targetIt)->Target->GetName() << " PROPERTIES \n";
-
- for (std::map<std::string, std::string>::const_iterator
- propIt = (*targetIt)->Properties.begin();
- propIt != (*targetIt)->Properties.end();
- ++propIt)
- {
- exportFileStream << " " << propIt->first
- << " \"" << propIt->second << "\"\n";
- }
- exportFileStream << " )\n\n";
- }
-
- // Perform the main install script generation.
- this->cmInstallGenerator::GenerateScript(os);
}
//----------------------------------------------------------------------------
void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
Indent const& indent)
{
- // install rule for the file created above
- std::vector<std::string> exportFile;
- exportFile.push_back(this->ExportFilename);
- this->AddInstallRule(os, this->Destination.c_str(), cmTarget::INSTALL_FILES,
- exportFile, false, 0,
- this->FilePermissions.c_str(),
- 0, this->Filename.c_str(), 0, indent);
+ // Install the main export file.
+ std::vector<std::string> files;
+ files.push_back(this->MainImportFile);
+ this->AddInstallRule(os, cmTarget::INSTALL_FILES, files, false, 0,
+ this->FilePermissions.c_str(), 0, 0, 0, indent);
}
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index ee0ae3e1fa..24f4aaca8e 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -19,42 +19,12 @@
#include "cmInstallGenerator.h"
-class cmTarget;
-
-
-class cmInstallTargetGenerator;
+class cmExportInstallFileGenerator;
class cmInstallFilesGenerator;
-
-/* cmInstallExportTarget is used in cmGlobalGenerator to collect the
-install generators for the exported targets. These are then used by the
-cmInstallExportGenerator.
-*/
-class cmTargetExport
-{
-public:
- cmTargetExport(cmTarget* tgt,
- cmInstallTargetGenerator* archive,
- cmInstallTargetGenerator* runtime,
- cmInstallTargetGenerator* library,
- cmInstallTargetGenerator* framework,
- cmInstallTargetGenerator* bundle,
- cmInstallFilesGenerator* headers
- ) : Target(tgt), ArchiveGenerator(archive),
- RuntimeGenerator(runtime), LibraryGenerator(library),
- FrameworkGenerator(framework), BundleGenerator(bundle),
- HeaderGenerator(headers) {}
-
- cmTarget* Target;
- cmInstallTargetGenerator* ArchiveGenerator;
- cmInstallTargetGenerator* RuntimeGenerator;
- cmInstallTargetGenerator* LibraryGenerator;
- cmInstallTargetGenerator* FrameworkGenerator;
- cmInstallTargetGenerator* BundleGenerator;
- cmInstallFilesGenerator* HeaderGenerator;
-private:
- cmTargetExport();
-};
-
+class cmInstallTargetGenerator;
+class cmTarget;
+class cmTargetExport;
+class cmMakefile;
/** \class cmInstallExportGenerator
* \brief Generate rules for creating an export files.
@@ -62,45 +32,33 @@ private:
class cmInstallExportGenerator: public cmInstallGenerator
{
public:
- cmInstallExportGenerator(const char* dest, const char* file_permissions,
+ cmInstallExportGenerator(const char* name,
+ const char* dest, const char* file_permissions,
const std::vector<std::string>& configurations,
const char* component,
- const char* filename, const char* prefix,
- const char* tempOutputDir);
-
- bool SetExportSet(const char* name,
- const std::vector<cmTargetExport*>* exportSet);
+ const char* filename, const char* name_space,
+ cmMakefile* mf);
+ ~cmInstallExportGenerator();
protected:
- // internal class which collects all the properties which will be set
- // in the export file for the target
- class cmTargetWithProperties
- {
- public:
- cmTargetWithProperties(cmTarget* target):Target(target) {}
- cmTarget* Target;
- std::map<std::string, std::string> Properties;
- private:
- cmTargetWithProperties();
- };
+ typedef std::vector<cmTargetExport*> ExportSet;
typedef cmInstallGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os);
+ virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent);
virtual void GenerateScriptActions(std::ostream& os, Indent const& indent);
- static bool AddInstallLocations(cmTargetWithProperties *twp,
- cmInstallTargetGenerator* generator,
- const char* prefix);
- static bool AddInstallLocations(cmTargetWithProperties* twp,
- cmInstallFilesGenerator* generator,
- const char* propertyName);
+ void GenerateImportFile(ExportSet const* exportSet);
+ void GenerateImportFile(const char* config, ExportSet const* exportSet);
+ void ComputeTempDir();
std::string Name;
std::string FilePermissions;
- std::string Filename;
- std::string Prefix;
- std::string TempOutputDir;
- std::string ExportFilename;
+ std::string FileName;
+ std::string Namespace;
+ cmMakefile* Makefile;
- std::vector<cmTargetWithProperties*> Targets;
+ std::string TempDir;
+ std::string MainImportFile;
+ cmExportInstallFileGenerator* EFGen;
};
#endif
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
index 4b09aceed7..36e7e25810 100644
--- a/Source/cmInstallFilesCommand.cxx
+++ b/Source/cmInstallFilesCommand.cxx
@@ -119,9 +119,8 @@ void cmInstallFilesCommand::FinalPass()
void cmInstallFilesCommand::CreateInstallGenerator() const
{
// Construct the destination. This command always installs under
- // the prefix.
- std::string destination = "${CMAKE_INSTALL_PREFIX}";
- destination += this->Destination;
+ // the prefix. We skip the leading slash given by the user.
+ std::string destination = this->Destination.substr(1);
cmSystemTools::ConvertToUnixSlashes(destination);
// Use a file install generator.
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index ef7eac7f5c..843e31593b 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -47,7 +47,7 @@ void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
// Write code to install the files.
const char* no_properties = 0;
const char* no_dir_permissions = 0;
- this->AddInstallRule(os, this->Destination.c_str(),
+ this->AddInstallRule(os,
(this->Programs
? cmTarget::INSTALL_PROGRAMS
: cmTarget::INSTALL_FILES),
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 928b241c33..cd159651a0 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -55,7 +55,6 @@ cmInstallGenerator
void cmInstallGenerator
::AddInstallRule(
std::ostream& os,
- const char* dest,
int type,
std::vector<std::string> const& files,
bool optional /* = false */,
@@ -81,6 +80,7 @@ void cmInstallGenerator
default: stype = "FILE"; break;
}
os << indent;
+ std::string dest = this->GetInstallDestination();
os << "FILE(INSTALL DESTINATION \"" << dest << "\" TYPE " << stype.c_str();
if(optional)
{
@@ -238,3 +238,40 @@ void cmInstallGenerator::GenerateScriptActions(std::ostream&, Indent const&)
{
// No actions for this generator.
}
+
+//----------------------------------------------------------------------------
+bool cmInstallGenerator::InstallsForConfig(const char* config)
+{
+ // If this is not a configuration-specific rule then we install.
+ if(this->Configurations.empty())
+ {
+ return true;
+ }
+
+ // This is a configuration-specific rule. Check if the config
+ // matches this rule.
+ std::string config_upper = cmSystemTools::UpperCase(config?config:"");
+ for(std::vector<std::string>::const_iterator i =
+ this->Configurations.begin();
+ i != this->Configurations.end(); ++i)
+ {
+ if(cmSystemTools::UpperCase(*i) == config_upper)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
+std::string cmInstallGenerator::GetInstallDestination() const
+{
+ std::string result;
+ if(!this->Destination.empty() &&
+ !cmSystemTools::FileIsFullPath(this->Destination.c_str()))
+ {
+ result = "${CMAKE_INSTALL_PREFIX}/";
+ }
+ result += this->Destination;
+ return result;
+}
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 3abcf86493..904bb2be94 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -62,8 +62,8 @@ public:
void Generate(std::ostream& os, const char* config,
std::vector<std::string> const& configurationTypes);
- static void AddInstallRule(
- std::ostream& os, const char* dest, int type,
+ void AddInstallRule(
+ std::ostream& os, int type,
std::vector<std::string> const& files,
bool optional = false,
const char* properties = 0,
@@ -78,6 +78,14 @@ public:
{ return this->Destination.c_str(); }
const std::vector<std::string>& GetConfigurations() const
{ return this->Configurations; }
+
+ /** Get the install destination as it should appear in the
+ installation script. */
+ std::string GetInstallDestination() const;
+
+ /** Test if this generator installs something for a given configuration. */
+ bool InstallsForConfig(const char*);
+
protected:
typedef cmInstallGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx
index 8a29665eea..013728a280 100644
--- a/Source/cmInstallProgramsCommand.cxx
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -80,9 +80,8 @@ void cmInstallProgramsCommand::FinalPass()
}
// Construct the destination. This command always installs under
- // the prefix.
- std::string destination = "${CMAKE_INSTALL_PREFIX}";
- destination += this->Destination;
+ // the prefix. We skip the leading slash given by the user.
+ std::string destination = this->Destination.substr(1);
cmSystemTools::ConvertToUnixSlashes(destination);
// Use a file install generator.
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index d6a934516e..8a56329bab 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -113,22 +113,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
if(config && *config)
{
- std::string config_upper = cmSystemTools::UpperCase(config);
// Skip this configuration for config-specific installation that
// does not match it.
- if(!this->Configurations.empty())
+ if(!this->InstallsForConfig(config))
{
- bool found = false;
- for(std::vector<std::string>::const_iterator i =
- this->Configurations.begin();
- !found && i != this->Configurations.end(); ++i)
- {
- found = found || (cmSystemTools::UpperCase(*i) == config_upper);
- }
- if(!found)
- {
- return;
- }
+ return;
}
// Generate a per-configuration block.
@@ -154,7 +143,7 @@ cmInstallTargetGenerator
Indent const& indent)
{
// Compute the full path to the main installed file for this target.
- std::string toInstallPath = this->Destination;
+ std::string toInstallPath = this->GetInstallDestination();
toInstallPath += "/";
toInstallPath += this->GetInstallFilename(this->Target, config,
this->ImportLibrary, false);
@@ -279,7 +268,7 @@ cmInstallTargetGenerator
const char* no_rename = 0;
const char* no_properties = 0;
bool optional = this->Optional || this->ImportLibrary;
- this->AddInstallRule(os, this->Destination.c_str(), type, files,
+ this->AddInstallRule(os, type, files,
optional, no_properties,
this->FilePermissions.c_str(), no_dir_permissions,
no_rename, literal_args.c_str(),
@@ -412,7 +401,7 @@ cmInstallTargetGenerator
{
if(cmTarget* tgt = this->Target->GetMakefile()->
GetLocalGenerator()->GetGlobalGenerator()->
- FindTarget(0, lib.c_str(), false))
+ FindTarget(0, lib.c_str()))
{
if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
{
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index e37a5ef015..01d36bb83e 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -40,6 +40,9 @@ public:
static std::string GetInstallFilename(cmTarget*target, const char* config,
bool implib, bool useSOName);
+ cmTarget* GetTarget() const { return this->Target; }
+ bool IsImportLibrary() const { return this->ImportLibrary; }
+
protected:
typedef cmInstallGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index f49e1bd252..4812572568 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1809,7 +1809,7 @@ std::string cmLocalGenerator::GetRealDependency(const char* inName,
}
// Look for a CMake target with the given name.
- if(cmTarget* target = this->GlobalGenerator->FindTarget(0,name.c_str(),true))
+ if(cmTarget* target = this->Makefile->FindTargetToUse(name.c_str()))
{
// make sure it is not just a coincidence that the target name
// found is part of the inName
@@ -1876,7 +1876,7 @@ std::string cmLocalGenerator::GetRealLocation(const char* inName,
std::string outName=inName;
// Look for a CMake target with the given name, which is an executable
// and which can be run
- cmTarget* target = this->GlobalGenerator->FindTarget(0, inName, true);
+ cmTarget* target = this->Makefile->FindTargetToUse(inName);
if ((target != 0)
&& (target->GetType() == cmTarget::EXECUTABLE)
&& ((this->Makefile->IsOn("CMAKE_CROSSCOMPILING") == false)
@@ -2348,8 +2348,8 @@ cmLocalGenerator
{
// Compute the full install destination. Note that converting
// to unix slashes also removes any trailing slash.
- std::string destination = "${CMAKE_INSTALL_PREFIX}";
- destination += l->second.GetInstallPath();
+ // We also skip over the leading slash given by the user.
+ std::string destination = l->second.GetInstallPath().substr(1);
cmSystemTools::ConvertToUnixSlashes(destination);
// Generate the proper install generator for this target type.
@@ -2372,8 +2372,8 @@ cmLocalGenerator
// destination.
cmInstallTargetGenerator g1(l->second, destination.c_str(), true);
g1.Generate(os, config, configurationTypes);
- destination = "${CMAKE_INSTALL_PREFIX}";
- destination += l->second.GetRuntimeInstallPath();
+ // We also skip over the leading slash given by the user.
+ destination = l->second.GetRuntimeInstallPath().substr(1);
cmSystemTools::ConvertToUnixSlashes(destination);
cmInstallTargetGenerator g2(l->second, destination.c_str(), false);
g2.Generate(os, config, configurationTypes);
diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx
index b462cd3ce9..258d027329 100644
--- a/Source/cmLocalVisualStudio6Generator.cxx
+++ b/Source/cmLocalVisualStudio6Generator.cxx
@@ -1061,8 +1061,7 @@ void cmLocalVisualStudio6Generator
// Compute the proper name to use to link this library.
std::string lib;
std::string libDebug;
- cmTarget* tgt = this->GlobalGenerator->FindTarget(0, j->first.c_str(),
- false);
+ cmTarget* tgt = this->GlobalGenerator->FindTarget(0, j->first.c_str());
if(tgt)
{
lib = cmSystemTools::GetFilenameWithoutExtension
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index d75e9eb951..1abd467b42 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -37,6 +37,8 @@
#include <cmsys/RegularExpression.hxx>
+#include <cmsys/auto_ptr.hxx>
+
#include <ctype.h> // for isspace
// default is not to be building executables
@@ -176,6 +178,12 @@ cmMakefile::~cmMakefile()
{
delete *i;
}
+ for(std::vector<cmTarget*>::iterator
+ i = this->ImportedTargetsOwned.begin();
+ i != this->ImportedTargetsOwned.end(); ++i)
+ {
+ delete *i;
+ }
for(unsigned int i=0; i < this->UsedCommands.size(); i++)
{
delete this->UsedCommands[i];
@@ -824,7 +832,7 @@ void cmMakefile::AddUtilityCommand(const char* utilityName,
bool escapeOldStyle, const char* comment)
{
// Create a target instance for this utility.
- cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName, false);
+ cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName);
if (excludeFromAll)
{
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
@@ -1005,7 +1013,7 @@ void cmMakefile::AddLinkLibraryForTarget(const char *target,
if ( i != this->Targets.end())
{
cmTarget* tgt =
- this->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(0,lib,false);
+ this->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(0,lib);
if(tgt)
{
bool allowModules = true;
@@ -1018,8 +1026,7 @@ void cmMakefile::AddLinkLibraryForTarget(const char *target,
// if it is not a static or shared library then you can not link to it
if(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) ||
(tgt->GetType() == cmTarget::SHARED_LIBRARY) ||
- (tgt->GetType() == cmTarget::EXECUTABLE &&
- tgt->GetPropertyAsBool("ENABLE_EXPORTS"))))
+ tgt->IsExecutableWithExports()))
{
cmOStringStream e;
e << "Attempt to add link target " << lib << " of type: "
@@ -1162,6 +1169,9 @@ void cmMakefile::InitializeFromParent()
// Copy include regular expressions.
this->IncludeFileRegularExpression = parent->IncludeFileRegularExpression;
this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression;
+
+ // Imported targets.
+ this->ImportedTargets = parent->ImportedTargets;
}
void cmMakefile::ConfigureSubDirectory(cmLocalGenerator *lg2)
@@ -1467,7 +1477,7 @@ void cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
type = cmTarget::STATIC_LIBRARY;
}
- cmTarget* target = this->AddNewTarget(type, lname, false);
+ cmTarget* target = this->AddNewTarget(type, lname);
// Clear its dependencies. Otherwise, dependencies might persist
// over changes in CMakeLists.txt, making the information stale and
// hence useless.
@@ -1484,7 +1494,7 @@ cmTarget* cmMakefile::AddExecutable(const char *exeName,
const std::vector<std::string> &srcs,
bool excludeFromAll)
{
- cmTarget* target = this->AddNewTarget(cmTarget::EXECUTABLE, exeName, false);
+ cmTarget* target = this->AddNewTarget(cmTarget::EXECUTABLE, exeName);
if(excludeFromAll)
{
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
@@ -1494,26 +1504,16 @@ cmTarget* cmMakefile::AddExecutable(const char *exeName,
return target;
}
-
-cmTarget* cmMakefile::AddNewTarget(cmTarget::TargetType type,
- const char* name,
- bool isImported)
+//----------------------------------------------------------------------------
+cmTarget*
+cmMakefile::AddNewTarget(cmTarget::TargetType type, const char* name)
{
cmTargets::iterator it;
cmTarget target;
target.SetType(type, name);
target.SetMakefile(this);
- if (isImported)
- {
- target.MarkAsImported();
- it=this->ImportedTargets.insert(
- cmTargets::value_type(target.GetName(), target)).first;
- }
- else
- {
- it=this->Targets.insert(
- cmTargets::value_type(target.GetName(), target)).first;
- }
+ it=this->Targets.insert(
+ cmTargets::value_type(target.GetName(), target)).first;
this->LocalGenerator->GetGlobalGenerator()->AddTarget(*it);
return &it->second;
}
@@ -2869,7 +2869,7 @@ bool cmMakefile::GetPropertyAsBool(const char* prop)
}
-cmTarget* cmMakefile::FindTarget(const char* name, bool useImportedTargets)
+cmTarget* cmMakefile::FindTarget(const char* name)
{
cmTargets& tgts = this->GetTargets();
@@ -2879,15 +2879,6 @@ cmTarget* cmMakefile::FindTarget(const char* name, bool useImportedTargets)
return &i->second;
}
- if (useImportedTargets)
- {
- cmTargets::iterator impTarget = this->ImportedTargets.find(name);
- if (impTarget != this->ImportedTargets.end())
- {
- return &impTarget->second;
- }
- }
-
return 0;
}
@@ -3091,3 +3082,37 @@ void cmMakefile::DefineProperties(cmake *cm)
"The same concept applies to the default build of other generators.",
false);
}
+
+//----------------------------------------------------------------------------
+cmTarget*
+cmMakefile::AddImportedTarget(const char* name, cmTarget::TargetType type)
+{
+ // Create the target.
+ cmsys::auto_ptr<cmTarget> target(new cmTarget);
+ target->SetType(type, name);
+ target->SetMakefile(this);
+ target->MarkAsImported();
+
+ // Add to the set of available imported targets.
+ this->ImportedTargets[name] = target.get();
+
+ // Transfer ownership to this cmMakefile object.
+ this->ImportedTargetsOwned.push_back(target.get());
+ return target.release();
+}
+
+//----------------------------------------------------------------------------
+cmTarget* cmMakefile::FindTargetToUse(const char* name)
+{
+ // Look for an imported target. These take priority because they
+ // are more local in scope and do not have to be globally unique.
+ std::map<cmStdString, cmTarget*>::const_iterator
+ imported = this->ImportedTargets.find(name);
+ if(imported != this->ImportedTargets.end())
+ {
+ return imported->second;
+ }
+
+ // Look for a target built in this project.
+ return this->LocalGenerator->GetGlobalGenerator()->FindTarget(0, name);
+}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index e511851e65..5664e2587a 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -172,9 +172,10 @@ public:
void AddDefineFlag(const char* definition);
void RemoveDefineFlag(const char* definition);
- cmTarget* AddNewTarget(cmTarget::TargetType type,
- const char* name,
- bool isImported);
+ /** Create a new imported target with the name and type given. */
+ cmTarget* AddImportedTarget(const char* name, cmTarget::TargetType type);
+
+ cmTarget* AddNewTarget(cmTarget::TargetType type, const char* name);
/**
* Add an executable to the build.
@@ -436,10 +437,12 @@ public:
* Get the list of targets, const version
*/
const cmTargets &GetTargets() const { return this->Targets; }
- const cmTargets &GetImportedTargets() const { return this->ImportedTargets; }
- cmTarget* FindTarget(const char* name, bool useImportedTargets);
+ cmTarget* FindTarget(const char* name);
+ /** Find a target to use in place of the given name. The target
+ returned may be imported or built within the project. */
+ cmTarget* FindTargetToUse(const char* name);
/**
* Get a list of include directories in the build.
@@ -766,7 +769,6 @@ protected:
// libraries, classes, and executables
cmTargets Targets;
- cmTargets ImportedTargets;
std::vector<cmSourceFile*> SourceFiles;
// Tests
@@ -842,6 +844,10 @@ private:
// stack of list files being read
std::deque<cmStdString> ListFileStack;
+
+ cmTarget* FindBasicTarget(const char* name);
+ std::vector<cmTarget*> ImportedTargetsOwned;
+ std::map<cmStdString, cmTarget*> ImportedTargets;
};
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 85d8565f3b..e67b991f10 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -259,7 +259,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
}
// Add symbol export flags if necessary.
- if(this->Target->GetPropertyAsBool("ENABLE_EXPORTS"))
+ if(this->Target->IsExecutableWithExports())
{
std::string export_flag_var = "CMAKE_EXE_EXPORTS_";
export_flag_var += linkLanguage;
@@ -351,7 +351,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
std::vector<std::string> commands1;
cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
- if(this->Target->GetPropertyAsBool("ENABLE_EXPORTS"))
+ if(this->Target->IsExecutableWithExports())
{
// If a separate rule for creating an import library is specified
// add it now.
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 37bd5f94cf..0c550efde9 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -869,7 +869,7 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
for(cmTarget::LinkLibraryVectorType::const_iterator j = libs.begin();
j != libs.end(); ++j)
{
- if(cmTarget const* linkee = gg->FindTarget(0, j->first.c_str(), false))
+ if(cmTarget const* linkee = gg->FindTarget(0, j->first.c_str()))
{
if(emitted.insert(linkee).second)
{
@@ -1371,7 +1371,7 @@ void cmMakefileTargetGenerator
{
// Depend on other CMake targets.
if(cmTarget* tgt =
- this->GlobalGenerator->FindTarget(0, lib->first.c_str(), false))
+ this->GlobalGenerator->FindTarget(0, lib->first.c_str()))
{
if(const char* location =
tgt->GetLocation(this->LocalGenerator->ConfigurationName.c_str()))
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 0922c1dd2c..dbf71c2b8c 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -220,9 +220,7 @@ bool cmSetPropertyCommand::HandleTargetMode()
for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
ni != this->Names.end(); ++ni)
{
- if(cmTarget* target =
- this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
- ->FindTarget(0, ni->c_str(), true))
+ if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str()))
{
// Handle the current target.
if(!this->HandleTarget(target))
diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx
index ccbe0d5fa6..26615dc3ac 100644
--- a/Source/cmSetTargetPropertiesCommand.cxx
+++ b/Source/cmSetTargetPropertiesCommand.cxx
@@ -95,9 +95,7 @@ bool cmSetTargetPropertiesCommand
std::vector<std::string> &propertyPairs,
cmMakefile *mf)
{
- cmTarget* target =
- mf->GetLocalGenerator()->GetGlobalGenerator()->FindTarget(0, tname, true);
- if ( target)
+ if(cmTarget* target = mf->FindTargetToUse(tname))
{
// now loop through all the props and set them
unsigned int k;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 274c3af45b..0fb6f7b279 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -154,6 +154,96 @@ void cmTarget::DefineProperties(cmake *cm)
"(such as \".lib\") on an import library name.");
cm->DefineProperty
+ ("IMPORTED", cmProperty::TARGET,
+ "Read-only indication of whether a target is IMPORTED.",
+ "The boolean value of this property is true for targets created with "
+ "the IMPORTED option to add_executable or add_library. "
+ "It is false for targets built within the project.");
+
+ cm->DefineProperty
+ ("IMPORTED_CONFIGURATIONS", cmProperty::TARGET,
+ "Configurations provided for an IMPORTED target.",
+ "Lists configuration names available for an IMPORTED target. "
+ "The names correspond to configurations defined in the project from "
+ "which the target is imported. "
+ "If the importing project uses a different set of configurations "
+ "the names may be mapped using the MAP_IMPORTED_CONFIG_<CONFIG> "
+ "property. "
+ "Ignored for non-imported targets.");
+
+ cm->DefineProperty
+ ("IMPORTED_ENABLE_EXPORTS", cmProperty::TARGET,
+ "Enable linking to an IMPORTED executable target.",
+ "Indicates that an IMPORTED executable target exports symbols for "
+ "use by plugin modules. "
+ "This is the imported target equivalent of the ENABLE_EXPORTS "
+ "property.");
+
+ cm->DefineProperty
+ ("IMPORTED_IMPLIB", cmProperty::TARGET,
+ "Full path to the import library for an IMPORTED target.",
+ "Specifies the location of the \".lib\" part of a windows DLL. "
+ "Ignored for non-imported targets.");
+
+ cm->DefineProperty
+ ("IMPORTED_IMPLIB_<CONFIG>", cmProperty::TARGET,
+ "Per-configuration version of IMPORTED_IMPLIB property.",
+ "This property is used when loading settings for the <CONFIG> "
+ "configuration of an imported target. "
+ "Configuration names correspond to those provided by the project "
+ "from which the target is imported.");
+
+ cm->DefineProperty
+ ("IMPORTED_LINK_LIBRARIES", cmProperty::TARGET,
+ "Transitive link dependencies of an IMPORTED target.",
+ "Lists dependencies that must be linked when an IMPORTED library "
+ "target is linked to another target. "
+ "Ignored for non-imported targets.");
+
+ cm->DefineProperty
+ ("IMPORTED_LINK_LIBRARIES_<CONFIG>", cmProperty::TARGET,
+ "Per-configuration version of IMPORTED_LINK_LIBRARIES property.",
+ "This property is used when loading settings for the <CONFIG> "
+ "configuration of an imported target. "
+ "Configuration names correspond to those provided by the project "
+ "from which the target is imported.");
+
+ cm->DefineProperty
+ ("IMPORTED_LOCATION", cmProperty::TARGET,
+ "Full path to the main file on disk for an IMPORTED target.",
+ "Specifies the location of an IMPORTED target file on disk. "
+ "For executables this is the location of the executable file. "
+ "For static libraries and modules this is the location of the "
+ "library or module. "
+ "For shared libraries on non-DLL platforms this is the location of "
+ "the shared library. "
+ "For DLLs this is the location of the \".dll\" part of the library. "
+ "Ignored for non-imported targets.");
+
+ cm->DefineProperty
+ ("IMPORTED_LOCATION_<CONFIG>", cmProperty::TARGET,
+ "Per-configuration version of IMPORTED_LOCATION property.",
+ "This property is used when loading settings for the <CONFIG> "
+ "configuration of an imported target. "
+ "Configuration names correspond to those provided by the project "
+ "from which the target is imported.");
+
+ cm->DefineProperty
+ ("IMPORTED_SONAME", cmProperty::TARGET,
+ "The \"soname\" of an IMPORTED target of shared library type.",
+ "Specifies the \"soname\" embedded in an imported shared library. "
+ "This is meaningful only on platforms supporting the feature. "
+ "Ignored for non-imported targets.");
+
+ cm->DefineProperty
+ ("IMPORTED_SONAME_<CONFIG>", cmProperty::TARGET,
+ "Per-configuration version of IMPORTED_SONAME property.",
+ "This property is used when loading settings for the <CONFIG> "
+ "configuration of an imported target. "
+ "Configuration names correspond to those provided by the project "
+ "from which the target is imported.");
+
+ cm->DefineProperty
("EXCLUDE_FROM_ALL", cmProperty::TARGET,
"Exclude the target from the all target.",
"A property on a target that indicates if the target is excluded "
@@ -206,11 +296,37 @@ void cmTarget::DefineProperties(cmake *cm)
cm->DefineProperty
("LOCATION", cmProperty::TARGET,
- "Where a target will be written on disk.",
- "A read only property on a target that indicates where that target "
- "will be written. For libraries and executables this will be where "
- "the file is written on disk. This property is computed based on a "
- "number of other settings.");
+ "Deprecated. Use LOCATION_<CONFIG> or avoid altogether.",
+ "This property is provided for compatibility with CMake 2.4 and below. "
+ "It was meant to get the location of an executable target's output file "
+ "for use in add_custom_command. "
+ "In CMake 2.6 and above add_custom_command automatically recognizes a "
+ "target name in its COMMAND and DEPENDS options and computes the "
+ "target location. Therefore this property need not be used. "
+ "This property is not defined for IMPORTED targets because they "
+ "were not available in CMake 2.4 or below anyway.");
+
+ cm->DefineProperty
+ ("LOCATION_<CONFIG>", cmProperty::TARGET,
+ "Read-only property providing a target location on disk.",
+ "A read-only property that indicates where a target's main file is "
+ "located on disk for the configuration <CONFIG>. "
+ "The property is defined only for library and executable targets.");
+
+ cm->DefineProperty
+ ("MAP_IMPORTED_CONFIG_<CONFIG>", cmProperty::TARGET,
+ "Map from project configuration to IMPORTED target's configuration.",
+ "List configurations of an imported target that may be used for "
+ "the current project's <CONFIG> configuration. "
+ "Targets imported from another project may not provide the same set "
+ "of configuration names available in the current project. "
+ "Setting this property tells CMake what imported configurations are "
+ "suitable for use when building the <CONFIG> configuration. "
+ "The first configuration in the list found to be provided by the "
+ "imported target is selected. If no matching configurations are "
+ "available the imported target is considered to be not found. "
+ "This property is ignored for non-imported targets.",
+ false /* TODO: make this chained */ );
cm->DefineProperty
("OUTPUT_NAME", cmProperty::TARGET,
@@ -481,6 +597,25 @@ void cmTarget::SetMakefile(cmMakefile* mf)
}
//----------------------------------------------------------------------------
+bool cmTarget::IsExecutableWithExports()
+{
+ if(this->GetType() == cmTarget::EXECUTABLE)
+ {
+ if(this->IsImported())
+ {
+ // The "IMPORTED_" namespace is used for properties exported
+ // from the project providing imported targets.
+ return this->GetPropertyAsBool("IMPORTED_ENABLE_EXPORTS");
+ }
+ else
+ {
+ return this->GetPropertyAsBool("ENABLE_EXPORTS");
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
class cmTargetTraceDependencies
{
public:
@@ -603,8 +738,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
}
// Check for a non-imported target with this name.
- if(cmTarget* t =
- this->GlobalGenerator->FindTarget(0, util.c_str(), false))
+ if(cmTarget* t = this->GlobalGenerator->FindTarget(0, util.c_str()))
{
// If we find the target and the dep was given as a full path,
// then make sure it was not a full path to something else, and
@@ -671,8 +805,7 @@ cmTargetTraceDependencies
{
std::string const& command = *cit->begin();
// Look for a non-imported target with this name.
- if(cmTarget* t =
- this->GlobalGenerator->FindTarget(0, command.c_str(), false))
+ if(cmTarget* t = this->GlobalGenerator->FindTarget(0, command.c_str()))
{
if(t->GetType() == cmTarget::EXECUTABLE)
{
@@ -1287,6 +1420,13 @@ void cmTarget::SetProperty(const char* prop, const char* value)
}
this->Properties.SetProperty(prop, value, cmProperty::TARGET);
+
+ // If imported information is being set, wipe out cached
+ // information.
+ if(this->IsImported() && strncmp(prop, "IMPORTED", 8) == 0)
+ {
+ this->ImportInfoMap.clear();
+ }
}
//----------------------------------------------------------------------------
@@ -1297,6 +1437,13 @@ void cmTarget::AppendProperty(const char* prop, const char* value)
return;
}
this->Properties.AppendProperty(prop, value, cmProperty::TARGET);
+
+ // If imported information is being set, wipe out cached
+ // information.
+ if(this->IsImported() && strncmp(prop, "IMPORTED", 8) == 0)
+ {
+ this->ImportInfoMap.clear();
+ }
}
//----------------------------------------------------------------------------
@@ -1319,10 +1466,11 @@ const char* cmTarget::GetDirectory(const char* config, bool implib)
}
//----------------------------------------------------------------------------
-const char* cmTarget::ImportedGetDirectory(const char* config, bool)
+const char* cmTarget::ImportedGetDirectory(const char* config, bool implib)
{
- const char* location=this->GetLocation(config);
- this->Directory = cmSystemTools::GetFilenamePath(location);
+ this->Directory =
+ cmSystemTools::GetFilenamePath(
+ this->ImportedGetFullPath(config, implib));
return this->Directory.c_str();
}
@@ -1360,18 +1508,8 @@ const char* cmTarget::GetLocation(const char* config)
//----------------------------------------------------------------------------
const char* cmTarget::ImportedGetLocation(const char* config)
{
- if ((config) && (strlen(config)))
- {
- std::string propertyName=cmSystemTools::UpperCase(config);
- propertyName+="_LOCATION";
- const char* configLocation=this->GetProperty(propertyName.c_str());
- if ((configLocation) && (strlen(configLocation)))
- {
- return configLocation;
- }
- }
-
- return this->GetProperty("LOCATION");
+ this->Location = this->ImportedGetFullPath(config, false);
+ return this->Location.c_str();
}
//----------------------------------------------------------------------------
@@ -1484,38 +1622,41 @@ const char *cmTarget::GetProperty(const char* prop,
return 0;
}
- // don't use GetLocation() for imported targets, because there this
- // calls GetProperty() to get the location...
- if (!this->IsImported())
+ // 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)
{
- // watch for special "computed" properties that are dependent on other
- // properties or variables, always recompute them
- if (!strcmp(prop,"LOCATION"))
+ if(!this->IsImported() && strcmp(prop,"LOCATION") == 0)
{
// Set the LOCATION property of the target. Note that this
// cannot take into account the per-configuration name of the
// target because the configuration type may not be known at
- // CMake time. We should deprecate this feature and instead
- // support transforming an executable target name given as the
- // command part of custom commands into the proper path at
- // build time. Alternatively we could put environment
- // variable settings in all custom commands that hold the name
- // of the target for each configuration and then give a
- // reference to the variable in the location.
+ // CMake time. It is now deprecated as described in the
+ // documentation.
this->SetProperty("LOCATION", this->GetLocation(0));
}
- // Per-configuration location can be computed.
- int len = static_cast<int>(strlen(prop));
- if(len > 9 && strcmp(prop+len-9, "_LOCATION") == 0)
+ // Support "LOCATION_<CONFIG>".
+ if(strncmp(prop, "LOCATION_", 9) == 0)
{
- std::string configName(prop, len-9);
+ std::string configName = prop+9;
this->SetProperty(prop, this->GetLocation(configName.c_str()));
}
-
- if(strcmp(prop, "OBJECT_FILES") == 0)
+ else
{
- this->ComputeObjectFiles();
+ // Support "<CONFIG>_LOCATION" for compatiblity.
+ int len = static_cast<int>(strlen(prop));
+ if(len > 9 && strcmp(prop+len-9, "_LOCATION") == 0)
+ {
+ std::string configName(prop, len-9);
+ if(configName != "IMPORTED")
+ {
+ this->SetProperty(prop, this->GetLocation(configName.c_str()));
+ }
+ }
}
}
@@ -1750,15 +1891,57 @@ std::string cmTarget::GetPDBName(const char* config)
}
//----------------------------------------------------------------------------
+std::string cmTarget::GetSOName(const char* config)
+{
+ if(this->IsImported())
+ {
+ // Lookup the imported soname.
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+ {
+ return info->SOName;
+ }
+ else
+ {
+ return "";
+ }
+ }
+ else
+ {
+ // Compute the soname that will be built.
+ std::string name;
+ std::string soName;
+ std::string realName;
+ std::string impName;
+ std::string pdbName;
+ this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
+ return soName;
+ }
+}
+
+//----------------------------------------------------------------------------
std::string cmTarget::GetFullName(const char* config, bool implib)
{
- return this->GetFullNameInternal(this->GetType(), config, implib);
+ if(this->IsImported())
+ {
+ return this->GetFullNameImported(config, implib);
+ }
+ else
+ {
+ return this->GetFullNameInternal(this->GetType(), config, implib);
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetFullNameImported(const char* config, bool implib)
+{
+ return cmSystemTools::GetFilenameName(
+ this->ImportedGetFullPath(config, implib));
}
//----------------------------------------------------------------------------
-void cmTarget::GetFullName(std::string& prefix, std::string& base,
- std::string& suffix, const char* config,
- bool implib)
+void cmTarget::GetFullNameComponents(std::string& prefix, std::string& base,
+ std::string& suffix, const char* config,
+ bool implib)
{
this->GetFullNameInternal(this->GetType(), config, implib,
prefix, base, suffix);
@@ -1767,6 +1950,19 @@ void cmTarget::GetFullName(std::string& prefix, std::string& base,
//----------------------------------------------------------------------------
std::string cmTarget::GetFullPath(const char* config, bool implib)
{
+ if(this->IsImported())
+ {
+ return this->ImportedGetFullPath(config, implib);
+ }
+ else
+ {
+ return this->NormalGetFullPath(config, implib);
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::NormalGetFullPath(const char* config, bool implib)
+{
// Start with the output directory for the target.
std::string fpath = this->GetDirectory(config, implib);
fpath += "/";
@@ -1777,8 +1973,31 @@ std::string cmTarget::GetFullPath(const char* config, bool implib)
}
//----------------------------------------------------------------------------
-std::string cmTarget::GetFullNameInternal(TargetType type, const char* config,
- bool implib)
+std::string cmTarget::ImportedGetFullPath(const char* config, bool implib)
+{
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+ {
+ if(implib)
+ {
+ return info->ImportLibrary;
+ }
+ else
+ {
+ return info->Location;
+ }
+ }
+ else
+ {
+ std::string result = this->GetName();
+ result += "-NOTFOUND";
+ return result;
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmTarget::GetFullNameInternal(TargetType type, const char* config,
+ bool implib)
{
std::string prefix;
std::string base;
@@ -1795,43 +2014,6 @@ void cmTarget::GetFullNameInternal(TargetType type,
std::string& outBase,
std::string& outSuffix)
{
- if (this->IsImported())
- {
- this->ImportedGetFullNameInternal(type, config, implib,
- outPrefix, outBase, outSuffix);
- }
- else
- {
- this->NormalGetFullNameInternal(type, config, implib,
- outPrefix, outBase, outSuffix);
- }
-}
-
-//----------------------------------------------------------------------------
-void cmTarget::ImportedGetFullNameInternal(TargetType ,
- const char* config,
- bool ,
- std::string& outPrefix,
- std::string& outBase,
- std::string& outSuffix)
-{
- // find the basename, suffix and prefix from getLocation()
- // implib ?
- std::string location=this->GetLocation(config);
- outBase=cmSystemTools::GetFilenameWithoutExtension(location);
- outSuffix = cmSystemTools::GetFilenameExtension(location);
- outPrefix = "";
-}
-
-
-//----------------------------------------------------------------------------
-void cmTarget::NormalGetFullNameInternal(TargetType type,
- const char* config,
- bool implib,
- std::string& outPrefix,
- std::string& outBase,
- std::string& outSuffix)
-{
// Use just the target name for non-main target types.
if(type != cmTarget::STATIC_LIBRARY &&
type != cmTarget::SHARED_LIBRARY &&
@@ -2019,6 +2201,14 @@ void cmTarget::GetLibraryNamesInternal(std::string& name,
TargetType type,
const char* config)
{
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if(this->IsImported())
+ {
+ abort();
+ }
+
// Construct the name of the soname flag variable for this language.
const char* ll =
this->GetLinkerLanguage(
@@ -2140,6 +2330,14 @@ void cmTarget::GetExecutableNamesInternal(std::string& name,
TargetType type,
const char* config)
{
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if(this->IsImported())
+ {
+ abort();
+ }
+
// This versioning is supported only for executables and then only
// when the platform supports symbolic links.
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -2554,8 +2752,7 @@ const char* cmTarget::GetExportMacro()
// Define the symbol for targets that export symbols.
if(this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY ||
- this->GetType() == cmTarget::EXECUTABLE &&
- this->GetPropertyAsBool("ENABLE_EXPORTS"))
+ this->IsExecutableWithExports())
{
if(const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL"))
{
@@ -2618,3 +2815,208 @@ bool cmTarget::IsChrpathAvailable()
return true;
}
+
+//----------------------------------------------------------------------------
+cmTarget::ImportInfo const*
+cmTarget::GetImportInfo(const char* config)
+{
+ // 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 && *config)
+ {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ else
+ {
+ config_upper = "NOCONFIG";
+ }
+ ImportInfoMapType::const_iterator i =
+ this->ImportInfoMap.find(config_upper);
+ if(i == this->ImportInfoMap.end())
+ {
+ ImportInfo info;
+ this->ComputeImportInfo(config_upper, info);
+ ImportInfoMapType::value_type entry(config_upper, info);
+ i = this->ImportInfoMap.insert(entry).first;
+ }
+
+ // If the location is empty then the target is not available for
+ // this configuration.
+ if(i->second.Location.empty())
+ {
+ return 0;
+ }
+
+ // Return the import information.
+ return &i->second;
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::ComputeImportInfo(std::string const& desired_config,
+ ImportInfo& info)
+{
+ // 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.
+
+ // Track the configuration-specific property suffix.
+ std::string suffix = "_";
+ suffix += desired_config;
+
+ // Look for a mapping from the current project's configuration to
+ // the imported project's configuration.
+ std::vector<std::string> mappedConfigs;
+ {
+ std::string mapProp = "MAP_IMPORTED_CONFIG_";
+ mapProp += desired_config;
+ if(const char* mapValue = this->GetProperty(mapProp.c_str()))
+ {
+ cmSystemTools::ExpandListArgument(mapValue, mappedConfigs);
+ }
+ }
+
+ // If a mapping was found, check its configurations.
+ const char* loc = 0;
+ for(std::vector<std::string>::const_iterator mci = mappedConfigs.begin();
+ !loc && mci != mappedConfigs.end(); ++mci)
+ {
+ // Look for this configuration.
+ std::string mcUpper = cmSystemTools::UpperCase(mci->c_str());
+ std::string locProp = "IMPORTED_LOCATION_";
+ locProp += mcUpper;
+ loc = this->GetProperty(locProp.c_str());
+
+ // If it was found, use it for all properties below.
+ if(loc)
+ {
+ 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)
+ {
+ return;
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations. Look for an exact-match.
+ if(!loc)
+ {
+ std::string locProp = "IMPORTED_LOCATION";
+ locProp += suffix;
+ loc = this->GetProperty(locProp.c_str());
+ }
+
+ // If we have not yet found it then there are no mapped
+ // configurations and no exact match.
+ if(!loc)
+ {
+ // 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 we have not yet found it then the project is willing to try
+ // any available configuration.
+ if(!loc)
+ {
+ 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 && aci != availableConfigs.end(); ++aci)
+ {
+ suffix = "_";
+ suffix += cmSystemTools::UpperCase(availableConfigs[0]);
+ std::string locProp = "IMPORTED_LOCATION";
+ locProp += suffix;
+ loc = this->GetProperty(locProp.c_str());
+ }
+ }
+
+ // If we have not yet found it then the target is not available.
+ if(!loc)
+ {
+ return;
+ }
+
+ // A provided configuration has been chosen. Load the
+ // configuration's properties.
+ info.Location = loc;
+
+ // Get the soname.
+ if(this->GetType() == cmTarget::SHARED_LIBRARY)
+ {
+ std::string soProp = "IMPORTED_SONAME";
+ soProp += suffix;
+ if(const char* config_soname = this->GetProperty(soProp.c_str()))
+ {
+ info.SOName = config_soname;
+ }
+ else if(const char* soname = this->GetProperty("IMPORTED_SONAME"))
+ {
+ info.SOName = soname;
+ }
+ }
+
+ // Get the import library.
+ if(this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->IsExecutableWithExports())
+ {
+ std::string impProp = "IMPORTED_IMPLIB";
+ impProp += suffix;
+ if(const char* config_implib = this->GetProperty(impProp.c_str()))
+ {
+ 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_LIBRARIES";
+ linkProp += suffix;
+ if(const char* config_libs = this->GetProperty(linkProp.c_str()))
+ {
+ cmSystemTools::ExpandListArgument(config_libs, info.LinkLibraries);
+ }
+ else if(const char* libs = this->GetProperty("IMPORTED_LINK_LIBRARIES"))
+ {
+ cmSystemTools::ExpandListArgument(libs, info.LinkLibraries);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string> const*
+cmTarget::GetImportedLinkLibraries(const char* config)
+{
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+ {
+ return &info->LinkLibraries;
+ }
+ else
+ {
+ return 0;
+ }
+}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 50e8429b60..b983629867 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -194,6 +194,11 @@ public:
bool IsImported() const {return this->IsImportedTarget;}
+ /** Get link libraries for the given configuration of an imported
+ target. */
+ std::vector<std::string> const*
+ GetImportedLinkLibraries(const char* config);
+
/** Get the directory in which this target will be built. If the
configuration name is given then the generator will add its
subdirectory for that configuration. Otherwise just the canonical
@@ -226,13 +231,16 @@ public:
/** Get the full name of the target according to the settings in its
makefile. */
std::string GetFullName(const char* config=0, bool implib = false);
- void GetFullName(std::string& prefix,
- std::string& base, std::string& suffix,
- const char* config=0, bool implib = false);
+ void GetFullNameComponents(std::string& prefix,
+ std::string& base, std::string& suffix,
+ const char* config=0, bool implib = false);
/** Get the name of the pdb file for the target. */
std::string GetPDBName(const char* config=0);
+ /** Get the soname of the target. Allowed only for a shared library. */
+ std::string GetSOName(const char* config);
+
/** Get the full path to the target according to the settings in its
makefile and the configuration type. */
std::string GetFullPath(const char* config=0, bool implib = false);
@@ -308,6 +316,10 @@ public:
// until we have per-target object file properties.
void GetLanguages(std::set<cmStdString>& languages) const;
+ /** Return whether this target is an executable with symbol exports
+ enabled. */
+ bool IsExecutableWithExports();
+
private:
/**
* A list of direct dependencies. Use in conjunction with DependencyMap.
@@ -393,20 +405,14 @@ private:
const char* ImportedGetLocation(const char* config);
const char* NormalGetLocation(const char* config);
- void NormalGetFullNameInternal(TargetType type, const char* config,
- bool implib,
- std::string& outPrefix,
- std::string& outBase,
- std::string& outSuffix);
- void ImportedGetFullNameInternal(TargetType type, const char* config,
- bool implib,
- std::string& outPrefix,
- std::string& outBase,
- std::string& outSuffix);
+ std::string GetFullNameImported(const char* config, bool implib);
const char* ImportedGetDirectory(const char* config, bool implib);
const char* NormalGetDirectory(const char* config, bool implib);
+ std::string ImportedGetFullPath(const char* config, bool implib);
+ std::string NormalGetFullPath(const char* config, bool implib);
+
private:
std::string Name;
std::vector<cmCustomCommand> PreBuildCommands;
@@ -436,6 +442,19 @@ private:
bool DLLPlatform;
bool IsImportedTarget;
+ // Cache import information from properties for each configuration.
+ struct ImportInfo
+ {
+ std::string Location;
+ std::string SOName;
+ std::string ImportLibrary;
+ std::vector<std::string> LinkLibraries;
+ };
+ typedef std::map<cmStdString, ImportInfo> ImportInfoMapType;
+ ImportInfoMapType ImportInfoMap;
+ ImportInfo const* GetImportInfo(const char* config);
+ void ComputeImportInfo(std::string const& desired_config, ImportInfo& info);
+
// The cmMakefile instance that owns this target. This should
// always be set.
cmMakefile* Makefile;