| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying   file Copyright.txt or https://cmake.org/licensing for details.  */#include "cmScriptGenerator.h"#include <utility>#include "cmStringAlgorithms.h"#include "cmSystemTools.h"cmScriptGenerator::cmScriptGenerator(std::string config_var,                                     std::vector<std::string> configurations)  : RuntimeConfigVariable(std::move(config_var))  , Configurations(std::move(configurations))  , ConfigurationTypes(nullptr)  , ActionsPerConfig(false){}cmScriptGenerator::~cmScriptGenerator() = default;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.clear();  this->ConfigurationTypes = nullptr;}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 =    cmStrCat("\"${", this->RuntimeConfigVariable, "}\" MATCHES \"^(");  if (!config.empty()) {    cmScriptGeneratorEncodeConfig(config, result);  }  result += ")$\"";  return result;}std::string cmScriptGenerator::CreateConfigTest(  std::vector<std::string> const& configs){  std::string result =    cmStrCat("\"${", this->RuntimeConfigVariable, "}\" MATCHES \"^(");  const char* sep = "";  for (std::string const& config : configs) {    result += sep;    sep = "|";    cmScriptGeneratorEncodeConfig(config, 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 indent){  if (this->ActionsPerConfig) {    this->GenerateScriptActionsPerConfig(os, indent);  } else {    this->GenerateScriptActionsOnce(os, indent);  }}void cmScriptGenerator::GenerateScriptActions(std::ostream& os, Indent 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& /*unused*/,                                                const std::string& /*unused*/,                                                Indent /*unused*/){  // 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::string const& cfg : this->Configurations) {    if (cmSystemTools::UpperCase(cfg) == config_upper) {      return true;    }  }  return false;}void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,                                                  Indent 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 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::string const& cfgType : *this->ConfigurationTypes) {      if (this->GeneratesForConfig(cfgType)) {        // Generate a per-configuration block.        std::string config_test = this->CreateConfigTest(cfgType);        os << indent << (first ? "if(" : "elseif(") << config_test << ")\n";        this->GenerateScriptForConfig(os, cfgType, indent.Next());        first = false;      }    }    if (!first) {      if (this->NeedsScriptNoConfig()) {        os << indent << "else()\n";        this->GenerateScriptNoConfig(os, indent.Next());      }      os << indent << "endif()\n";    }  }}
 |