From c0d000d234525c709b8f6226d1c78c3cc0b632b3 Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Tue, 19 Jun 2007 13:10:21 -0400 Subject: ENH: add INSTALL(EXPORT ...) mode and INSTALL( TARGETS ... EXPORT ) , tests still have to be added Alex --- Source/CMakeLists.txt | 1 + Source/cmGlobalGenerator.cxx | 42 ++++++- Source/cmGlobalGenerator.h | 15 ++- Source/cmInstallCommand.cxx | 186 +++++++++++++++++++++++++++++ Source/cmInstallCommand.h | 1 + Source/cmInstallExportGenerator.cxx | 231 ++++++++++++++++++++++++++++++++++++ Source/cmInstallExportGenerator.h | 92 ++++++++++++++ 7 files changed, 565 insertions(+), 3 deletions(-) create mode 100644 Source/cmInstallExportGenerator.cxx create mode 100644 Source/cmInstallExportGenerator.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 8000842..f7d6537 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -115,6 +115,7 @@ SET(SRCS cmGlobalUnixMakefileGenerator3.h cmInstallGenerator.h cmInstallGenerator.cxx + cmInstallExportGenerator.cxx cmInstallFilesGenerator.h cmInstallFilesGenerator.cxx cmInstallScriptGenerator.h diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 189f5e4..1835f6d 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -21,6 +21,7 @@ #include "cmMakefile.h" #include "cmSourceFile.h" #include "cmVersion.h" +#include "cmInstallExportGenerator.h" #include // 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 >::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* cmGlobalGenerator::GetExportSet( + const char* name) const +{ + std::map >::const_iterator + exportSetIt = this->ExportSets.find(name); + if (exportSetIt != this->ExportSets.end()) + { + return &exportSetIt->second; + } + + return 0; +} + + void cmGlobalGenerator::EnableInstallTarget() { this->InstallTargetEnabled = true; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 8ed5e3a..7785c9a 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -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,8 +131,17 @@ 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* GetExportSet(const char* name) const; + void EnableInstallTarget(); - + int TryCompileTimeout; bool GetForceUnixPaths() {return this->ForceUnixPaths;} @@ -231,6 +242,8 @@ protected: // Set of named installation components requested by the project. std::set InstallComponents; bool InstallTargetEnabled; + // Sets of named target exports + std::map > ExportSets; // Manifest of all targets that will be built for each configuration. // This is computed just before local generators generate. diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 62d3579..53a4173 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -20,6 +20,7 @@ #include "cmInstallFilesGenerator.h" #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" +#include "cmInstallExportGenerator.h" #include @@ -62,6 +63,10 @@ bool cmInstallCommand::InitialPass(std::vector 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 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 const& args) std::string archive_component; std::string library_component; std::string runtime_component; + std::string exportName; std::vector archive_configurations; std::vector library_configurations; std::vector runtime_configurations; @@ -164,6 +171,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector 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 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 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 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 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 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 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 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 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 @@ -1126,6 +1164,154 @@ cmInstallCommand::HandleDirectoryMode(std::vector const& args) } //---------------------------------------------------------------------------- +bool cmInstallCommand::HandleExportMode(std::vector 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 exports; + const char* destination = 0; + std::string filename; + std::string permissions; + std::string prefix; + std::vector 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::const_iterator exportIt = exports.begin(); + exportIt != exports.end(); + ++exportIt) + { + + const std::vector* 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 { diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h index 7c7e2e7..bb51f9c 100644 --- a/Source/cmInstallCommand.h +++ b/Source/cmInstallCommand.h @@ -248,6 +248,7 @@ private: bool HandleTargetsMode(std::vector const& args); bool HandleFilesMode(std::vector const& args); bool HandleDirectoryMode(std::vector const& args); + bool HandleExportMode(std::vector const& args); void ComputeDestination(const char* destination, std::string& dest) const; bool CheckPermissions(std::string const& arg, std::string& permissions)const; }; diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx new file mode 100644 index 0000000..171cf32 --- /dev/null +++ b/Source/cmInstallExportGenerator.cxx @@ -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 + +#include "cmInstallTargetGenerator.h" +#include "cmGeneratedFileStream.h" +#include "cmTarget.h" + +#include "cmInstallExportGenerator.h" + +cmInstallExportGenerator::cmInstallExportGenerator(const char* destination, + const char* file_permissions, + std::vector 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& 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::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* 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::const_iterator it=set->begin(); + it != set->end(); + ++it) + { + std::string targetName = (*it)->Target->GetName(); + + cmTargetWithProperties* targetWithProps = 0; + for(unsigned int i=0; iTargets.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::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::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); + +} + diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h new file mode 100644 index 0000000..9dc2eff --- /dev/null +++ b/Source/cmInstallExportGenerator.h @@ -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& configurations, + const char* filename, const char* prefix, + const char* tempOutputDir); + + bool SetExportSet(const char* name, + const std::vector* 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 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 Configurations; + std::string Filename; + std::string Prefix; + std::string TempOutputDir; + std::string ExportFilename; + + std::vector Targets; +}; + +#endif -- cgit v0.12