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 cmExprLexer.cxx
cmExprParser.cxx cmExprParser.cxx
cmExprParserHelper.cxx cmExprParserHelper.cxx
cmExportBuildFileGenerator.h
cmExportBuildFileGenerator.cxx
cmExportFileGenerator.h
cmExportFileGenerator.cxx
cmExportInstallFileGenerator.h
cmExportInstallFileGenerator.cxx
cmExtraEclipseCDT4Generator.cxx cmExtraEclipseCDT4Generator.cxx
cmExtraEclipseCDT4Generator.h cmExtraEclipseCDT4Generator.h
cmFileTimeComparison.cxx cmFileTimeComparison.cxx

View File

@ -32,7 +32,7 @@ bool cmAddDependenciesCommand
cmTarget* target = cmTarget* target =
this->GetMakefile()->GetLocalGenerator()-> this->GetMakefile()->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, target_name.c_str(), false); GetGlobalGenerator()->FindTarget(0, target_name.c_str());
if(target) if(target)
{ {
std::vector<std::string>::const_iterator s = args.begin(); std::vector<std::string>::const_iterator s = args.begin();

View File

@ -51,7 +51,7 @@ bool cmAddExecutableCommand
++s; ++s;
excludeFromAll = true; excludeFromAll = true;
} }
else if(*s == "IMPORT") else if(*s == "IMPORTED")
{ {
++s; ++s;
importTarget = true; importTarget = true;
@ -62,11 +62,59 @@ bool cmAddExecutableCommand
} }
} }
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; 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()) 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. " "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 " "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_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 // If the second argument is "SHARED" or "STATIC", then it controls
// the type of library. Otherwise, it is treated as a source or // the type of library. Otherwise, it is treated as a source or
// source list name. There may be two keyword arguments, check for them // source list name. There may be two keyword arguments, check for them
bool haveSpecifiedType = false;
while ( s != args.end() ) while ( s != args.end() )
{ {
std::string libType = *s; std::string libType = *s;
@ -53,23 +54,26 @@ bool cmAddLibraryCommand
{ {
++s; ++s;
type = cmTarget::STATIC_LIBRARY; type = cmTarget::STATIC_LIBRARY;
haveSpecifiedType = true;
} }
else if(libType == "SHARED") else if(libType == "SHARED")
{ {
++s; ++s;
type = cmTarget::SHARED_LIBRARY; type = cmTarget::SHARED_LIBRARY;
haveSpecifiedType = true;
} }
else if(libType == "MODULE") else if(libType == "MODULE")
{ {
++s; ++s;
type = cmTarget::MODULE_LIBRARY; type = cmTarget::MODULE_LIBRARY;
haveSpecifiedType = true;
} }
else if(*s == "EXCLUDE_FROM_ALL") else if(*s == "EXCLUDE_FROM_ALL")
{ {
++s; ++s;
excludeFromAll = true; excludeFromAll = true;
} }
else if(*s == "IMPORT") else if(*s == "IMPORTED")
{ {
++s; ++s;
importTarget = true; importTarget = true;
@ -98,11 +102,46 @@ bool cmAddLibraryCommand
type = cmTarget::STATIC_LIBRARY; 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; 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()) if (s == args.end())
{ {

View File

@ -73,7 +73,26 @@ public:
"to STATIC.\n" "to STATIC.\n"
"If EXCLUDE_FROM_ALL is given the target will not be built by default. " "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 " "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); cmTypeMacro(cmAddLibraryCommand, cmCommand);

View File

@ -158,7 +158,7 @@ std::vector<cmComputeLinkDepends::LinkEntry> const&
cmComputeLinkDepends::Compute() cmComputeLinkDepends::Compute()
{ {
// Follow the link dependencies of the target to be linked. // 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. // Complete the breadth-first search of dependencies.
while(!this->BFSQueue.empty()) while(!this->BFSQueue.empty())
@ -222,8 +222,7 @@ int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
int index = lei->second; int index = lei->second;
LinkEntry& entry = this->EntryList[index]; LinkEntry& entry = this->EntryList[index];
entry.Item = item; entry.Item = item;
entry.Target = entry.Target = this->Makefile->FindTargetToUse(entry.Item.c_str());
this->GlobalGenerator->FindTarget(0, entry.Item.c_str(), false);
// If the item has dependencies queue it to follow them. // If the item has dependencies queue it to follow them.
if(entry.Target) if(entry.Target)
@ -264,8 +263,15 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
if(entry.Target) if(entry.Target)
{ {
// Follow the target dependencies. // Follow the target dependencies.
this->AddLinkEntries(depender_index, if(entry.Target->IsImported())
entry.Target->GetOriginalLinkLibraries()); {
this->AddImportedLinkEntries(depender_index, entry.Target);
}
else
{
this->AddTargetLinkEntries(depender_index,
entry.Target->GetOriginalLinkLibraries());
}
} }
else 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, void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
const char* value) const char* value)
{ {
@ -283,39 +301,49 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
std::vector<std::string> deplist; std::vector<std::string> deplist;
cmSystemTools::ExpandListArgument(value, deplist); cmSystemTools::ExpandListArgument(value, deplist);
// Construct the vector of type/value pairs from the variable. // Compute which library configuration to link.
LinkLibraryVectorType libs; cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
cmTarget::LinkLibraryType linkType = cmTarget::GENERAL; 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(); for(std::vector<std::string>::const_iterator di = deplist.begin();
di != deplist.end(); ++di) di != deplist.end(); ++di)
{ {
if(*di == "debug") if(*di == "debug")
{ {
linkType = cmTarget::DEBUG; llt = cmTarget::DEBUG;
} }
else if(*di == "optimized") else if(*di == "optimized")
{ {
linkType = cmTarget::OPTIMIZED; llt = cmTarget::OPTIMIZED;
} }
else if(*di == "general") else if(*di == "general")
{ {
linkType = cmTarget::GENERAL; llt = cmTarget::GENERAL;
} }
else if(!di->empty()) else if(!di->empty())
{ {
cmTarget::LibraryID lib(*di, linkType); if(llt == cmTarget::GENERAL || llt == linkType)
libs.push_back(lib); {
actual_libs.push_back(*di);
}
linkType = cmTarget::GENERAL; linkType = cmTarget::GENERAL;
} }
} }
// Add the entries from this list. // Add the entries from this list.
this->AddLinkEntries(depender_index, libs); this->AddLinkEntries(depender_index, actual_libs);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmComputeLinkDepends::AddLinkEntries(int depender_index, void
LinkLibraryVectorType const& libs) cmComputeLinkDepends::AddTargetLinkEntries(int depender_index,
LinkLibraryVectorType const& libs)
{ {
// Compute which library configuration to link. // Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED; cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
@ -324,23 +352,42 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
linkType = cmTarget::DEBUG; linkType = cmTarget::DEBUG;
} }
// Track inferred dependency sets implied by this list. // Look for entries meant for this configuration.
std::map<int, DependSet> dependSets; std::vector<std::string> actual_libs;
// Loop over the libraries linked directly by the target.
for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin(); for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
li != libs.end(); ++li) li != libs.end(); ++li)
{ {
// Skip entries that will resolve to the target getting linked. if(li->second == cmTarget::GENERAL || li->second == linkType)
// Skip libraries not meant for the current configuration. {
if(li->first == this->Target->GetName() || li->first.empty() || actual_libs.push_back(li->first);
!(li->second == cmTarget::GENERAL || li->second == linkType)) }
}
// 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; continue;
} }
// Add a link entry for this item. // 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. // The depender must come before the dependee.
if(depender_index >= 0) if(depender_index >= 0)

View File

@ -66,9 +66,12 @@ private:
typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType; typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType;
int AddLinkEntry(std::string const& item); int AddLinkEntry(std::string const& item);
void AddImportedLinkEntries(int depender_index, cmTarget* target);
void AddVarLinkEntries(int depender_index, const char* value); void AddVarLinkEntries(int depender_index, const char* value);
void AddTargetLinkEntries(int depender_index,
LinkLibraryVectorType const& libs);
void AddLinkEntries(int depender_index, void AddLinkEntries(int depender_index,
LinkLibraryVectorType const& libs); std::vector<std::string> const& libs);
// One entry for each unique item. // One entry for each unique item.
std::vector<LinkEntry> EntryList; 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. // Compute the proper name to use to link this library.
const char* config = this->Config; const char* config = this->Config;
bool implib = this->UseImportLibrary; bool impexe = (tgt && tgt->IsExecutableWithExports());
bool impexe = (tgt && if(impexe && !this->UseImportLibrary && !this->LoaderFlag)
tgt->GetType() == cmTarget::EXECUTABLE &&
tgt->GetPropertyAsBool("ENABLE_EXPORTS"));
if(impexe && !implib && !this->LoaderFlag)
{ {
// Skip linking to executables on platforms with no import // Skip linking to executables on platforms with no import
// libraries or loader flags. // libraries or loader flags.
@ -325,13 +322,18 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
// platform. Add it now. // platform. Add it now.
std::string linkItem; std::string linkItem;
linkItem = this->LoaderFlag; linkItem = this->LoaderFlag;
std::string exe = tgt->GetFullPath(config, implib); std::string exe = tgt->GetFullPath(config, this->UseImportLibrary);
linkItem += exe; linkItem += exe;
this->Items.push_back(Item(linkItem, true)); this->Items.push_back(Item(linkItem, true));
this->Depends.push_back(exe); this->Depends.push_back(exe);
} }
else 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. // Pass the full path to the target file.
std::string lib = tgt->GetFullPath(config, implib); std::string lib = tgt->GetFullPath(config, implib);
this->Depends.push_back(lib); 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 // Try to get the soname of the library. Only files with this name
// could possibly conflict. // could possibly conflict.
std::string soName; std::string soName = target->GetSOName(this->Config);
const char* soname = 0; const char* soname = soName.empty()? 0 : soName.c_str();
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();
}
// Add the library runtime entry. // Add the library runtime entry.
this->AddLibraryRuntimeInfo(fullPath, soname); 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 "cmGeneratedFileStream.h"
#include "cmake.h" #include "cmake.h"
#include <cmsys/auto_ptr.hxx> #include "cmExportBuildFileGenerator.h"
cmExportCommand::cmExportCommand() cmExportCommand::cmExportCommand()
:cmCommand() :cmCommand()
,ArgumentGroup() ,ArgumentGroup()
,Targets(&Helper, "TARGETS") ,Targets(&Helper, "TARGETS")
,Append(&Helper, "APPEND", &ArgumentGroup) ,Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
,Prefix(&Helper, "PREFIX", &ArgumentGroup)
,Filename(&Helper, "FILE", &ArgumentGroup) ,Filename(&Helper, "FILE", &ArgumentGroup)
{ {
// at first TARGETS // at first TARGETS
@ -53,151 +52,131 @@ bool cmExportCommand
if (!unknownArgs.empty()) if (!unknownArgs.empty())
{ {
this->SetError("Unknown arguments."); this->SetError("Unknown arguments.");
cmSystemTools::SetFatalErrorOccured();
return false; return false;
} }
if (this->Targets.WasFound() == false) if (this->Targets.WasFound() == false)
{ {
this->SetError("TARGETS option missing."); this->SetError("TARGETS option missing.");
cmSystemTools::SetFatalErrorOccured();
return false; return false;
} }
if(!this->Filename.WasFound())
if ( !this->Makefile->CanIWriteThisFile(this->Filename.GetString().c_str()) )
{ {
std::string e = "attempted to write a file: " + this->Filename.GetString() this->SetError("FILE <filename> option missing.");
+ " into a source directory.";
this->SetError(e.c_str());
cmSystemTools::SetFatalErrorOccured();
return false; 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. // Get the file to write.
cmsys::auto_ptr<std::ofstream> foutPtr; std::string fname = this->Filename.GetString();
if(this->Append.IsEnabled()) if(cmSystemTools::FileIsFullPath(fname.c_str()))
{ {
cmsys::auto_ptr<std::ofstream> ap( if(!this->Makefile->CanIWriteThisFile(fname.c_str()))
new std::ofstream(this->Filename.GetString().c_str(), std::ios::app)); {
foutPtr = ap; cmOStringStream e;
e << "FILE option given filename \"" << fname
<< "\" which is in the source tree.\n";
this->SetError(e.str().c_str());
return false;
}
} }
else else
{ {
cmsys::auto_ptr<cmGeneratedFileStream> ap( // Interpret relative paths with respect to the current build dir.
new cmGeneratedFileStream(this->Filename.GetString().c_str(), true)); fname = this->Makefile->GetCurrentOutputDirectory();
ap->SetCopyIfDifferent(true); fname += "/";
foutPtr = ap; 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; return true;
} }
// the following code may move into an "export generator" // Collect the targets to be exported.
// Compute the set of configurations. std::vector<cmTarget*> targets;
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 for(std::vector<std::string>::const_iterator
currentTarget = this->Targets.GetVector().begin(); currentTarget = this->Targets.GetVector().begin();
currentTarget != this->Targets.GetVector().end(); currentTarget != this->Targets.GetVector().end();
++currentTarget) ++currentTarget)
{ {
cmTarget* target = this->Makefile->GetLocalGenerator()-> if(cmTarget* target =
GetGlobalGenerator()->FindTarget(0, currentTarget->c_str(), true); this->Makefile->GetLocalGenerator()->
if (target == 0) GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))
{ {
std::string e = "detected unknown target: " + *currentTarget; if((target->GetType() == cmTarget::EXECUTABLE) ||
this->SetError(e.c_str()); (target->GetType() == cmTarget::STATIC_LIBRARY) ||
cmSystemTools::SetFatalErrorOccured(); (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; return false;
} }
} }
for(std::vector<std::string>::const_iterator // Setup export file generation.
currentTarget = this->Targets.GetVector().begin(); cmExportBuildFileGenerator ebfg;
currentTarget != this->Targets.GetVector().end(); ebfg.SetExportFile(fname.c_str());
++currentTarget) ebfg.SetNamespace(this->Namespace.GetCString());
{ ebfg.SetExports(&targets);
// 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;
}
fout << "SET_TARGET_PROPERTIES(" << this->Prefix.GetString().c_str() // Compute the set of configurations exported.
<< currentTarget->c_str() << " PROPERTIES \n" if(const char* types =
<<" LOCATION \""<< target->GetLocation(0)<<"\"\n"; this->Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
for(std::vector<std::string>::const_iterator {
currentConfig = configurationTypes.begin(); std::vector<std::string> configurationTypes;
currentConfig != configurationTypes.end(); cmSystemTools::ExpandListArgument(types, configurationTypes);
++currentConfig) for(std::vector<std::string>::const_iterator
{ ci = configurationTypes.begin();
if (!currentConfig->empty()) ci != configurationTypes.end(); ++ci)
{ {
const char* loc = target->GetLocation(currentConfig->c_str()); ebfg.AddConfiguration(ci->c_str());
if (loc && *loc)
{
fout << " " << currentConfig->c_str()
<< "_LOCATION \"" << loc << "\"\n";
}
}
}
fout << " )\n\n";
} }
} }
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; return true;
} }

View File

@ -55,7 +55,7 @@ public:
virtual const char* GetTerseDocumentation() virtual const char* GetTerseDocumentation()
{ {
return 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() virtual const char* GetFullDocumentation()
{ {
return return
" export(TARGETS tgt1 ... tgtN [PREFIX <prefix>] FILE <filename> " " export(TARGETS [target1 [target2 [...]]] [NAMESPACE <namespace>]\n"
"[APPEND])\n" " FILE <filename>)\n"
"Create a file that can be included into a CMake listfile with the " "Create a file <filename> that may be included by outside projects to "
"INCLUDE command. The file will contain a number of SET commands " "import targets from the current project's build tree. "
"that will set all the variables needed for library dependency " "This is useful during cross-compiling to build utility executables "
"information. This should be the last command in the top level " "that can run on the host platform in one project and then import "
"CMakeLists.txt file of the project. If the APPEND option is " "them into another project being compiled for the target platform. "
"specified, the SET commands will be appended to the given file " "If the NAMESPACE option is given the <namespace> string will be "
"instead of replacing it."; "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); cmTypeMacro(cmExportCommand, cmCommand);
@ -80,8 +88,7 @@ public:
private: private:
cmCommandArgumentGroup ArgumentGroup; cmCommandArgumentGroup ArgumentGroup;
cmCAStringVector Targets; cmCAStringVector Targets;
cmCAEnabler Append; cmCAString Namespace;
cmCAString Prefix;
cmCAString Filename; 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; return false;
} }
if(cmTarget* target = if(cmTarget* target = this->Makefile->FindTargetToUse(this->Name.c_str()))
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
->FindTarget(0, this->Name.c_str(), true))
{ {
return this->StoreResult(target->GetProperty(this->PropertyName.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(); std::string var = args[0].c_str();
const char* targetName = args[1].c_str(); const char* targetName = args[1].c_str();
cmTarget *tgt = this->Makefile->GetLocalGenerator()->GetGlobalGenerator() if(cmTarget* tgt = this->Makefile->FindTargetToUse(targetName))
->FindTarget(0, targetName, true);
if (tgt)
{ {
cmTarget& target = *tgt; cmTarget& target = *tgt;
const char *prop = target.GetProperty(args[2].c_str()); const char *prop = target.GetProperty(args[2].c_str());

View File

@ -25,7 +25,7 @@
#include "cmMakefile.h" #include "cmMakefile.h"
#include "cmSourceFile.h" #include "cmSourceFile.h"
#include "cmVersion.h" #include "cmVersion.h"
#include "cmInstallExportGenerator.h" #include "cmExportInstallFileGenerator.h"
#include <cmsys/Directory.hxx> #include <cmsys/Directory.hxx>
@ -693,7 +693,6 @@ void cmGlobalGenerator::Configure()
this->LocalGenerators.clear(); this->LocalGenerators.clear();
this->TargetDependencies.clear(); this->TargetDependencies.clear();
this->TotalTargets.clear(); this->TotalTargets.clear();
this->ImportedTotalTargets.clear();
this->LocalGeneratorToTargetMap.clear(); this->LocalGeneratorToTargetMap.clear();
this->ProjectMap.clear(); this->ProjectMap.clear();
@ -1321,9 +1320,8 @@ cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget* cmGlobalGenerator::FindTarget(const char* project, cmTarget*
const char* name, cmGlobalGenerator::FindTarget(const char* project, const char* name)
bool useImportedTargets)
{ {
// if project specific // if project specific
if(project) if(project)
@ -1331,8 +1329,7 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project,
std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project]; std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project];
for(unsigned int i = 0; i < gens->size(); ++i) for(unsigned int i = 0; i < gens->size(); ++i)
{ {
cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name, cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name);
useImportedTargets);
if(ret) if(ret)
{ {
return ret; return ret;
@ -1348,16 +1345,6 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project,
{ {
return i->second; 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; return 0;
} }
@ -1370,7 +1357,7 @@ bool cmGlobalGenerator::NameResolvesToFramework(const std::string& libname)
return true; 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 && if(tgt->GetType() == cmTarget::SHARED_LIBRARY &&
tgt->GetPropertyAsBool("FRAMEWORK")) tgt->GetPropertyAsBool("FRAMEWORK"))
@ -1758,12 +1745,12 @@ cmGlobalGenerator::ConsiderTargetDepends(cmTarget const* depender,
{ {
// Check the target's makefile first. // Check the target's makefile first.
cmTarget const* dependee = cmTarget const* dependee =
depender->GetMakefile()->FindTarget(dependee_name, false); depender->GetMakefile()->FindTarget(dependee_name);
// Then search globally. // Then search globally.
if(!dependee) if(!dependee)
{ {
dependee = this->FindTarget(0, dependee_name, false); dependee = this->FindTarget(0, dependee_name);
} }
// If not found then skip then the dependee. // If not found then skip then the dependee.
@ -1842,14 +1829,8 @@ cmGlobalGenerator
void cmGlobalGenerator::AddTarget(cmTargets::value_type &v) void cmGlobalGenerator::AddTarget(cmTargets::value_type &v)
{ {
if (v.second.IsImported()) assert(!v.second.IsImported());
{ this->TotalTargets[v.first] = &v.second;
this->ImportedTotalTargets[v.first] = &v.second;
}
else
{
this->TotalTargets[v.first] = &v.second;
}
} }
void cmGlobalGenerator::SetExternalMakefileProjectGenerator( void cmGlobalGenerator::SetExternalMakefileProjectGenerator(

View File

@ -186,9 +186,7 @@ public:
void FindMakeProgram(cmMakefile*); void FindMakeProgram(cmMakefile*);
///! Find a target by name by searching the local generators. ///! Find a target by name by searching the local generators.
cmTarget* FindTarget(const char* project, cmTarget* FindTarget(const char* project, const char* name);
const char* name,
bool useImportedTargets);
/** Determine if a name resolves to a framework on disk or a built target /** Determine if a name resolves to a framework on disk or a built target
that is a framework. */ that is a framework. */
@ -299,7 +297,6 @@ private:
// this is used to improve performance // this is used to improve performance
std::map<cmStdString,cmTarget *> TotalTargets; std::map<cmStdString,cmTarget *> TotalTargets;
std::map<cmStdString,cmTarget *> ImportedTotalTargets;
cmExternalMakefileProjectGenerator* ExtraGenerator; cmExternalMakefileProjectGenerator* ExtraGenerator;

View File

@ -399,7 +399,7 @@ void cmGlobalVisualStudio6Generator::WriteProject(std::ostream& fout,
if(j->first != dspname) if(j->first != dspname)
{ {
// is the library part of this DSW ? If so add dependency // 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 << "Begin Project Dependency\n";
fout << "Project_Dep_Name " << j->first.c_str() << "\n"; fout << "Project_Dep_Name " << j->first.c_str() << "\n";

View File

@ -338,8 +338,7 @@ cmGlobalVisualStudio71Generator
if(j->first != dspname) if(j->first != dspname)
{ {
// is the library part of this SLN ? If so add dependency // is the library part of this SLN ? If so add dependency
if(this->FindTarget(this->CurrentProject.c_str(), if(this->FindTarget(this->CurrentProject.c_str(), j->first.c_str()))
j->first.c_str(), false))
{ {
fout << "\t\t{" << this->GetGUID(j->first.c_str()) << "} = {" fout << "\t\t{" << this->GetGUID(j->first.c_str()) << "} = {"
<< this->GetGUID(j->first.c_str()) << "}\n"; << this->GetGUID(j->first.c_str()) << "}\n";

View File

@ -611,8 +611,7 @@ cmGlobalVisualStudio7Generator
if(j->first != dspname) if(j->first != dspname)
{ {
// is the library part of this SLN ? If so add dependency // is the library part of this SLN ? If so add dependency
if(this->FindTarget(this->CurrentProject.c_str(), if(this->FindTarget(this->CurrentProject.c_str(), j->first.c_str()))
j->first.c_str(), false))
{ {
std::string guid = this->GetGUID(j->first.c_str()); std::string guid = this->GetGUID(j->first.c_str());
if(guid.size() == 0) if(guid.size() == 0)

View File

@ -138,7 +138,7 @@ void cmGlobalVisualStudio8Generator::Generate()
mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
no_working_directory, no_depends, no_working_directory, no_depends,
noCommandLines); noCommandLines);
cmTarget* tgt = mf->FindTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false); cmTarget* tgt = mf->FindTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
if(!tgt) if(!tgt)
{ {
cmSystemTools::Error("Error adding target " cmSystemTools::Error("Error adding target "

View File

@ -270,7 +270,7 @@ cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target)
target.GetUtilities().begin(); target.GetUtilities().begin();
ui != target.GetUtilities().end(); ++ui) 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 || if(depTarget->GetType() == cmTarget::STATIC_LIBRARY ||
depTarget->GetType() == cmTarget::SHARED_LIBRARY || depTarget->GetType() == cmTarget::SHARED_LIBRARY ||
@ -315,7 +315,7 @@ cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget& target)
this->CreateGUID(altNameStr.c_str()); this->CreateGUID(altNameStr.c_str());
// The intermediate target should depend on the original target. // 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()); alt->AddUtility(target.GetName());
} }
@ -371,7 +371,7 @@ cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target,
{ {
// The depender is a target that links. Lookup the dependee to // The depender is a target that links. Lookup the dependee to
// see if it provides an alternative dependency name. // 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. // Check for an alternative name created by FixUtilityDepends.
if(const char* altName = if(const char* altName =

View File

@ -279,7 +279,7 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
mf->AddUtilityCommand("ALL_BUILD", true, no_depends, mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
no_working_directory, no_working_directory,
"echo", "Build all projects"); "echo", "Build all projects");
cmTarget* allbuild = mf->FindTarget("ALL_BUILD", false); cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
// Add XCODE depend helper // Add XCODE depend helper
std::string dir = mf->GetCurrentOutputDirectory(); std::string dir = mf->GetCurrentOutputDirectory();
@ -1346,7 +1346,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string pnprefix; std::string pnprefix;
std::string pnbase; std::string pnbase;
std::string pnsuffix; std::string pnsuffix;
target.GetFullName(pnprefix, pnbase, pnsuffix, configName); target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
// Store the product name for all target types. // Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME", buildSettings->AddAttribute("PRODUCT_NAME",
@ -2046,7 +2046,7 @@ void cmGlobalXCodeGenerator
{ {
// Add this dependency. // Add this dependency.
cmTarget* t = this->FindTarget(this->CurrentProject.c_str(), cmTarget* t = this->FindTarget(this->CurrentProject.c_str(),
lib->first.c_str(), false); lib->first.c_str());
cmXCodeObject* dptarget = this->FindXCodeTarget(t); cmXCodeObject* dptarget = this->FindXCodeTarget(t);
if(dptarget) if(dptarget)
{ {
@ -2062,7 +2062,7 @@ void cmGlobalXCodeGenerator
i != cmtarget->GetUtilities().end(); ++i) i != cmtarget->GetUtilities().end(); ++i)
{ {
cmTarget* t = this->FindTarget(this->CurrentProject.c_str(), 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 // 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 // on it. It may not be in this project if this is a sub
// project from the top. // project from the top.

View File

@ -51,8 +51,7 @@ bool cmIncludeExternalMSProjectCommand
// Create a target instance for this utility. // Create a target instance for this utility.
cmTarget* target=this->Makefile->AddNewTarget(cmTarget::UTILITY, cmTarget* target=this->Makefile->AddNewTarget(cmTarget::UTILITY,
utility_name.c_str(), utility_name.c_str());
false);
target->SetProperty("EXCLUDE_FROM_ALL","FALSE"); target->SetProperty("EXCLUDE_FROM_ALL","FALSE");
std::vector<std::string> no_outputs; std::vector<std::string> no_outputs;
cmCustomCommandLines commandLines; cmCustomCommandLines commandLines;

View File

@ -300,7 +300,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
++targetIt) ++targetIt)
{ {
// Lookup this target in the current directory. // 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. // Found the target. Check its type.
if(target->GetType() != cmTarget::EXECUTABLE && 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 // library. Install it to the archive destination if it
// exists. // exists.
if(dll_platform && !archiveArgs.GetDestination().empty() && if(dll_platform && !archiveArgs.GetDestination().empty() &&
target.GetPropertyAsBool("ENABLE_EXPORTS")) target.IsExecutableWithExports())
{ {
// The import library uses the ARCHIVE properties. // The import library uses the ARCHIVE properties.
archiveGenerator = CreateInstallTargetGenerator(target, archiveGenerator = CreateInstallTargetGenerator(target,
@ -1069,13 +1069,9 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
return false; return false;
} }
// Compute destination path.
std::string dest;
cmInstallCommandArguments::ComputeDestination(destination, dest);
// Create the directory install generator. // Create the directory install generator.
this->Makefile->AddInstallGenerator( this->Makefile->AddInstallGenerator(
new cmInstallDirectoryGenerator(dirs, dest.c_str(), new cmInstallDirectoryGenerator(dirs, destination,
permissions_file.c_str(), permissions_file.c_str(),
permissions_dir.c_str(), permissions_dir.c_str(),
configurations, configurations,
@ -1095,12 +1091,12 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
{ {
// This is the EXPORT mode. // This is the EXPORT mode.
cmInstallCommandArguments ica; cmInstallCommandArguments ica;
cmCAStringVector exports(&ica.Parser, "EXPORT"); cmCAString exp(&ica.Parser, "EXPORT");
cmCAString prefix(&ica.Parser, "PREFIX", &ica.ArgumentGroup); cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
cmCAString filename(&ica.Parser, "FILE", &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; std::vector<std::string> unknownArgs;
ica.Parse(&args, &unknownArgs); ica.Parse(&args, &unknownArgs);
@ -1118,44 +1114,66 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
return false; return false;
} }
std::string cmakeDir = this->Makefile->GetHomeOutputDirectory(); // Make sure there is a destination.
cmakeDir += cmake::GetCMakeFilesDirectory(); if(ica.GetDestination().empty())
for(std::vector<std::string>::const_iterator
exportIt = exports.GetVector().begin();
exportIt != exports.GetVector().end();
++exportIt)
{ {
const std::vector<cmTargetExport*>* exportSet = this-> // A destination is required.
Makefile->GetLocalGenerator()->GetGlobalGenerator()-> cmOStringStream e;
GetExportSet(exportIt->c_str()); e << args[0] << " given no DESTINATION!";
if (exportSet == 0) 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; 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()); this->SetError(e.str().c_str());
return false; 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; return true;
} }

View File

@ -98,7 +98,7 @@ public:
"file to be installed does not exist. " "file to be installed does not exist. "
"\n" "\n"
"The TARGETS signature:\n" "The TARGETS signature:\n"
" install(TARGETS targets...\n" " install(TARGETS targets... [EXPORT <export-name>]\n"
" [[ARCHIVE|LIBRARY|RUNTIME]\n" " [[ARCHIVE|LIBRARY|RUNTIME]\n"
" [DESTINATION <dir>]\n" " [DESTINATION <dir>]\n"
" [PERMISSIONS permissions...]\n" " [PERMISSIONS permissions...]\n"
@ -145,6 +145,12 @@ public:
"On non-DLL platforms mySharedLib will be installed to <prefix>/lib " "On non-DLL platforms mySharedLib will be installed to <prefix>/lib "
"and /some/full/path." "and /some/full/path."
"\n" "\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 " "Installing a target with EXCLUDE_FROM_ALL set to true has "
"undefined behavior." "undefined behavior."
"\n" "\n"
@ -248,6 +254,45 @@ public:
"For example, the code\n" "For example, the code\n"
" install(CODE \"MESSAGE(\\\"Sample install message.\\\")\")\n" " install(CODE \"MESSAGE(\\\"Sample install message.\\\")\")\n"
"will print a message during installation.\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 " "NOTE: This command supercedes the INSTALL_TARGETS command and the "
"target properties PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT. " "target properties PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT. "
"It also replaces the FILES forms of the INSTALL_FILES and " "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 const std::string& cmInstallCommandArguments::GetDestination() const
{ {
if (!this->AbsDestination.empty()) if (!this->DestinationString.empty())
{ {
return this->AbsDestination; return this->DestinationString;
} }
if (this->GenericArguments!=0) if (this->GenericArguments!=0)
{ {
@ -128,8 +128,8 @@ bool cmInstallCommandArguments::Finalize()
{ {
return false; return false;
} }
this->ComputeDestination(this->Destination.GetString(),this->AbsDestination); this->DestinationString = this->Destination.GetString();
cmSystemTools::ConvertToUnixSlashes(this->DestinationString);
return true; return true;
} }
@ -174,23 +174,3 @@ bool cmInstallCommandArguments::CheckPermissions(
// This is not a valid permission. // This is not a valid permission.
return false; 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 // once HandleDirectoryMode() is also switched to using
// cmInstallCommandArguments then these two functions can become non-static // cmInstallCommandArguments then these two functions can become non-static
// private member functions without arguments // private member functions without arguments
static void ComputeDestination(const std::string& inDest,
std::string& absDest);
static bool CheckPermissions(const std::string& onePerm, static bool CheckPermissions(const std::string& onePerm,
std::string& perm); std::string& perm);
cmCommandArgumentsHelper Parser; cmCommandArgumentsHelper Parser;
@ -57,7 +55,7 @@ class cmInstallCommandArguments
cmCAStringVector Configurations; cmCAStringVector Configurations;
cmCAEnabler Optional; cmCAEnabler Optional;
std::string AbsDestination; std::string DestinationString;
std::string PermissionsString; std::string PermissionsString;
cmInstallCommandArguments* GenericArguments; cmInstallCommandArguments* GenericArguments;

View File

@ -48,8 +48,7 @@ cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
bool not_optional = false; bool not_optional = false;
const char* no_properties = 0; const char* no_properties = 0;
const char* no_rename = 0; const char* no_rename = 0;
this->AddInstallRule(os, this->Destination.c_str(), this->AddInstallRule(os, cmTarget::INSTALL_DIRECTORY,
cmTarget::INSTALL_DIRECTORY,
this->Directories, this->Directories,
not_optional, no_properties, not_optional, no_properties,
this->FilePermissions.c_str(), this->FilePermissions.c_str(),

View File

@ -14,259 +14,198 @@
PURPOSE. See the above copyright notices for more information. PURPOSE. See the above copyright notices for more information.
=========================================================================*/ =========================================================================*/
#include "cmInstallExportGenerator.h"
#include <stdio.h> #include <stdio.h>
#include "cmake.h"
#include "cmInstallTargetGenerator.h" #include "cmInstallTargetGenerator.h"
#include "cmGeneratedFileStream.h" #include "cmGeneratedFileStream.h"
#include "cmTarget.h" #include "cmTarget.h"
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h" #include "cmInstallFilesGenerator.h"
#include "cmExportInstallFileGenerator.h"
//----------------------------------------------------------------------------
cmInstallExportGenerator::cmInstallExportGenerator( cmInstallExportGenerator::cmInstallExportGenerator(
const char* name,
const char* destination, const char* destination,
const char* file_permissions, const char* file_permissions,
std::vector<std::string> const& configurations, std::vector<std::string> const& configurations,
const char* component, 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) :cmInstallGenerator(destination, configurations, component)
,Name(name)
,FilePermissions(file_permissions) ,FilePermissions(file_permissions)
,Filename(filename) ,FileName(filename)
,Prefix(prefix) ,Namespace(name_space)
,TempOutputDir(tempOutputDir) ,Makefile(mf)
{ {
this->EFGen = new cmExportInstallFileGenerator(this);
} }
/* Helper function which adds the install locations from the generator //----------------------------------------------------------------------------
to the properties for this target. cmInstallExportGenerator::~cmInstallExportGenerator()
*/
bool cmInstallExportGenerator::AddInstallLocations(cmTargetWithProperties* twp,
cmInstallTargetGenerator* generator,
const char* prefix)
{ {
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 = ""; // 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)
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())
{ {
std::string destinationFilename = generator->GetDestination(); useMD5 = true;
destinationFilename += "/";
destinationFilename += generator->GetInstallFilename(0);
twp->Properties[propertyName.c_str()] = destinationFilename;
}
else
{
return false;
} }
} }
else else
{ {
for(std::vector<std::string>::const_iterator configIt = configs.begin(); useMD5 = true;
configIt != configs.end(); }
++configIt) if(useMD5)
{ {
std::string propertyName = configIt->c_str(); // Replace the destination path with a hash to keep it short.
propertyName += "_"; this->TempDir +=
propertyName += prefix; cmSystemTools::ComputeStringMD5(this->Destination.c_str());
propertyName += "LOCATION"; }
// check that this property doesn't exist yet and add it then else
if (twp->Properties.find(propertyName.c_str()) == twp->Properties.end()) {
{ std::string dest = this->Destination;
std::string destinationFilename = generator->GetDestination(); // Avoid unix full paths.
destinationFilename += "/"; if(dest[0] == '/')
destinationFilename +=generator->GetInstallFilename(configIt->c_str()); {
twp->Properties[propertyName.c_str()] = destinationFilename; dest[0] = '_';
} }
else // Avoid windows full paths by removing colons.
{ cmSystemTools::ReplaceString(dest, ":", "_");
return false; // 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) void cmInstallExportGenerator::GenerateScript(std::ostream& os)
{ {
// for the case that somebody exports the same set with the same file name // Get the export set requested.
// to different locations make the temp filename unique ExportSet const* exportSet =
char buf[64]; this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
sprintf(buf, "%p", this); ->GetExportSet(this->Name.c_str());
this->ExportFilename = this->TempOutputDir;
this->ExportFilename += "/";
this->ExportFilename += this->Filename;
this->ExportFilename += ".";
this->ExportFilename += buf;
cmGeneratedFileStream exportFileStream(this->ExportFilename.c_str()); // Skip empty sets.
if(!exportFileStream) if(!exportSet)
{ {
cmOStringStream e;
e << "INSTALL(EXPORT) given unknown export \"" << this->Name << "\"";
cmSystemTools::Error(e.str().c_str());
return; return;
} }
/* for every target add the IMPORT statements and set the properties // Create the temporary directory in which to store the files.
of the target. */ this->ComputeTempDir();
for(std::vector<cmTargetWithProperties*>::const_iterator cmSystemTools::MakeDirectory(this->TempDir.c_str());
targetIt = this->Targets.begin();
targetIt != this->Targets.end(); // Construct a temporary location for the file.
++targetIt) 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()) if(this->ConfigurationName && *this->ConfigurationName)
{ {
case cmTarget::EXECUTABLE: this->EFGen->AddConfiguration(this->ConfigurationName);
exportFileStream << "ADD_EXECUTABLE(" << this->Prefix.c_str() }
<< (*targetIt)->Target->GetName() else
<< " IMPORT )\n"; {
break; this->EFGen->AddConfiguration("");
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";
} }
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. // Perform the main install script generation.
this->cmInstallGenerator::GenerateScript(os); 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, void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
Indent const& indent) Indent const& indent)
{ {
// install rule for the file created above // Install the main export file.
std::vector<std::string> exportFile; std::vector<std::string> files;
exportFile.push_back(this->ExportFilename); files.push_back(this->MainImportFile);
this->AddInstallRule(os, this->Destination.c_str(), cmTarget::INSTALL_FILES, this->AddInstallRule(os, cmTarget::INSTALL_FILES, files, false, 0,
exportFile, false, 0, this->FilePermissions.c_str(), 0, 0, 0, indent);
this->FilePermissions.c_str(),
0, this->Filename.c_str(), 0, indent);
} }

View File

@ -19,42 +19,12 @@
#include "cmInstallGenerator.h" #include "cmInstallGenerator.h"
class cmTarget; class cmExportInstallFileGenerator;
class cmInstallTargetGenerator;
class cmInstallFilesGenerator; class cmInstallFilesGenerator;
class cmInstallTargetGenerator;
/* cmInstallExportTarget is used in cmGlobalGenerator to collect the class cmTarget;
install generators for the exported targets. These are then used by the class cmTargetExport;
cmInstallExportGenerator. class cmMakefile;
*/
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 cmInstallExportGenerator /** \class cmInstallExportGenerator
* \brief Generate rules for creating an export files. * \brief Generate rules for creating an export files.
@ -62,45 +32,33 @@ private:
class cmInstallExportGenerator: public cmInstallGenerator class cmInstallExportGenerator: public cmInstallGenerator
{ {
public: 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 std::vector<std::string>& configurations,
const char* component, const char* component,
const char* filename, const char* prefix, const char* filename, const char* name_space,
const char* tempOutputDir); cmMakefile* mf);
~cmInstallExportGenerator();
bool SetExportSet(const char* name,
const std::vector<cmTargetExport*>* exportSet);
protected: protected:
// internal class which collects all the properties which will be set typedef std::vector<cmTargetExport*> ExportSet;
// 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 cmInstallGeneratorIndent Indent; typedef cmInstallGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os); virtual void GenerateScript(std::ostream& os);
virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent);
virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); virtual void GenerateScriptActions(std::ostream& os, Indent const& indent);
static bool AddInstallLocations(cmTargetWithProperties *twp, void GenerateImportFile(ExportSet const* exportSet);
cmInstallTargetGenerator* generator, void GenerateImportFile(const char* config, ExportSet const* exportSet);
const char* prefix); void ComputeTempDir();
static bool AddInstallLocations(cmTargetWithProperties* twp,
cmInstallFilesGenerator* generator,
const char* propertyName);
std::string Name; std::string Name;
std::string FilePermissions; std::string FilePermissions;
std::string Filename; std::string FileName;
std::string Prefix; std::string Namespace;
std::string TempOutputDir; cmMakefile* Makefile;
std::string ExportFilename;
std::vector<cmTargetWithProperties*> Targets; std::string TempDir;
std::string MainImportFile;
cmExportInstallFileGenerator* EFGen;
}; };
#endif #endif

View File

@ -119,9 +119,8 @@ void cmInstallFilesCommand::FinalPass()
void cmInstallFilesCommand::CreateInstallGenerator() const void cmInstallFilesCommand::CreateInstallGenerator() const
{ {
// Construct the destination. This command always installs under // Construct the destination. This command always installs under
// the prefix. // the prefix. We skip the leading slash given by the user.
std::string destination = "${CMAKE_INSTALL_PREFIX}"; std::string destination = this->Destination.substr(1);
destination += this->Destination;
cmSystemTools::ConvertToUnixSlashes(destination); cmSystemTools::ConvertToUnixSlashes(destination);
// Use a file install generator. // Use a file install generator.

View File

@ -47,7 +47,7 @@ void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
// Write code to install the files. // Write code to install the files.
const char* no_properties = 0; const char* no_properties = 0;
const char* no_dir_permissions = 0; const char* no_dir_permissions = 0;
this->AddInstallRule(os, this->Destination.c_str(), this->AddInstallRule(os,
(this->Programs (this->Programs
? cmTarget::INSTALL_PROGRAMS ? cmTarget::INSTALL_PROGRAMS
: cmTarget::INSTALL_FILES), : cmTarget::INSTALL_FILES),

View File

@ -55,7 +55,6 @@ cmInstallGenerator
void cmInstallGenerator void cmInstallGenerator
::AddInstallRule( ::AddInstallRule(
std::ostream& os, std::ostream& os,
const char* dest,
int type, int type,
std::vector<std::string> const& files, std::vector<std::string> const& files,
bool optional /* = false */, bool optional /* = false */,
@ -81,6 +80,7 @@ void cmInstallGenerator
default: stype = "FILE"; break; default: stype = "FILE"; break;
} }
os << indent; os << indent;
std::string dest = this->GetInstallDestination();
os << "FILE(INSTALL DESTINATION \"" << dest << "\" TYPE " << stype.c_str(); os << "FILE(INSTALL DESTINATION \"" << dest << "\" TYPE " << stype.c_str();
if(optional) if(optional)
{ {
@ -238,3 +238,40 @@ void cmInstallGenerator::GenerateScriptActions(std::ostream&, Indent const&)
{ {
// No actions for this generator. // 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, void Generate(std::ostream& os, const char* config,
std::vector<std::string> const& configurationTypes); std::vector<std::string> const& configurationTypes);
static void AddInstallRule( void AddInstallRule(
std::ostream& os, const char* dest, int type, std::ostream& os, int type,
std::vector<std::string> const& files, std::vector<std::string> const& files,
bool optional = false, bool optional = false,
const char* properties = 0, const char* properties = 0,
@ -78,6 +78,14 @@ public:
{ return this->Destination.c_str(); } { return this->Destination.c_str(); }
const std::vector<std::string>& GetConfigurations() const const std::vector<std::string>& GetConfigurations() const
{ return this->Configurations; } { 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: protected:
typedef cmInstallGeneratorIndent Indent; typedef cmInstallGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os); virtual void GenerateScript(std::ostream& os);

View File

@ -80,9 +80,8 @@ void cmInstallProgramsCommand::FinalPass()
} }
// Construct the destination. This command always installs under // Construct the destination. This command always installs under
// the prefix. // the prefix. We skip the leading slash given by the user.
std::string destination = "${CMAKE_INSTALL_PREFIX}"; std::string destination = this->Destination.substr(1);
destination += this->Destination;
cmSystemTools::ConvertToUnixSlashes(destination); cmSystemTools::ConvertToUnixSlashes(destination);
// Use a file install generator. // Use a file install generator.

View File

@ -113,22 +113,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
if(config && *config) if(config && *config)
{ {
std::string config_upper = cmSystemTools::UpperCase(config);
// Skip this configuration for config-specific installation that // Skip this configuration for config-specific installation that
// does not match it. // does not match it.
if(!this->Configurations.empty()) if(!this->InstallsForConfig(config))
{ {
bool found = false; return;
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;
}
} }
// Generate a per-configuration block. // Generate a per-configuration block.
@ -154,7 +143,7 @@ cmInstallTargetGenerator
Indent const& indent) Indent const& indent)
{ {
// Compute the full path to the main installed file for this target. // Compute the full path to the main installed file for this target.
std::string toInstallPath = this->Destination; std::string toInstallPath = this->GetInstallDestination();
toInstallPath += "/"; toInstallPath += "/";
toInstallPath += this->GetInstallFilename(this->Target, config, toInstallPath += this->GetInstallFilename(this->Target, config,
this->ImportLibrary, false); this->ImportLibrary, false);
@ -279,7 +268,7 @@ cmInstallTargetGenerator
const char* no_rename = 0; const char* no_rename = 0;
const char* no_properties = 0; const char* no_properties = 0;
bool optional = this->Optional || this->ImportLibrary; bool optional = this->Optional || this->ImportLibrary;
this->AddInstallRule(os, this->Destination.c_str(), type, files, this->AddInstallRule(os, type, files,
optional, no_properties, optional, no_properties,
this->FilePermissions.c_str(), no_dir_permissions, this->FilePermissions.c_str(), no_dir_permissions,
no_rename, literal_args.c_str(), no_rename, literal_args.c_str(),
@ -412,7 +401,7 @@ cmInstallTargetGenerator
{ {
if(cmTarget* tgt = this->Target->GetMakefile()-> if(cmTarget* tgt = this->Target->GetMakefile()->
GetLocalGenerator()->GetGlobalGenerator()-> GetLocalGenerator()->GetGlobalGenerator()->
FindTarget(0, lib.c_str(), false)) FindTarget(0, lib.c_str()))
{ {
if(tgt->GetType() == cmTarget::SHARED_LIBRARY) if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
{ {

View File

@ -40,6 +40,9 @@ public:
static std::string GetInstallFilename(cmTarget*target, const char* config, static std::string GetInstallFilename(cmTarget*target, const char* config,
bool implib, bool useSOName); bool implib, bool useSOName);
cmTarget* GetTarget() const { return this->Target; }
bool IsImportLibrary() const { return this->ImportLibrary; }
protected: protected:
typedef cmInstallGeneratorIndent Indent; typedef cmInstallGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os); 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. // 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 // make sure it is not just a coincidence that the target name
// found is part of the inName // found is part of the inName
@ -1876,7 +1876,7 @@ std::string cmLocalGenerator::GetRealLocation(const char* inName,
std::string outName=inName; std::string outName=inName;
// Look for a CMake target with the given name, which is an executable // Look for a CMake target with the given name, which is an executable
// and which can be run // and which can be run
cmTarget* target = this->GlobalGenerator->FindTarget(0, inName, true); cmTarget* target = this->Makefile->FindTargetToUse(inName);
if ((target != 0) if ((target != 0)
&& (target->GetType() == cmTarget::EXECUTABLE) && (target->GetType() == cmTarget::EXECUTABLE)
&& ((this->Makefile->IsOn("CMAKE_CROSSCOMPILING") == false) && ((this->Makefile->IsOn("CMAKE_CROSSCOMPILING") == false)
@ -2348,8 +2348,8 @@ cmLocalGenerator
{ {
// Compute the full install destination. Note that converting // Compute the full install destination. Note that converting
// to unix slashes also removes any trailing slash. // to unix slashes also removes any trailing slash.
std::string destination = "${CMAKE_INSTALL_PREFIX}"; // We also skip over the leading slash given by the user.
destination += l->second.GetInstallPath(); std::string destination = l->second.GetInstallPath().substr(1);
cmSystemTools::ConvertToUnixSlashes(destination); cmSystemTools::ConvertToUnixSlashes(destination);
// Generate the proper install generator for this target type. // Generate the proper install generator for this target type.
@ -2372,8 +2372,8 @@ cmLocalGenerator
// destination. // destination.
cmInstallTargetGenerator g1(l->second, destination.c_str(), true); cmInstallTargetGenerator g1(l->second, destination.c_str(), true);
g1.Generate(os, config, configurationTypes); g1.Generate(os, config, configurationTypes);
destination = "${CMAKE_INSTALL_PREFIX}"; // We also skip over the leading slash given by the user.
destination += l->second.GetRuntimeInstallPath(); destination = l->second.GetRuntimeInstallPath().substr(1);
cmSystemTools::ConvertToUnixSlashes(destination); cmSystemTools::ConvertToUnixSlashes(destination);
cmInstallTargetGenerator g2(l->second, destination.c_str(), false); cmInstallTargetGenerator g2(l->second, destination.c_str(), false);
g2.Generate(os, config, configurationTypes); g2.Generate(os, config, configurationTypes);

View File

@ -1061,8 +1061,7 @@ void cmLocalVisualStudio6Generator
// Compute the proper name to use to link this library. // Compute the proper name to use to link this library.
std::string lib; std::string lib;
std::string libDebug; std::string libDebug;
cmTarget* tgt = this->GlobalGenerator->FindTarget(0, j->first.c_str(), cmTarget* tgt = this->GlobalGenerator->FindTarget(0, j->first.c_str());
false);
if(tgt) if(tgt)
{ {
lib = cmSystemTools::GetFilenameWithoutExtension lib = cmSystemTools::GetFilenameWithoutExtension

View File

@ -37,6 +37,8 @@
#include <cmsys/RegularExpression.hxx> #include <cmsys/RegularExpression.hxx>
#include <cmsys/auto_ptr.hxx>
#include <ctype.h> // for isspace #include <ctype.h> // for isspace
// default is not to be building executables // default is not to be building executables
@ -176,6 +178,12 @@ cmMakefile::~cmMakefile()
{ {
delete *i; 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++) for(unsigned int i=0; i < this->UsedCommands.size(); i++)
{ {
delete this->UsedCommands[i]; delete this->UsedCommands[i];
@ -824,7 +832,7 @@ void cmMakefile::AddUtilityCommand(const char* utilityName,
bool escapeOldStyle, const char* comment) bool escapeOldStyle, const char* comment)
{ {
// Create a target instance for this utility. // Create a target instance for this utility.
cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName, false); cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName);
if (excludeFromAll) if (excludeFromAll)
{ {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
@ -1005,7 +1013,7 @@ void cmMakefile::AddLinkLibraryForTarget(const char *target,
if ( i != this->Targets.end()) if ( i != this->Targets.end())
{ {
cmTarget* tgt = cmTarget* tgt =
this->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(0,lib,false); this->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(0,lib);
if(tgt) if(tgt)
{ {
bool allowModules = true; 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 it is not a static or shared library then you can not link to it
if(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) || if(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) ||
(tgt->GetType() == cmTarget::SHARED_LIBRARY) || (tgt->GetType() == cmTarget::SHARED_LIBRARY) ||
(tgt->GetType() == cmTarget::EXECUTABLE && tgt->IsExecutableWithExports()))
tgt->GetPropertyAsBool("ENABLE_EXPORTS"))))
{ {
cmOStringStream e; cmOStringStream e;
e << "Attempt to add link target " << lib << " of type: " e << "Attempt to add link target " << lib << " of type: "
@ -1162,6 +1169,9 @@ void cmMakefile::InitializeFromParent()
// Copy include regular expressions. // Copy include regular expressions.
this->IncludeFileRegularExpression = parent->IncludeFileRegularExpression; this->IncludeFileRegularExpression = parent->IncludeFileRegularExpression;
this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression; this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression;
// Imported targets.
this->ImportedTargets = parent->ImportedTargets;
} }
void cmMakefile::ConfigureSubDirectory(cmLocalGenerator *lg2) void cmMakefile::ConfigureSubDirectory(cmLocalGenerator *lg2)
@ -1467,7 +1477,7 @@ void cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
type = cmTarget::STATIC_LIBRARY; type = cmTarget::STATIC_LIBRARY;
} }
cmTarget* target = this->AddNewTarget(type, lname, false); cmTarget* target = this->AddNewTarget(type, lname);
// Clear its dependencies. Otherwise, dependencies might persist // Clear its dependencies. Otherwise, dependencies might persist
// over changes in CMakeLists.txt, making the information stale and // over changes in CMakeLists.txt, making the information stale and
// hence useless. // hence useless.
@ -1484,7 +1494,7 @@ cmTarget* cmMakefile::AddExecutable(const char *exeName,
const std::vector<std::string> &srcs, const std::vector<std::string> &srcs,
bool excludeFromAll) bool excludeFromAll)
{ {
cmTarget* target = this->AddNewTarget(cmTarget::EXECUTABLE, exeName, false); cmTarget* target = this->AddNewTarget(cmTarget::EXECUTABLE, exeName);
if(excludeFromAll) if(excludeFromAll)
{ {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
@ -1494,26 +1504,16 @@ cmTarget* cmMakefile::AddExecutable(const char *exeName,
return target; return target;
} }
//----------------------------------------------------------------------------
cmTarget* cmMakefile::AddNewTarget(cmTarget::TargetType type, cmTarget*
const char* name, cmMakefile::AddNewTarget(cmTarget::TargetType type, const char* name)
bool isImported)
{ {
cmTargets::iterator it; cmTargets::iterator it;
cmTarget target; cmTarget target;
target.SetType(type, name); target.SetType(type, name);
target.SetMakefile(this); target.SetMakefile(this);
if (isImported) it=this->Targets.insert(
{ cmTargets::value_type(target.GetName(), target)).first;
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;
}
this->LocalGenerator->GetGlobalGenerator()->AddTarget(*it); this->LocalGenerator->GetGlobalGenerator()->AddTarget(*it);
return &it->second; 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(); cmTargets& tgts = this->GetTargets();
@ -2879,15 +2879,6 @@ cmTarget* cmMakefile::FindTarget(const char* name, bool useImportedTargets)
return &i->second; return &i->second;
} }
if (useImportedTargets)
{
cmTargets::iterator impTarget = this->ImportedTargets.find(name);
if (impTarget != this->ImportedTargets.end())
{
return &impTarget->second;
}
}
return 0; return 0;
} }
@ -3091,3 +3082,37 @@ void cmMakefile::DefineProperties(cmake *cm)
"The same concept applies to the default build of other generators.", "The same concept applies to the default build of other generators.",
false); 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 AddDefineFlag(const char* definition);
void RemoveDefineFlag(const char* definition); void RemoveDefineFlag(const char* definition);
cmTarget* AddNewTarget(cmTarget::TargetType type, /** Create a new imported target with the name and type given. */
const char* name, cmTarget* AddImportedTarget(const char* name, cmTarget::TargetType type);
bool isImported);
cmTarget* AddNewTarget(cmTarget::TargetType type, const char* name);
/** /**
* Add an executable to the build. * Add an executable to the build.
@ -436,10 +437,12 @@ public:
* Get the list of targets, const version * Get the list of targets, const version
*/ */
const cmTargets &GetTargets() const { return this->Targets; } 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. * Get a list of include directories in the build.
@ -766,7 +769,6 @@ protected:
// libraries, classes, and executables // libraries, classes, and executables
cmTargets Targets; cmTargets Targets;
cmTargets ImportedTargets;
std::vector<cmSourceFile*> SourceFiles; std::vector<cmSourceFile*> SourceFiles;
// Tests // Tests
@ -842,6 +844,10 @@ private:
// stack of list files being read // stack of list files being read
std::deque<cmStdString> ListFileStack; 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. // Add symbol export flags if necessary.
if(this->Target->GetPropertyAsBool("ENABLE_EXPORTS")) if(this->Target->IsExecutableWithExports())
{ {
std::string export_flag_var = "CMAKE_EXE_EXPORTS_"; std::string export_flag_var = "CMAKE_EXE_EXPORTS_";
export_flag_var += linkLanguage; export_flag_var += linkLanguage;
@ -351,7 +351,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->Makefile->GetRequiredDefinition(linkRuleVar.c_str()); this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
std::vector<std::string> commands1; std::vector<std::string> commands1;
cmSystemTools::ExpandListArgument(linkRule, real_link_commands); 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 // If a separate rule for creating an import library is specified
// add it now. // add it now.

View File

@ -869,7 +869,7 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
for(cmTarget::LinkLibraryVectorType::const_iterator j = libs.begin(); for(cmTarget::LinkLibraryVectorType::const_iterator j = libs.begin();
j != libs.end(); ++j) 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) if(emitted.insert(linkee).second)
{ {
@ -1371,7 +1371,7 @@ void cmMakefileTargetGenerator
{ {
// Depend on other CMake targets. // Depend on other CMake targets.
if(cmTarget* tgt = if(cmTarget* tgt =
this->GlobalGenerator->FindTarget(0, lib->first.c_str(), false)) this->GlobalGenerator->FindTarget(0, lib->first.c_str()))
{ {
if(const char* location = if(const char* location =
tgt->GetLocation(this->LocalGenerator->ConfigurationName.c_str())) 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(); for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
ni != this->Names.end(); ++ni) ni != this->Names.end(); ++ni)
{ {
if(cmTarget* target = if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str()))
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
->FindTarget(0, ni->c_str(), true))
{ {
// Handle the current target. // Handle the current target.
if(!this->HandleTarget(target)) if(!this->HandleTarget(target))

View File

@ -95,9 +95,7 @@ bool cmSetTargetPropertiesCommand
std::vector<std::string> &propertyPairs, std::vector<std::string> &propertyPairs,
cmMakefile *mf) cmMakefile *mf)
{ {
cmTarget* target = if(cmTarget* target = mf->FindTargetToUse(tname))
mf->GetLocalGenerator()->GetGlobalGenerator()->FindTarget(0, tname, true);
if ( target)
{ {
// now loop through all the props and set them // now loop through all the props and set them
unsigned int k; 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 " "A target property that can be set to override the suffix "
"(such as \".lib\") on an import library name."); "(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 cm->DefineProperty
("EXCLUDE_FROM_ALL", cmProperty::TARGET, ("EXCLUDE_FROM_ALL", cmProperty::TARGET,
"Exclude the target from the all target.", "Exclude the target from the all target.",
@ -206,11 +296,37 @@ void cmTarget::DefineProperties(cmake *cm)
cm->DefineProperty cm->DefineProperty
("LOCATION", cmProperty::TARGET, ("LOCATION", cmProperty::TARGET,
"Where a target will be written on disk.", "Deprecated. Use LOCATION_<CONFIG> or avoid altogether.",
"A read only property on a target that indicates where that target " "This property is provided for compatibility with CMake 2.4 and below. "
"will be written. For libraries and executables this will be where " "It was meant to get the location of an executable target's output file "
"the file is written on disk. This property is computed based on a " "for use in add_custom_command. "
"number of other settings."); "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 cm->DefineProperty
("OUTPUT_NAME", cmProperty::TARGET, ("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 class cmTargetTraceDependencies
{ {
@ -603,8 +738,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
} }
// Check for a non-imported target with this name. // Check for a non-imported target with this name.
if(cmTarget* t = if(cmTarget* t = this->GlobalGenerator->FindTarget(0, util.c_str()))
this->GlobalGenerator->FindTarget(0, util.c_str(), false))
{ {
// If we find the target and the dep was given as a full path, // 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 // then make sure it was not a full path to something else, and
@ -671,8 +805,7 @@ cmTargetTraceDependencies
{ {
std::string const& command = *cit->begin(); std::string const& command = *cit->begin();
// Look for a non-imported target with this name. // Look for a non-imported target with this name.
if(cmTarget* t = if(cmTarget* t = this->GlobalGenerator->FindTarget(0, command.c_str()))
this->GlobalGenerator->FindTarget(0, command.c_str(), false))
{ {
if(t->GetType() == cmTarget::EXECUTABLE) 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); 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; return;
} }
this->Properties.AppendProperty(prop, value, cmProperty::TARGET); 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 =
this->Directory = cmSystemTools::GetFilenamePath(location); cmSystemTools::GetFilenamePath(
this->ImportedGetFullPath(config, implib));
return this->Directory.c_str(); return this->Directory.c_str();
} }
@ -1360,18 +1508,8 @@ const char* cmTarget::GetLocation(const char* config)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
const char* cmTarget::ImportedGetLocation(const char* config) const char* cmTarget::ImportedGetLocation(const char* config)
{ {
if ((config) && (strlen(config))) this->Location = this->ImportedGetFullPath(config, false);
{ return this->Location.c_str();
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");
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1484,38 +1622,41 @@ const char *cmTarget::GetProperty(const char* prop,
return 0; return 0;
} }
// don't use GetLocation() for imported targets, because there this // Watch for special "computed" properties that are dependent on
// calls GetProperty() to get the location... // other properties or variables. Always recompute them.
if (!this->IsImported()) 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 if(!this->IsImported() && strcmp(prop,"LOCATION") == 0)
// properties or variables, always recompute them
if (!strcmp(prop,"LOCATION"))
{ {
// Set the LOCATION property of the target. Note that this // Set the LOCATION property of the target. Note that this
// cannot take into account the per-configuration name of the // cannot take into account the per-configuration name of the
// target because the configuration type may not be known at // target because the configuration type may not be known at
// CMake time. We should deprecate this feature and instead // CMake time. It is now deprecated as described in the
// support transforming an executable target name given as the // documentation.
// 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.
this->SetProperty("LOCATION", this->GetLocation(0)); this->SetProperty("LOCATION", this->GetLocation(0));
} }
// Per-configuration location can be computed. // Support "LOCATION_<CONFIG>".
int len = static_cast<int>(strlen(prop)); if(strncmp(prop, "LOCATION_", 9) == 0)
if(len > 9 && strcmp(prop+len-9, "_LOCATION") == 0)
{ {
std::string configName(prop, len-9); std::string configName = prop+9;
this->SetProperty(prop, this->GetLocation(configName.c_str())); this->SetProperty(prop, this->GetLocation(configName.c_str()));
} }
else
if(strcmp(prop, "OBJECT_FILES") == 0)
{ {
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 cmTarget::GetFullName(const char* config, bool implib)
std::string& suffix, 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, this->GetFullNameInternal(this->GetType(), config, implib,
prefix, base, suffix); 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) 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. // Start with the output directory for the target.
std::string fpath = this->GetDirectory(config, implib); 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, std::string cmTarget::ImportedGetFullPath(const char* config, bool implib)
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 prefix;
std::string base; std::string base;
@ -1794,43 +2013,6 @@ void cmTarget::GetFullNameInternal(TargetType type,
std::string& outPrefix, std::string& outPrefix,
std::string& outBase, std::string& outBase,
std::string& outSuffix) 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. // Use just the target name for non-main target types.
if(type != cmTarget::STATIC_LIBRARY && if(type != cmTarget::STATIC_LIBRARY &&
@ -2019,6 +2201,14 @@ void cmTarget::GetLibraryNamesInternal(std::string& name,
TargetType type, TargetType type,
const char* config) 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. // Construct the name of the soname flag variable for this language.
const char* ll = const char* ll =
this->GetLinkerLanguage( this->GetLinkerLanguage(
@ -2140,6 +2330,14 @@ void cmTarget::GetExecutableNamesInternal(std::string& name,
TargetType type, TargetType type,
const char* config) 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 // This versioning is supported only for executables and then only
// when the platform supports symbolic links. // when the platform supports symbolic links.
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
@ -2554,8 +2752,7 @@ const char* cmTarget::GetExportMacro()
// Define the symbol for targets that export symbols. // Define the symbol for targets that export symbols.
if(this->GetType() == cmTarget::SHARED_LIBRARY || if(this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY ||
this->GetType() == cmTarget::EXECUTABLE && this->IsExecutableWithExports())
this->GetPropertyAsBool("ENABLE_EXPORTS"))
{ {
if(const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL")) if(const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL"))
{ {
@ -2618,3 +2815,208 @@ bool cmTarget::IsChrpathAvailable()
return true; 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;} 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 /** Get the directory in which this target will be built. If the
configuration name is given then the generator will add its configuration name is given then the generator will add its
subdirectory for that configuration. Otherwise just the canonical 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 /** Get the full name of the target according to the settings in its
makefile. */ makefile. */
std::string GetFullName(const char* config=0, bool implib = false); std::string GetFullName(const char* config=0, bool implib = false);
void GetFullName(std::string& prefix, void GetFullNameComponents(std::string& prefix,
std::string& base, std::string& suffix, std::string& base, std::string& suffix,
const char* config=0, bool implib = false); const char* config=0, bool implib = false);
/** Get the name of the pdb file for the target. */ /** Get the name of the pdb file for the target. */
std::string GetPDBName(const char* config=0); 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 /** Get the full path to the target according to the settings in its
makefile and the configuration type. */ makefile and the configuration type. */
std::string GetFullPath(const char* config=0, bool implib = false); std::string GetFullPath(const char* config=0, bool implib = false);
@ -308,6 +316,10 @@ public:
// until we have per-target object file properties. // until we have per-target object file properties.
void GetLanguages(std::set<cmStdString>& languages) const; void GetLanguages(std::set<cmStdString>& languages) const;
/** Return whether this target is an executable with symbol exports
enabled. */
bool IsExecutableWithExports();
private: private:
/** /**
* A list of direct dependencies. Use in conjunction with DependencyMap. * A list of direct dependencies. Use in conjunction with DependencyMap.
@ -393,20 +405,14 @@ private:
const char* ImportedGetLocation(const char* config); const char* ImportedGetLocation(const char* config);
const char* NormalGetLocation(const char* config); const char* NormalGetLocation(const char* config);
void NormalGetFullNameInternal(TargetType type, const char* config, std::string GetFullNameImported(const char* config, bool implib);
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);
const char* ImportedGetDirectory(const char* config, bool implib); const char* ImportedGetDirectory(const char* config, bool implib);
const char* NormalGetDirectory(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: private:
std::string Name; std::string Name;
std::vector<cmCustomCommand> PreBuildCommands; std::vector<cmCustomCommand> PreBuildCommands;
@ -436,6 +442,19 @@ private:
bool DLLPlatform; bool DLLPlatform;
bool IsImportedTarget; 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 // The cmMakefile instance that owns this target. This should
// always be set. // always be set.
cmMakefile* Makefile; cmMakefile* Makefile;