1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmScriptGenerator.h"
8 #include "cmStringAlgorithms.h"
9 #include "cmSystemTools.h"
11 cmScriptGenerator::cmScriptGenerator(std::string config_var,
12 std::vector<std::string> configurations)
13 : RuntimeConfigVariable(std::move(config_var))
14 , Configurations(std::move(configurations))
18 cmScriptGenerator::~cmScriptGenerator() = default;
20 void cmScriptGenerator::Generate(
21 std::ostream& os, const std::string& config,
22 std::vector<std::string> const& configurationTypes)
24 this->ConfigurationName = config;
25 this->ConfigurationTypes = &configurationTypes;
26 this->GenerateScript(os);
27 this->ConfigurationName.clear();
28 this->ConfigurationTypes = nullptr;
31 static void cmScriptGeneratorEncodeConfig(const std::string& config,
34 for (const char* c = config.c_str(); *c; ++c) {
35 if (*c >= 'a' && *c <= 'z') {
37 result += static_cast<char>(*c + 'A' - 'a');
40 } else if (*c >= 'A' && *c <= 'Z') {
43 result += static_cast<char>(*c + 'a' - 'A');
51 std::string cmScriptGenerator::CreateConfigTest(const std::string& config)
53 std::string result = cmStrCat(this->RuntimeConfigVariable, " MATCHES \"^(");
54 if (!config.empty()) {
55 cmScriptGeneratorEncodeConfig(config, result);
61 std::string cmScriptGenerator::CreateConfigTest(
62 std::vector<std::string> const& configs)
64 std::string result = cmStrCat(this->RuntimeConfigVariable, " MATCHES \"^(");
66 for (std::string const& config : configs) {
69 cmScriptGeneratorEncodeConfig(config, result);
75 void cmScriptGenerator::GenerateScript(std::ostream& os)
80 // Generate the script possibly with per-configuration code.
81 this->GenerateScriptConfigs(os, indent);
84 void cmScriptGenerator::GenerateScriptConfigs(std::ostream& os, Indent indent)
86 if (this->ActionsPerConfig) {
87 this->GenerateScriptActionsPerConfig(os, indent);
89 this->GenerateScriptActionsOnce(os, indent);
93 void cmScriptGenerator::GenerateScriptActions(std::ostream& os, Indent indent)
95 if (this->ActionsPerConfig) {
96 // This is reached for single-configuration build generators in a
97 // per-config script generator.
98 this->GenerateScriptForConfig(os, this->ConfigurationName, indent);
102 void cmScriptGenerator::GenerateScriptForConfig(std::ostream& /*unused*/,
103 const std::string& /*unused*/,
106 // No actions for this generator.
109 bool cmScriptGenerator::GeneratesForConfig(const std::string& config)
111 // If this is not a configuration-specific rule then we install.
112 if (this->Configurations.empty()) {
116 // This is a configuration-specific rule. Check if the config
117 // matches this rule.
118 std::string config_upper = cmSystemTools::UpperCase(config);
119 return std::any_of(this->Configurations.begin(), this->Configurations.end(),
120 [&config_upper](std::string const& cfg) -> bool {
121 return cmSystemTools::UpperCase(cfg) == config_upper;
125 void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,
128 if (this->Configurations.empty()) {
129 // This rule is for all configurations.
130 this->GenerateScriptActions(os, indent);
132 // Generate a per-configuration block.
133 std::string config_test = this->CreateConfigTest(this->Configurations);
134 os << indent << "if(" << config_test << ")\n";
135 this->GenerateScriptActions(os, indent.Next());
136 os << indent << "endif()\n";
140 void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os,
143 if (this->ConfigurationTypes->empty()) {
144 // In a single-configuration generator there is only one action
145 // and it applies if the runtime-requested configuration is among
146 // the rule's allowed configurations. The configuration built in
147 // the tree does not matter for this decision but will be used to
148 // generate proper target file names into the code.
149 this->GenerateScriptActionsOnce(os, indent);
151 // In a multi-configuration generator we produce a separate rule
152 // in a block for each configuration that is built. We restrict
153 // the list of configurations to those to which this rule applies.
155 for (std::string const& cfgType : *this->ConfigurationTypes) {
156 if (this->GeneratesForConfig(cfgType)) {
157 // Generate a per-configuration block.
158 std::string config_test = this->CreateConfigTest(cfgType);
159 os << indent << (first ? "if(" : "elseif(") << config_test << ")\n";
160 this->GenerateScriptForConfig(os, cfgType, indent.Next());
165 if (this->NeedsScriptNoConfig()) {
166 os << indent << "else()\n";
167 this->GenerateScriptNoConfig(os, indent.Next());
169 os << indent << "endif()\n";