ENH: add INSTALL(EXPORT ...) mode and INSTALL( TARGETS ... EXPORT <set> ) ,

tests still have to be added

Alex
This commit is contained in:
Alexander Neundorf 2007-06-19 13:10:21 -04:00
parent 617602e9e9
commit c0d000d234
7 changed files with 565 additions and 3 deletions

View File

@ -115,6 +115,7 @@ SET(SRCS
cmGlobalUnixMakefileGenerator3.h
cmInstallGenerator.h
cmInstallGenerator.cxx
cmInstallExportGenerator.cxx
cmInstallFilesGenerator.h
cmInstallFilesGenerator.cxx
cmInstallScriptGenerator.h

View File

@ -21,6 +21,7 @@
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmVersion.h"
#include "cmInstallExportGenerator.h"
#include <stdlib.h> // required for atof
@ -56,8 +57,7 @@ cmGlobalGenerator::cmGlobalGenerator()
cmGlobalGenerator::~cmGlobalGenerator()
{
// Delete any existing cmLocalGenerators
unsigned int i;
for (i = 0; i < this->LocalGenerators.size(); ++i)
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
{
delete this->LocalGenerators[i];
}
@ -67,6 +67,17 @@ cmGlobalGenerator::~cmGlobalGenerator()
{
delete this->ExtraGenerator;
}
for (std::map<cmStdString, std::vector<cmTargetExport*> >::iterator
setIt = this->ExportSets.begin();
setIt != this->ExportSets.end();
++setIt)
{
for (unsigned int i = 0; i < setIt->second.size(); ++i)
{
delete setIt->second[i];
}
}
}
// Find the make program for the generator, required for try compiles
@ -1014,6 +1025,33 @@ void cmGlobalGenerator::AddInstallComponent(const char* component)
}
}
void cmGlobalGenerator::AddTargetToExports(const char* exportSetName,
cmTarget* target,
cmInstallTargetGenerator* archive,
cmInstallTargetGenerator* runTime,
cmInstallTargetGenerator* library)
{
if ((exportSetName) && (*exportSetName) && (target))
{
cmTargetExport* te = new cmTargetExport(target, archive, runTime, library);
this->ExportSets[exportSetName].push_back(te);
}
}
const std::vector<cmTargetExport*>* cmGlobalGenerator::GetExportSet(
const char* name) const
{
std::map<cmStdString, std::vector<cmTargetExport*> >::const_iterator
exportSetIt = this->ExportSets.find(name);
if (exportSetIt != this->ExportSets.end())
{
return &exportSetIt->second;
}
return 0;
}
void cmGlobalGenerator::EnableInstallTarget()
{
this->InstallTargetEnabled = true;

View File

@ -27,6 +27,8 @@ class cmMakefile;
class cmLocalGenerator;
class cmExternalMakefileProjectGenerator;
class cmTarget;
class cmTargetExport;
class cmInstallTargetGenerator;
/** \class cmGlobalGenerator
* \brief Responable for overseeing the generation process for the entire tree
@ -129,6 +131,15 @@ public:
const char* GetExtraGeneratorName() const;
void AddInstallComponent(const char* component);
///! Add one installed target to the sets of the exports
void AddTargetToExports(const char* exportSet, cmTarget* target,
cmInstallTargetGenerator* archive,
cmInstallTargetGenerator* runTime,
cmInstallTargetGenerator* library);
///! Get the export target set with the given name
const std::vector<cmTargetExport*>* GetExportSet(const char* name) const;
void EnableInstallTarget();
int TryCompileTimeout;
@ -231,6 +242,8 @@ protected:
// Set of named installation components requested by the project.
std::set<cmStdString> InstallComponents;
bool InstallTargetEnabled;
// Sets of named target exports
std::map<cmStdString, std::vector<cmTargetExport*> > ExportSets;
// Manifest of all targets that will be built for each configuration.
// This is computed just before local generators generate.

View File

@ -20,6 +20,7 @@
#include "cmInstallFilesGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmInstallExportGenerator.h"
#include <cmsys/Glob.hxx>
@ -62,6 +63,10 @@ bool cmInstallCommand::InitialPass(std::vector<std::string> const& args)
{
return this->HandleDirectoryMode(args);
}
else if(args[0] == "EXPORT")
{
return this->HandleExportMode(args);
}
// Unknown mode.
cmStdString e = "called with unknown mode ";
@ -135,6 +140,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
bool doing_permissions = false;
bool doing_component = false;
bool doing_configurations = false;
bool doing_export = false;
bool archive_settings = true;
bool library_settings = true;
bool runtime_settings = true;
@ -148,6 +154,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
std::string archive_component;
std::string library_component;
std::string runtime_component;
std::string exportName;
std::vector<std::string> archive_configurations;
std::vector<std::string> library_configurations;
std::vector<std::string> runtime_configurations;
@ -164,6 +171,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = false;
doing_component = false;
doing_configurations = false;
doing_export = false;
}
else if(args[i] == "PERMISSIONS")
{
@ -173,6 +181,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = true;
doing_component = false;
doing_configurations = false;
doing_export = false;
}
else if(args[i] == "COMPONENT")
{
@ -182,6 +191,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = false;
doing_component = true;
doing_configurations = false;
doing_export = false;
}
else if(args[i] == "CONFIGURATIONS")
{
@ -191,6 +201,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = false;
doing_component = false;
doing_configurations = true;
doing_export = false;
}
else if(args[i] == "ARCHIVE")
{
@ -200,6 +211,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = false;
doing_component = false;
doing_configurations = false;
doing_export = false;
archive_settings = true;
library_settings = false;
runtime_settings = false;
@ -212,6 +224,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = false;
doing_component = false;
doing_configurations = false;
doing_export = false;
archive_settings = false;
library_settings = true;
runtime_settings = false;
@ -224,10 +237,21 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
doing_permissions = false;
doing_component = false;
doing_configurations = false;
doing_export = false;
archive_settings = false;
library_settings = false;
runtime_settings = true;
}
else if(args[i] == "EXPORT")
{
// Switch to setting only runtime properties.
doing_targets = false;
doing_destination = false;
doing_permissions = false;
doing_component = false;
doing_configurations = false;
doing_export = true;
}
else if(args[i] == "OPTIONAL")
{
// Set the optional property.
@ -370,6 +394,11 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
runtime_configurations.push_back(args[i]);
}
}
else if(doing_export)
{
exportName = args[i];
doing_export = false;
}
else
{
// Unknown argument.
@ -566,6 +595,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
this->Makefile->AddInstallGenerator(runtimeGenerator);
this->Makefile->AddInstallGenerator(libraryGenerator);
if (!exportName.empty())
{
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
->AddTargetToExports(exportName.c_str(),
&target,
archiveGenerator,
runtimeGenerator,
libraryGenerator);
}
}
// Tell the global generator about any installation component names
@ -1125,6 +1163,154 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
return true;
}
//----------------------------------------------------------------------------
bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
{
// This is the EXPORT mode.
bool doing_exports = true;
bool doing_destination = false;
bool doing_permissions = false;
bool doing_configurations = false;
bool doing_filename = false;
bool doing_prefix = false;
std::vector<std::string> exports;
const char* destination = 0;
std::string filename;
std::string permissions;
std::string prefix;
std::vector<std::string> configurations;
for(unsigned int i=1; i < args.size(); ++i)
{
if(args[i] == "DESTINATION")
{
// Switch to setting the destination property.
doing_exports = false;
doing_destination = true;
doing_permissions = false;
doing_configurations = false;
doing_filename = false;
doing_prefix = false;
}
else if(args[i] == "PERMISSIONS")
{
// Switch to setting the permissions property.
doing_exports = false;
doing_destination = false;
doing_permissions = true;
doing_configurations = false;
doing_filename = false;
doing_prefix = false;
}
else if(args[i] == "CONFIGURATIONS")
{
// Switch to setting the configurations property.
doing_exports = false;
doing_destination = false;
doing_permissions = false;
doing_configurations = true;
doing_filename = false;
doing_prefix = false;
}
else if(args[i] == "FILENAME")
{
// Switch to setting the rename property.
doing_exports = false;
doing_destination = false;
doing_permissions = false;
doing_configurations = false;
doing_filename = true;
doing_prefix = false;
}
else if(args[i] == "PREFIX")
{
// Switch to setting the rename property.
doing_exports = false;
doing_destination = false;
doing_permissions = false;
doing_configurations = false;
doing_filename = false;
doing_prefix = true;
}
else if(doing_exports)
{
// Store the file for installation.
exports.push_back(args[i]);
}
else if(doing_configurations)
{
configurations.push_back(args[i]);
}
else if(doing_destination)
{
destination = args[i].c_str();
doing_destination = false;
}
else if(doing_permissions)
{
// Check the requested permission.
if(!this->CheckPermissions(args[i], permissions))
{
cmOStringStream e;
e << args[0] << " given invalid permission \""
<< args[i] << "\".";
this->SetError(e.str().c_str());
return false;
}
}
else if(doing_filename)
{
filename = args[i];
doing_filename = false;
}
else if(doing_prefix)
{
prefix = args[i];
doing_prefix = false;
}
else
{
// Unknown argument.
cmOStringStream e;
e << args[0] << " given unknown argument \"" << args[i] << "\".";
this->SetError(e.str().c_str());
return false;
}
}
std::string cmakeDir = this->Makefile->GetHomeOutputDirectory();
cmakeDir += cmake::GetCMakeFilesDirectory();
for(std::vector<std::string>::const_iterator exportIt = exports.begin();
exportIt != exports.end();
++exportIt)
{
const std::vector<cmTargetExport*>* exportSet = this->
Makefile->GetLocalGenerator()->GetGlobalGenerator()->
GetExportSet(exportIt->c_str());
if (exportSet == 0)
{
return false;
}
// Create the export install generator.
cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
destination, permissions.c_str(), configurations,
filename.c_str(), prefix.c_str(), cmakeDir.c_str());
if (exportGenerator->SetExportSet(exportIt->c_str(),exportSet))
{
this->Makefile->AddInstallGenerator(exportGenerator);
}
else
{
delete exportGenerator;
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
void cmInstallCommand::ComputeDestination(const char* destination,
std::string& dest) const

View File

@ -248,6 +248,7 @@ private:
bool HandleTargetsMode(std::vector<std::string> const& args);
bool HandleFilesMode(std::vector<std::string> const& args);
bool HandleDirectoryMode(std::vector<std::string> const& args);
bool HandleExportMode(std::vector<std::string> const& args);
void ComputeDestination(const char* destination, std::string& dest) const;
bool CheckPermissions(std::string const& arg, std::string& permissions)const;
};

View File

@ -0,0 +1,231 @@
/*=========================================================================
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 <stdio.h>
#include "cmInstallTargetGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmTarget.h"
#include "cmInstallExportGenerator.h"
cmInstallExportGenerator::cmInstallExportGenerator(const char* destination,
const char* file_permissions,
std::vector<std::string> const& configurations,
const char* filename, const char* prefix, const char* tempOutputDir)
:cmInstallGenerator(destination)
,FilePermissions(file_permissions)
,Configurations(configurations)
,Filename(filename)
,Prefix(prefix)
,TempOutputDir(tempOutputDir)
{
}
/* Helper function which adds the install locations from the generator
to the properties for this target.
*/
bool cmInstallExportGenerator::AddInstallLocations(cmTargetWithProperties* twp,
cmInstallTargetGenerator* generator,
const char* prefix)
{
if (generator == 0) // nothing to do
{
return true;
}
if (prefix == 0)
{
prefix = "";
}
const std::vector<std::string>& configs = generator->GetConfigurations();
if (configs.empty())
{
std::string propertyName = prefix;
propertyName += "LOCATION";
// check that this property doesn't exist yet and add it then
if (twp->Properties.find(propertyName.c_str())== twp->Properties.end())
{
std::string destinationFilename = generator->GetDestination();
destinationFilename += "/";
destinationFilename += generator->GetInstallFilename(0);
twp->Properties[propertyName.c_str()] = destinationFilename;
}
else
{
return false;
}
}
else
{
for(std::vector<std::string>::const_iterator configIt = configs.begin();
configIt != configs.end();
++configIt)
{
std::string propertyName = configIt->c_str();
propertyName += "_";
propertyName += prefix;
propertyName += "LOCATION";
// check that this property doesn't exist yet and add it then
if (twp->Properties.find(propertyName.c_str())== twp->Properties.end())
{
std::string destinationFilename = generator->GetDestination();
destinationFilename += "/";
destinationFilename +=generator->GetInstallFilename(configIt->c_str());
twp->Properties[propertyName.c_str()] = destinationFilename;
}
else
{
return false;
}
}
}
return true;
}
bool cmInstallExportGenerator::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];
}
}
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;
}
}
return true;
}
void cmInstallExportGenerator::GenerateScript(std::ostream& os)
{
// for the case that somebody exports the same set with the same file name
// to different locations make the temp filename unique
char buf[64];
snprintf(buf, 64, "%p", this);
this->ExportFilename = this->TempOutputDir;
this->ExportFilename += "/";
this->ExportFilename += this->Filename;
this->ExportFilename += ".";
this->ExportFilename += buf;
cmGeneratedFileStream exportFileStream(this->ExportFilename.c_str());
if(!exportFileStream)
{
return;
}
/* for every target add the IMPORT statements and set the properties
of the target. */
for(std::vector<cmTargetWithProperties*>::const_iterator
targetIt = this->Targets.begin();
targetIt != this->Targets.end();
++targetIt)
{
switch ((*targetIt)->Target->GetType())
{
case cmTarget::EXECUTABLE:
exportFileStream << "ADD_EXECUTABLE(" << this->Prefix.c_str()
<< (*targetIt)->Target->GetName()
<< " IMPORT )\n";
break;
case cmTarget::STATIC_LIBRARY:
exportFileStream << "ADD_LIBRARY(" << this->Prefix.c_str()
<< (*targetIt)->Target->GetName()
<< " STATIC IMPORT )\n";
break;
case cmTarget::SHARED_LIBRARY:
exportFileStream << "ADD_LIBRARY(" << this->Prefix.c_str()
<< (*targetIt)->Target->GetName()
<< " SHARED IMPORT )\n";
break;
case cmTarget::MODULE_LIBRARY:
exportFileStream << "ADD_LIBRARY(" << this->Prefix.c_str()
<< (*targetIt)->Target->GetName()
<< " MODULE IMPORT )\n";
break;
default: // should never happen
break;
}
exportFileStream << "SET_TARGET_PROPERTIES ( " << this->Prefix.c_str()
<< (*targetIt)->Target->GetName() << " PROPERTIES \n";
for (std::map<std::string, std::string>::const_iterator
propIt = (*targetIt)->Properties.begin();
propIt != (*targetIt)->Properties.end();
++propIt)
{
exportFileStream << " " << propIt->first
<< " \"" << propIt->second << "\"\n";
}
exportFileStream << " )\n\n";
}
// install rule for the file created above
this->AddInstallRule(os, this->Destination.c_str(), cmTarget::INSTALL_FILES,
this->ExportFilename.c_str(), false, 0,
this->FilePermissions.c_str(), 0, this->Configurations,
0, this->Filename.c_str(), 0);
}

View File

@ -0,0 +1,92 @@
/*=========================================================================
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 cmInstallExportGenerator_h
#define cmInstallExportGenerator_h
#include "cmInstallGenerator.h"
class cmTarget;
class cmInstallTargetGenerator;
/* cmInstallExportTarget is used in cmGlobalGenerator to collect the
install generators for the exported targets. These are then used by the
cmInstallExportGenerator.
*/
class cmTargetExport
{
public:
cmTargetExport(cmTarget* tgt,
cmInstallTargetGenerator* archive,
cmInstallTargetGenerator* runtime,
cmInstallTargetGenerator* library
) : Target(tgt), ArchiveGenerator(archive),
RuntimeGenerator(runtime), LibraryGenerator(library) {}
cmTarget* Target;
cmInstallTargetGenerator* ArchiveGenerator;
cmInstallTargetGenerator* RuntimeGenerator;
cmInstallTargetGenerator* LibraryGenerator;
private:
cmTargetExport();
};
/** \class cmInstallExportGenerator
* \brief Generate rules for creating an export files.
*/
class cmInstallExportGenerator: public cmInstallGenerator
{
public:
cmInstallExportGenerator(const char* dest, const char* file_permissions,
const std::vector<std::string>& configurations,
const char* filename, const char* prefix,
const char* tempOutputDir);
bool SetExportSet(const char* name,
const std::vector<cmTargetExport*>* exportSet);
protected:
// internal class which collects all the properties which will be set
// in the export file for the target
class cmTargetWithProperties
{
public:
cmTargetWithProperties(cmTarget* target):Target(target) {}
cmTarget* Target;
std::map<std::string, std::string> Properties;
private:
cmTargetWithProperties();
};
virtual void GenerateScript(std::ostream& os);
static bool AddInstallLocations(cmTargetWithProperties *twp,
cmInstallTargetGenerator* generator,
const char* prefix);
std::string Name;
std::string FilePermissions;
const std::vector<std::string> Configurations;
std::string Filename;
std::string Prefix;
std::string TempOutputDir;
std::string ExportFilename;
std::vector<cmTargetWithProperties*> Targets;
};
#endif