From e67f5138b80b3b04844f3f5c0a3c69796266f9e6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 16 Mar 2009 10:39:56 -0400 Subject: ENH: Refactor cmInstallGenerator for re-use A new cmScriptGenerator base class factors out the non-install-specific part of cmInstallGenerator. This will be useful for other generators that want per-configuration functionality. --- Source/CMakeLists.txt | 2 + Source/cmInstallGenerator.cxx | 124 +------------------ Source/cmInstallGenerator.h | 47 +------- Source/cmInstallTargetGenerator.cxx | 43 +------ Source/cmInstallTargetGenerator.h | 8 +- Source/cmScriptGenerator.cxx | 232 ++++++++++++++++++++++++++++++++++++ Source/cmScriptGenerator.h | 99 +++++++++++++++ bootstrap | 1 + 8 files changed, 345 insertions(+), 211 deletions(-) create mode 100644 Source/cmScriptGenerator.cxx create mode 100644 Source/cmScriptGenerator.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index d977a46..89ee0ad 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -201,6 +201,8 @@ SET(SRCS cmPropertyDefinitionMap.h cmPropertyMap.cxx cmPropertyMap.h + cmScriptGenerator.h + cmScriptGenerator.cxx cmSourceFile.cxx cmSourceFile.h cmSourceFileLocation.cxx diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index c2e0256..94a7080 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -24,11 +24,9 @@ cmInstallGenerator ::cmInstallGenerator(const char* destination, std::vector const& configurations, const char* component): + cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations), Destination(destination? destination:""), - Configurations(configurations), - Component(component? component:""), - ConfigurationName(0), - ConfigurationTypes(0) + Component(component? component:"") { } @@ -39,19 +37,6 @@ cmInstallGenerator } //---------------------------------------------------------------------------- -void -cmInstallGenerator -::Generate(std::ostream& os, const char* config, - std::vector const& configurationTypes) -{ - this->ConfigurationName = config; - this->ConfigurationTypes = &configurationTypes; - this->GenerateScript(os); - this->ConfigurationName = 0; - this->ConfigurationTypes = 0; -} - -//---------------------------------------------------------------------------- void cmInstallGenerator ::AddInstallRule( std::ostream& os, @@ -63,7 +48,7 @@ void cmInstallGenerator const char* permissions_dir /* = 0 */, const char* rename /* = 0 */, const char* literal_args /* = 0 */, - cmInstallGeneratorIndent const& indent + Indent const& indent ) { // Use the FILE command to install the file. @@ -128,63 +113,6 @@ void cmInstallGenerator } //---------------------------------------------------------------------------- -static void cmInstallGeneratorEncodeConfig(const char* config, - std::string& result) -{ - for(const char* c = config; *c; ++c) - { - if(*c >= 'a' && *c <= 'z') - { - result += "["; - result += *c + ('A' - 'a'); - result += *c; - result += "]"; - } - else if(*c >= 'A' && *c <= 'Z') - { - result += "["; - result += *c; - result += *c + ('a' - 'A'); - result += "]"; - } - else - { - result += *c; - } - } -} - -//---------------------------------------------------------------------------- -std::string -cmInstallGenerator::CreateConfigTest(const char* config) -{ - std::string result = "\"${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^("; - if(config && *config) - { - cmInstallGeneratorEncodeConfig(config, result); - } - result += ")$\""; - return result; -} - -//---------------------------------------------------------------------------- -std::string -cmInstallGenerator::CreateConfigTest(std::vector const& configs) -{ - std::string result = "\"${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^("; - const char* sep = ""; - for(std::vector::const_iterator ci = configs.begin(); - ci != configs.end(); ++ci) - { - result += sep; - sep = "|"; - cmInstallGeneratorEncodeConfig(ci->c_str(), result); - } - result += ")$\""; - return result; -} - -//---------------------------------------------------------------------------- std::string cmInstallGenerator::CreateComponentTest(const char* component) { @@ -214,53 +142,9 @@ void cmInstallGenerator::GenerateScript(std::ostream& os) } //---------------------------------------------------------------------------- -void -cmInstallGenerator::GenerateScriptConfigs(std::ostream& os, - Indent const& indent) -{ - if(this->Configurations.empty()) - { - // This rule is for all configurations. - this->GenerateScriptActions(os, indent); - } - else - { - // Generate a per-configuration block. - std::string config_test = this->CreateConfigTest(this->Configurations); - os << indent << "IF(" << config_test << ")\n"; - this->GenerateScriptActions(os, indent.Next()); - os << indent << "ENDIF(" << config_test << ")\n"; - } -} - -//---------------------------------------------------------------------------- -void cmInstallGenerator::GenerateScriptActions(std::ostream&, Indent const&) -{ - // No actions for this generator. -} - -//---------------------------------------------------------------------------- bool cmInstallGenerator::InstallsForConfig(const char* config) { - // If this is not a configuration-specific rule then we install. - if(this->Configurations.empty()) - { - return true; - } - - // This is a configuration-specific rule. Check if the config - // matches this rule. - std::string config_upper = cmSystemTools::UpperCase(config?config:""); - for(std::vector::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) - { - if(cmSystemTools::UpperCase(*i) == config_upper) - { - return true; - } - } - return false; + return this->GeneratesForConfig(config); } //---------------------------------------------------------------------------- diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index 904bb2b..a6da119 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -17,41 +17,15 @@ #ifndef cmInstallGenerator_h #define cmInstallGenerator_h -#include "cmStandardIncludes.h" +#include "cmScriptGenerator.h" class cmLocalGenerator; -class cmInstallGeneratorIndent -{ -public: - cmInstallGeneratorIndent(): Level(0) {} - cmInstallGeneratorIndent(int level): Level(level) {} - void Write(std::ostream& os) const - { - for(int i=0; i < this->Level; ++i) - { - os << " "; - } - } - cmInstallGeneratorIndent Next(int step = 2) const - { - return cmInstallGeneratorIndent(this->Level + step); - } -private: - int Level; -}; -inline std::ostream& operator<<(std::ostream& os, - cmInstallGeneratorIndent const& indent) -{ - indent.Write(os); - return os; -} - /** \class cmInstallGenerator * \brief Support class for generating install scripts. * */ -class cmInstallGenerator +class cmInstallGenerator: public cmScriptGenerator { public: cmInstallGenerator(const char* destination, @@ -59,9 +33,6 @@ public: const char* component); virtual ~cmInstallGenerator(); - void Generate(std::ostream& os, const char* config, - std::vector const& configurationTypes); - void AddInstallRule( std::ostream& os, int type, std::vector const& files, @@ -71,13 +42,11 @@ public: const char* permissions_dir = 0, const char* rename = 0, const char* literal_args = 0, - cmInstallGeneratorIndent const& indent = cmInstallGeneratorIndent() + Indent const& indent = Indent() ); const char* GetDestination() const { return this->Destination.c_str(); } - const std::vector& GetConfigurations() const - { return this->Configurations; } /** Get the install destination as it should appear in the installation script. */ @@ -87,23 +56,13 @@ public: bool InstallsForConfig(const char*); protected: - typedef cmInstallGeneratorIndent Indent; virtual void GenerateScript(std::ostream& os); - virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); - virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); - std::string CreateConfigTest(const char* config); - std::string CreateConfigTest(std::vector const& configs); std::string CreateComponentTest(const char* component); // Information shared by most generator types. std::string Destination; - std::vector const Configurations; std::string Component; - - // Information used during generation. - const char* ConfigurationName; - std::vector const* ConfigurationTypes; }; #endif diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index fabcb0a..b8df71e 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -33,6 +33,7 @@ cmInstallTargetGenerator cmInstallGenerator(dest, configurations, component), Target(&t), ImportLibrary(implib), FilePermissions(file_permissions), Optional(optional) { + this->ActionsPerConfig = true; this->NamelinkMode = NamelinkModeNone; this->Target->SetHaveInstallRule(true); } @@ -76,48 +77,6 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os) } //---------------------------------------------------------------------------- -void cmInstallTargetGenerator::GenerateScriptConfigs(std::ostream& os, - Indent const& indent) -{ - if(this->ConfigurationTypes->empty()) - { - // In a single-configuration generator, only the install rule's - // configuration test is important. If that passes, the target is - // installed regardless of for what configuration it was built. - this->cmInstallGenerator::GenerateScriptConfigs(os, indent); - } - else - { - // In a multi-configuration generator, a separate rule is produced - // in a block for each configuration that is built. However, the - // list of configurations is restricted to those for which this - // install rule applies. - for(std::vector::const_iterator i = - this->ConfigurationTypes->begin(); - i != this->ConfigurationTypes->end(); ++i) - { - const char* config = i->c_str(); - if(this->InstallsForConfig(config)) - { - // Generate a per-configuration block. - std::string config_test = this->CreateConfigTest(config); - os << indent << "IF(" << config_test << ")\n"; - this->GenerateScriptForConfig(os, config, indent.Next()); - os << indent << "ENDIF(" << config_test << ")\n"; - } - } - } -} - -//---------------------------------------------------------------------------- -void cmInstallTargetGenerator::GenerateScriptActions(std::ostream& os, - Indent const& indent) -{ - // This is reached for single-configuration generators only. - this->GenerateScriptForConfig(os, this->ConfigurationName, indent); -} - -//---------------------------------------------------------------------------- void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, const char* config, Indent const& indent) diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index aa4db86..3a2f0d0 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -65,11 +65,9 @@ public: protected: virtual void GenerateScript(std::ostream& os); - virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); - virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); - void GenerateScriptForConfig(std::ostream& os, - const char* config, - Indent const& indent); + virtual void GenerateScriptForConfig(std::ostream& os, + const char* config, + Indent const& indent); void AddInstallNamePatchRule(std::ostream& os, Indent const& indent, const char* config, const std::string& toDestDirPath); diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx new file mode 100644 index 0000000..c3a521a --- /dev/null +++ b/Source/cmScriptGenerator.cxx @@ -0,0 +1,232 @@ +/*========================================================================= + + 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 "cmScriptGenerator.h" + +#include "cmSystemTools.h" + +//---------------------------------------------------------------------------- +cmScriptGenerator +::cmScriptGenerator(const char* config_var, + std::vector const& configurations): + RuntimeConfigVariable(config_var), + Configurations(configurations), + ConfigurationName(0), + ConfigurationTypes(0), + ActionsPerConfig(false) +{ +} + +//---------------------------------------------------------------------------- +cmScriptGenerator +::~cmScriptGenerator() +{ +} + +//---------------------------------------------------------------------------- +void +cmScriptGenerator +::Generate(std::ostream& os, const char* config, + std::vector const& configurationTypes) +{ + this->ConfigurationName = config; + this->ConfigurationTypes = &configurationTypes; + this->GenerateScript(os); + this->ConfigurationName = 0; + this->ConfigurationTypes = 0; +} + +//---------------------------------------------------------------------------- +static void cmScriptGeneratorEncodeConfig(const char* config, + std::string& result) +{ + for(const char* c = config; *c; ++c) + { + if(*c >= 'a' && *c <= 'z') + { + result += "["; + result += *c + ('A' - 'a'); + result += *c; + result += "]"; + } + else if(*c >= 'A' && *c <= 'Z') + { + result += "["; + result += *c; + result += *c + ('a' - 'A'); + result += "]"; + } + else + { + result += *c; + } + } +} + +//---------------------------------------------------------------------------- +std::string +cmScriptGenerator::CreateConfigTest(const char* config) +{ + std::string result = "\"${"; + result += this->RuntimeConfigVariable; + result += "}\" MATCHES \"^("; + if(config && *config) + { + cmScriptGeneratorEncodeConfig(config, result); + } + result += ")$\""; + return result; +} + +//---------------------------------------------------------------------------- +std::string +cmScriptGenerator::CreateConfigTest(std::vector const& configs) +{ + std::string result = "\"${"; + result += this->RuntimeConfigVariable; + result += "}\" MATCHES \"^("; + const char* sep = ""; + for(std::vector::const_iterator ci = configs.begin(); + ci != configs.end(); ++ci) + { + result += sep; + sep = "|"; + cmScriptGeneratorEncodeConfig(ci->c_str(), result); + } + result += ")$\""; + return result; +} + +//---------------------------------------------------------------------------- +void cmScriptGenerator::GenerateScript(std::ostream& os) +{ + // Track indentation. + Indent indent; + + // Generate the script possibly with per-configuration code. + this->GenerateScriptConfigs(os, indent); +} + +//---------------------------------------------------------------------------- +void cmScriptGenerator::GenerateScriptConfigs(std::ostream& os, + Indent const& indent) +{ + if(this->ActionsPerConfig) + { + this->GenerateScriptActionsPerConfig(os, indent); + } + else + { + this->GenerateScriptActionsOnce(os, indent); + } +} + +//---------------------------------------------------------------------------- +void cmScriptGenerator::GenerateScriptActions(std::ostream& os, + Indent const& indent) +{ + if(this->ActionsPerConfig) + { + // This is reached for single-configuration build generators in a + // per-config script generator. + this->GenerateScriptForConfig(os, this->ConfigurationName, indent); + } +} + +//---------------------------------------------------------------------------- +void cmScriptGenerator::GenerateScriptForConfig(std::ostream&, const char*, + Indent const&) +{ + // No actions for this generator. +} + +//---------------------------------------------------------------------------- +bool cmScriptGenerator::GeneratesForConfig(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::const_iterator i = + this->Configurations.begin(); + i != this->Configurations.end(); ++i) + { + if(cmSystemTools::UpperCase(*i) == config_upper) + { + return true; + } + } + return false; +} + +//---------------------------------------------------------------------------- +void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os, + Indent const& indent) +{ + if(this->Configurations.empty()) + { + // This rule is for all configurations. + this->GenerateScriptActions(os, indent); + } + else + { + // Generate a per-configuration block. + std::string config_test = this->CreateConfigTest(this->Configurations); + os << indent << "IF(" << config_test << ")\n"; + this->GenerateScriptActions(os, indent.Next()); + os << indent << "ENDIF(" << config_test << ")\n"; + } +} + +//---------------------------------------------------------------------------- +void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os, + Indent const& indent) +{ + if(this->ConfigurationTypes->empty()) + { + // In a single-configuration generator there is only one action + // and it applies if the runtime-requested configuration is among + // the rule's allowed configurations. The configuration built in + // the tree does not matter for this decision but will be used to + // generate proper target file names into the code. + this->GenerateScriptActionsOnce(os, indent); + } + else + { + // In a multi-configuration generator we produce a separate rule + // in a block for each configuration that is built. We restrict + // the list of configurations to those to which this rule applies. + for(std::vector::const_iterator i = + this->ConfigurationTypes->begin(); + i != this->ConfigurationTypes->end(); ++i) + { + const char* config = i->c_str(); + if(this->GeneratesForConfig(config)) + { + // Generate a per-configuration block. + std::string config_test = this->CreateConfigTest(config); + os << indent << "IF(" << config_test << ")\n"; + this->GenerateScriptForConfig(os, config, indent.Next()); + os << indent << "ENDIF(" << config_test << ")\n"; + } + } + } +} diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h new file mode 100644 index 0000000..b777001 --- /dev/null +++ b/Source/cmScriptGenerator.h @@ -0,0 +1,99 @@ +/*========================================================================= + + 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 cmScriptGenerator_h +#define cmScriptGenerator_h + +#include "cmStandardIncludes.h" + +class cmScriptGeneratorIndent +{ +public: + cmScriptGeneratorIndent(): Level(0) {} + cmScriptGeneratorIndent(int level): Level(level) {} + void Write(std::ostream& os) const + { + for(int i=0; i < this->Level; ++i) + { + os << " "; + } + } + cmScriptGeneratorIndent Next(int step = 2) const + { + return cmScriptGeneratorIndent(this->Level + step); + } +private: + int Level; +}; +inline std::ostream& operator<<(std::ostream& os, + cmScriptGeneratorIndent const& indent) +{ + indent.Write(os); + return os; +} + +/** \class cmScriptGenerator + * \brief Support class for generating install and test scripts. + * + */ +class cmScriptGenerator +{ +public: + cmScriptGenerator(const char* config_var, + std::vector const& configurations); + virtual ~cmScriptGenerator(); + + void Generate(std::ostream& os, const char* config, + std::vector const& configurationTypes); + + const std::vector& GetConfigurations() const + { return this->Configurations; } + +protected: + typedef cmScriptGeneratorIndent Indent; + virtual void GenerateScript(std::ostream& os); + virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); + virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); + virtual void GenerateScriptForConfig(std::ostream& os, + const char* config, + Indent const& indent); + + // Test if this generator does something for a given configuration. + bool GeneratesForConfig(const char*); + + std::string CreateConfigTest(const char* config); + std::string CreateConfigTest(std::vector const& configs); + std::string CreateComponentTest(const char* component); + + // Information shared by most generator types. + std::string RuntimeConfigVariable; + std::vector const Configurations; + + // Information used during generation. + const char* ConfigurationName; + std::vector const* ConfigurationTypes; + + // True if the subclass needs to generate an explicit rule for each + // configuration. False if the subclass only generates one rule for + // all enabled configurations. + bool ActionsPerConfig; + +private: + void GenerateScriptActionsOnce(std::ostream& os, Indent const& indent); + void GenerateScriptActionsPerConfig(std::ostream& os, Indent const& indent); +}; + +#endif diff --git a/bootstrap b/bootstrap index e6229cf..9b27930 100755 --- a/bootstrap +++ b/bootstrap @@ -167,6 +167,7 @@ CMAKE_CXX_SOURCES="\ cmInstallFilesGenerator \ cmInstallScriptGenerator \ cmInstallTargetGenerator \ + cmScriptGenerator \ cmSourceFile \ cmSourceFileLocation \ cmSystemTools \ -- cgit v0.12