resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmScriptGenerator.cxx
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"
4
5 #include <algorithm>
6 #include <utility>
7
8 #include "cmStringAlgorithms.h"
9 #include "cmSystemTools.h"
10
11 cmScriptGenerator::cmScriptGenerator(std::string config_var,
12                                      std::vector<std::string> configurations)
13   : RuntimeConfigVariable(std::move(config_var))
14   , Configurations(std::move(configurations))
15 {
16 }
17
18 cmScriptGenerator::~cmScriptGenerator() = default;
19
20 void cmScriptGenerator::Generate(
21   std::ostream& os, const std::string& config,
22   std::vector<std::string> const& configurationTypes)
23 {
24   this->ConfigurationName = config;
25   this->ConfigurationTypes = &configurationTypes;
26   this->GenerateScript(os);
27   this->ConfigurationName.clear();
28   this->ConfigurationTypes = nullptr;
29 }
30
31 static void cmScriptGeneratorEncodeConfig(const std::string& config,
32                                           std::string& result)
33 {
34   for (const char* c = config.c_str(); *c; ++c) {
35     if (*c >= 'a' && *c <= 'z') {
36       result += "[";
37       result += static_cast<char>(*c + 'A' - 'a');
38       result += *c;
39       result += "]";
40     } else if (*c >= 'A' && *c <= 'Z') {
41       result += "[";
42       result += *c;
43       result += static_cast<char>(*c + 'a' - 'A');
44       result += "]";
45     } else {
46       result += *c;
47     }
48   }
49 }
50
51 std::string cmScriptGenerator::CreateConfigTest(const std::string& config)
52 {
53   std::string result = cmStrCat(this->RuntimeConfigVariable, " MATCHES \"^(");
54   if (!config.empty()) {
55     cmScriptGeneratorEncodeConfig(config, result);
56   }
57   result += ")$\"";
58   return result;
59 }
60
61 std::string cmScriptGenerator::CreateConfigTest(
62   std::vector<std::string> const& configs)
63 {
64   std::string result = cmStrCat(this->RuntimeConfigVariable, " MATCHES \"^(");
65   const char* sep = "";
66   for (std::string const& config : configs) {
67     result += sep;
68     sep = "|";
69     cmScriptGeneratorEncodeConfig(config, result);
70   }
71   result += ")$\"";
72   return result;
73 }
74
75 void cmScriptGenerator::GenerateScript(std::ostream& os)
76 {
77   // Track indentation.
78   Indent indent;
79
80   // Generate the script possibly with per-configuration code.
81   this->GenerateScriptConfigs(os, indent);
82 }
83
84 void cmScriptGenerator::GenerateScriptConfigs(std::ostream& os, Indent indent)
85 {
86   if (this->ActionsPerConfig) {
87     this->GenerateScriptActionsPerConfig(os, indent);
88   } else {
89     this->GenerateScriptActionsOnce(os, indent);
90   }
91 }
92
93 void cmScriptGenerator::GenerateScriptActions(std::ostream& os, Indent indent)
94 {
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);
99   }
100 }
101
102 void cmScriptGenerator::GenerateScriptForConfig(std::ostream& /*unused*/,
103                                                 const std::string& /*unused*/,
104                                                 Indent /*unused*/)
105 {
106   // No actions for this generator.
107 }
108
109 bool cmScriptGenerator::GeneratesForConfig(const std::string& config)
110 {
111   // If this is not a configuration-specific rule then we install.
112   if (this->Configurations.empty()) {
113     return true;
114   }
115
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;
122                      });
123 }
124
125 void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,
126                                                   Indent indent)
127 {
128   if (this->Configurations.empty()) {
129     // This rule is for all configurations.
130     this->GenerateScriptActions(os, indent);
131   } else {
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";
137   }
138 }
139
140 void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os,
141                                                        Indent indent)
142 {
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);
150   } else {
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.
154     bool first = true;
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());
161         first = false;
162       }
163     }
164     if (!first) {
165       if (this->NeedsScriptNoConfig()) {
166         os << indent << "else()\n";
167         this->GenerateScriptNoConfig(os, indent.Next());
168       }
169       os << indent << "endif()\n";
170     }
171   }
172 }