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
This commit is contained in:
Brad King 2008-01-28 08:38:36 -05:00
parent a7cb9d1120
commit 5594ad4885
52 changed files with 2230 additions and 752 deletions

View File

@ -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

View File

@ -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();

View File

@ -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))
{
this->Makefile->AddNewTarget(cmTarget::EXECUTABLE, exename.c_str(), true);
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)
{
// 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())
{

View File

@ -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."
;
}

View File

@ -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())
{

View File

@ -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);

View File

@ -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;
}
// Track inferred dependency sets implied by this list.
std::map<int, DependSet> dependSets;
// Loop over the libraries linked directly by the target.
// 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)
{
// 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))
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 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 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)

View File

@ -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;

View File

@ -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);

View File

@ -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());
}

View File

@ -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

View File

@ -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()))
{
std::string e = "detected unknown target: " + *currentTarget;
this->SetError(e.c_str());
cmSystemTools::SetFatalErrorOccured();
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
{
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)
{
// 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)))
{
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;
}
// Setup export file generation.
cmExportBuildFileGenerator ebfg;
ebfg.SetExportFile(fname.c_str());
ebfg.SetNamespace(this->Namespace.GetCString());
ebfg.SetExports(&targets);
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";
// Compute the set of configurations exported.
if(const char* types =
this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
{
std::vector<std::string> configurationTypes;
cmSystemTools::ExpandListArgument(types, configurationTypes);
for(std::vector<std::string>::const_iterator
ci = configurationTypes.begin();
ci != configurationTypes.end(); ++ci)
{
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;
}

View File

@ -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;
};

View File

@ -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";
}

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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()));
}

View File

@ -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());

View File

@ -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(

View File

@ -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;

View File

@ -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";

View File

@ -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";

View File

@ -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)

View File

@ -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 "

View File

@ -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 =

View File

@ -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.

View File

@ -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;

View File

@ -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)
// A destination is required.
cmOStringStream e;
e << args[0] << " given no DESTINATION!";
this->SetError(e.str().c_str());
return false;
}
// 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;
}
// 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 given unknown export name \"" << exportIt->c_str() << "\".";
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());
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());
if (exportGenerator->SetExportSet(exportIt->c_str(),exportSet))
{
this->Makefile->AddInstallGenerator(exportGenerator);
}
else
{
cmOStringStream e;
e << "EXPORT failed, maybe a target is exported more than once.";
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;
}

View File

@ -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 "

View File

@ -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);
}

View File

@ -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;

View File

@ -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(),

View File

@ -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);
}
/* 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)
//----------------------------------------------------------------------------
cmInstallExportGenerator::~cmInstallExportGenerator()
{
if (generator == 0) // nothing to do
delete this->EFGen;
}
//----------------------------------------------------------------------------
void cmInstallExportGenerator::ComputeTempDir()
{
// 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;
}
else
{
this->TempDir += "/";
}
if (prefix == 0)
// 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)
{
prefix = "";
}
const std::vector<std::string>& configs = generator->GetConfigurations();
if (configs.empty())
{
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;
}
}
useMD5 = true;
}
if(useMD5)
{
// Replace the destination path with a hash to keep it short.
this->TempDir +=
cmSystemTools::ComputeStringMD5(this->Destination.c_str());
}
else
{
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 true;
}
bool cmInstallExportGenerator::AddInstallLocations(cmTargetWithProperties* twp,
cmInstallFilesGenerator* generator,
const char* propertyName)
{
if (generator == 0) // nothing to do
{
return true;
}
if ((propertyName == 0) || (*propertyName == '\0'))
{
return false;
}
// check that this property doesn't exist yet and add it then
if (twp->Properties.find(propertyName) == twp->Properties.end())
{
twp->Properties[propertyName] = generator->GetDestination();
return true;
}
return false;
}
bool cmInstallExportGenerator::SetExportSet(const char* name,
const std::vector<cmTargetExport*>* set)
{
if ((name == 0) || (*name == 0) || (set==0))
{
return false;
}
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)
{
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)
{
targetWithProps = new cmTargetWithProperties((*it)->Target);
this->Targets.push_back(targetWithProps);
}
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)
{
return false;
}
if (this->AddInstallLocations(targetWithProps, (*it)->HeaderGenerator,
"PUBLIC_HEADER_LOCATION") == false)
{
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
void cmInstallExportGenerator::GenerateScript(std::ostream& os)
{
// 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;
// Get the export set requested.
ExportSet const* exportSet =
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
->GetExportSet(this->Name.c_str());
cmGeneratedFileStream exportFileStream(this->ExportFilename.c_str());
if(!exportFileStream)
// Skip empty sets.
if(!exportSet)
{
cmOStringStream e;
e << "INSTALL(EXPORT) given unknown export \"" << this->Name << "\"";
cmSystemTools::Error(e.str().c_str());
return;
}
/* 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)
// 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())
{
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";
if(this->ConfigurationName && *this->ConfigurationName)
{
this->EFGen->AddConfiguration(this->ConfigurationName);
}
else
{
this->EFGen->AddConfiguration("");
}
}
else
{
for(std::vector<std::string>::const_iterator
ci = this->ConfigurationTypes->begin();
ci != this->ConfigurationTypes->end(); ++ci)
{
this->EFGen->AddConfiguration(ci->c_str());
}
}
this->EFGen->GenerateImportFile();
// Perform the main install script generation.
this->cmInstallGenerator::GenerateScript(os);
}
//----------------------------------------------------------------------------
void
cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
Indent const& indent)
{
// 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)
{
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();
}
}
//----------------------------------------------------------------------------
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);
}

View File

@ -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

View File

@ -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.

View File

@ -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),

View File

@ -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;
}

View File

@ -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);

View File

@ -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.

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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.

View File

@ -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()))

View File

@ -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))

View File

@ -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;

View File

@ -153,6 +153,96 @@ void cmTarget::DefineProperties(cmake *cm)
"A target property that can be set to override the suffix "
"(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.",
@ -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,
@ -480,6 +596,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
{
@ -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::GetFullName(const char* config, bool implib)
std::string cmTarget::GetSOName(const char* config)
{
return this->GetFullNameInternal(this->GetType(), config, implib);
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;
}
}
//----------------------------------------------------------------------------
void cmTarget::GetFullName(std::string& prefix, std::string& base,
std::string& suffix, const char* config,
bool implib)
std::string cmTarget::GetFullName(const char* config, bool 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::GetFullNameComponents(std::string& prefix, std::string& base,
std::string& suffix, const char* config,
bool implib)
{
this->GetFullNameInternal(this->GetType(), config, implib,
prefix, base, suffix);
@ -1766,6 +1949,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);
@ -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;
@ -1794,43 +2013,6 @@ void cmTarget::GetFullNameInternal(TargetType type,
std::string& outPrefix,
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 &&
@ -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;
}
}

View File

@ -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;