diff options
Diffstat (limited to 'Source/cmScriptGenerator.cxx')
-rw-r--r-- | Source/cmScriptGenerator.cxx | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx new file mode 100644 index 0000000..e44b236 --- /dev/null +++ b/Source/cmScriptGenerator.cxx @@ -0,0 +1,238 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmScriptGenerator.h" + +#include "cmSystemTools.h" + +//---------------------------------------------------------------------------- +cmScriptGenerator +::cmScriptGenerator(const std::string& config_var, + std::vector<std::string> const& configurations): + RuntimeConfigVariable(config_var), + Configurations(configurations), + ConfigurationName(""), + ConfigurationTypes(0), + ActionsPerConfig(false) +{ +} + +//---------------------------------------------------------------------------- +cmScriptGenerator +::~cmScriptGenerator() +{ +} + +//---------------------------------------------------------------------------- +void +cmScriptGenerator +::Generate(std::ostream& os, const std::string& config, + std::vector<std::string> const& configurationTypes) +{ + this->ConfigurationName = config; + this->ConfigurationTypes = &configurationTypes; + this->GenerateScript(os); + this->ConfigurationName = ""; + this->ConfigurationTypes = 0; +} + +//---------------------------------------------------------------------------- +static void cmScriptGeneratorEncodeConfig(const std::string& config, + std::string& result) +{ + for(const char* c = config.c_str(); *c; ++c) + { + if(*c >= 'a' && *c <= 'z') + { + result += "["; + result += static_cast<char>(*c + 'A' - 'a'); + result += *c; + result += "]"; + } + else if(*c >= 'A' && *c <= 'Z') + { + result += "["; + result += *c; + result += static_cast<char>(*c + 'a' - 'A'); + result += "]"; + } + else + { + result += *c; + } + } +} + +//---------------------------------------------------------------------------- +std::string +cmScriptGenerator::CreateConfigTest(const std::string& config) +{ + std::string result = "\"${"; + result += this->RuntimeConfigVariable; + result += "}\" MATCHES \"^("; + if(!config.empty()) + { + cmScriptGeneratorEncodeConfig(config, result); + } + result += ")$\""; + return result; +} + +//---------------------------------------------------------------------------- +std::string +cmScriptGenerator::CreateConfigTest(std::vector<std::string> const& configs) +{ + std::string result = "\"${"; + result += this->RuntimeConfigVariable; + result += "}\" MATCHES \"^("; + const char* sep = ""; + for(std::vector<std::string>::const_iterator ci = configs.begin(); + ci != configs.end(); ++ci) + { + result += sep; + sep = "|"; + cmScriptGeneratorEncodeConfig(*ci, 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 std::string&, + Indent const&) +{ + // No actions for this generator. +} + +//---------------------------------------------------------------------------- +bool cmScriptGenerator::GeneratesForConfig(const std::string& 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); + 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; +} + +//---------------------------------------------------------------------------- +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. + bool first = true; + for(std::vector<std::string>::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 << (first? "if(" : "elseif(") << config_test << ")\n"; + this->GenerateScriptForConfig(os, config, indent.Next()); + first = false; + } + } + if(!first) + { + if(this->NeedsScriptNoConfig()) + { + os << indent << "else()\n"; + this->GenerateScriptNoConfig(os, indent.Next()); + } + os << indent << "endif()\n"; + } + } +} |