Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmRulePlaceholderExpander.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmRulePlaceholderExpander.h"
4
5
#include <utility>
6
7
#include "cmOutputConverter.h"
8
#include "cmStringAlgorithms.h"
9
#include "cmSystemTools.h"
10
11
cmRulePlaceholderExpander::cmRulePlaceholderExpander(
12
  cmBuildStep buildStep, std::map<std::string, std::string> compilers,
13
  std::map<std::string, std::string> variableMappings,
14
  std::string compilerSysroot, std::string linkerSysroot)
15
0
  : BuildStep(buildStep)
16
0
  , Compilers(std::move(compilers))
17
0
  , VariableMappings(std::move(variableMappings))
18
0
  , CompilerSysroot(std::move(compilerSysroot))
19
0
  , LinkerSysroot(std::move(linkerSysroot))
20
0
{
21
0
}
22
23
std::string cmRulePlaceholderExpander::ExpandVariable(
24
  std::string const& variable)
25
0
{
26
0
  if (this->ReplaceValues->LinkFlags) {
27
0
    if (variable == "LINK_FLAGS") {
28
0
      return this->ReplaceValues->LinkFlags;
29
0
    }
30
0
  }
31
0
  if (this->ReplaceValues->Linker) {
32
0
    if (variable == "CMAKE_LINKER") {
33
0
      auto result = this->OutputConverter->ConvertToOutputForExisting(
34
0
        this->ReplaceValues->Linker);
35
0
      if (this->ReplaceValues->Launcher) {
36
        // Add launcher as part of expansion so that it always appears
37
        // immediately before the command itself, regardless of whether the
38
        // overall rule template contains other content at the front.
39
0
        result = cmStrCat(this->ReplaceValues->Launcher, ' ', result);
40
0
      }
41
0
      return result;
42
0
    }
43
0
  }
44
0
  if (this->ReplaceValues->Manifests) {
45
0
    if (variable == "MANIFESTS") {
46
0
      return this->ReplaceValues->Manifests;
47
0
    }
48
0
  }
49
0
  if (this->ReplaceValues->Flags) {
50
0
    if (variable == "FLAGS") {
51
0
      return this->ReplaceValues->Flags;
52
0
    }
53
0
  }
54
55
0
  if (this->ReplaceValues->Source) {
56
0
    if (variable == "SOURCE") {
57
0
      return this->ReplaceValues->Source;
58
0
    }
59
0
  }
60
0
  if (this->ReplaceValues->DynDepFile) {
61
0
    if (variable == "DYNDEP_FILE") {
62
0
      return this->ReplaceValues->DynDepFile;
63
0
    }
64
0
  }
65
0
  if (this->ReplaceValues->PreprocessedSource) {
66
0
    if (variable == "PREPROCESSED_SOURCE") {
67
0
      return this->ReplaceValues->PreprocessedSource;
68
0
    }
69
0
  }
70
0
  if (this->ReplaceValues->AssemblySource) {
71
0
    if (variable == "ASSEMBLY_SOURCE") {
72
0
      return this->ReplaceValues->AssemblySource;
73
0
    }
74
0
  }
75
0
  if (this->ReplaceValues->Object) {
76
0
    if (variable == "OBJECT") {
77
0
      return this->ReplaceValues->Object;
78
0
    }
79
0
  }
80
0
  if (this->ReplaceValues->TargetSupportDir) {
81
0
    if (variable == "TARGET_SUPPORT_DIR") {
82
0
      return this->ReplaceValues->TargetSupportDir;
83
0
    }
84
0
  }
85
0
  if (this->ReplaceValues->ObjectDir) {
86
0
    if (variable == "OBJECT_DIR") {
87
0
      return this->ReplaceValues->ObjectDir;
88
0
    }
89
0
  }
90
0
  if (this->ReplaceValues->ObjectFileDir) {
91
0
    if (variable == "OBJECT_FILE_DIR") {
92
0
      return this->ReplaceValues->ObjectFileDir;
93
0
    }
94
0
  }
95
0
  if (this->ReplaceValues->Objects) {
96
0
    if (variable == "OBJECTS") {
97
0
      return this->ReplaceValues->Objects;
98
0
    }
99
0
  }
100
0
  if (this->ReplaceValues->ObjectsQuoted) {
101
0
    if (variable == "OBJECTS_QUOTED") {
102
0
      return this->ReplaceValues->ObjectsQuoted;
103
0
    }
104
0
  }
105
0
  if (this->ReplaceValues->CudaCompileMode) {
106
0
    if (variable == "CUDA_COMPILE_MODE") {
107
0
      return this->ReplaceValues->CudaCompileMode;
108
0
    }
109
0
  }
110
0
  if (this->ReplaceValues->AIXExports) {
111
0
    if (variable == "AIX_EXPORTS") {
112
0
      return this->ReplaceValues->AIXExports;
113
0
    }
114
0
  }
115
0
  if (this->ReplaceValues->ISPCHeader) {
116
0
    if (variable == "ISPC_HEADER") {
117
0
      return this->ReplaceValues->ISPCHeader;
118
0
    }
119
0
  }
120
0
  if (this->ReplaceValues->Defines && variable == "DEFINES") {
121
0
    return this->ReplaceValues->Defines;
122
0
  }
123
0
  if (this->ReplaceValues->Includes && variable == "INCLUDES") {
124
0
    return this->ReplaceValues->Includes;
125
0
  }
126
0
  if (this->ReplaceValues->SwiftLibraryName) {
127
0
    if (variable == "SWIFT_LIBRARY_NAME") {
128
0
      return this->ReplaceValues->SwiftLibraryName;
129
0
    }
130
0
  }
131
0
  if (this->ReplaceValues->SwiftModule) {
132
0
    if (variable == "SWIFT_MODULE") {
133
0
      return this->ReplaceValues->SwiftModule;
134
0
    }
135
0
  }
136
0
  if (this->ReplaceValues->SwiftModuleName) {
137
0
    if (variable == "SWIFT_MODULE_NAME") {
138
0
      return this->ReplaceValues->SwiftModuleName;
139
0
    }
140
0
  }
141
0
  if (this->ReplaceValues->SwiftSources) {
142
0
    if (variable == "SWIFT_SOURCES") {
143
0
      return this->ReplaceValues->SwiftSources;
144
0
    }
145
0
  }
146
0
  if (this->ReplaceValues->RustSources) {
147
0
    if (variable == "RUST_SOURCES") {
148
0
      return this->ReplaceValues->RustSources;
149
0
    }
150
0
  }
151
0
  if (this->ReplaceValues->RustObjectDeps) {
152
0
    if (variable == "RUST_OBJECT_DEPS") {
153
0
      return this->ReplaceValues->RustObjectDeps;
154
0
    }
155
0
  }
156
0
  if (this->ReplaceValues->TargetPDB) {
157
0
    if (variable == "TARGET_PDB") {
158
0
      return this->ReplaceValues->TargetPDB;
159
0
    }
160
0
  }
161
0
  if (this->ReplaceValues->TargetCompilePDB) {
162
0
    if (variable == "TARGET_COMPILE_PDB") {
163
0
      return this->ReplaceValues->TargetCompilePDB;
164
0
    }
165
0
  }
166
0
  if (this->ReplaceValues->DependencyFile) {
167
0
    if (variable == "DEP_FILE") {
168
0
      return this->ReplaceValues->DependencyFile;
169
0
    }
170
0
  }
171
0
  if (this->ReplaceValues->DependencyTarget) {
172
0
    if (variable == "DEP_TARGET") {
173
0
      return this->ReplaceValues->DependencyTarget;
174
0
    }
175
0
  }
176
0
  if (this->ReplaceValues->Fatbinary) {
177
0
    if (variable == "FATBINARY") {
178
0
      return this->ReplaceValues->Fatbinary;
179
0
    }
180
0
  }
181
0
  if (this->ReplaceValues->RegisterFile) {
182
0
    if (variable == "REGISTER_FILE") {
183
0
      return this->ReplaceValues->RegisterFile;
184
0
    }
185
0
  }
186
187
0
  if (this->ReplaceValues->Target) {
188
0
    if (variable == "TARGET_QUOTED") {
189
0
      std::string targetQuoted = this->ReplaceValues->Target;
190
0
      if (!targetQuoted.empty() && targetQuoted.front() != '\"') {
191
0
        targetQuoted = '\"';
192
0
        targetQuoted += this->ReplaceValues->Target;
193
0
        targetQuoted += '\"';
194
0
      }
195
0
      return targetQuoted;
196
0
    }
197
0
    if (variable == "TARGET_UNQUOTED") {
198
0
      std::string unquoted = this->ReplaceValues->Target;
199
0
      std::string::size_type sz = unquoted.size();
200
0
      if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') {
201
0
        unquoted = unquoted.substr(1, sz - 2);
202
0
      }
203
0
      return unquoted;
204
0
    }
205
0
    if (this->ReplaceValues->LanguageCompileFlags) {
206
0
      if (variable == "LANGUAGE_COMPILE_FLAGS") {
207
0
        return this->ReplaceValues->LanguageCompileFlags;
208
0
      }
209
0
    }
210
0
    if (this->ReplaceValues->Target) {
211
0
      if (variable == "TARGET") {
212
0
        return this->ReplaceValues->Target;
213
0
      }
214
0
    }
215
0
    if (variable == "TARGET_IMPLIB") {
216
0
      return this->TargetImpLib;
217
0
    }
218
0
    if (variable == "TARGET_VERSION_MAJOR") {
219
0
      if (this->ReplaceValues->TargetVersionMajor) {
220
0
        return this->ReplaceValues->TargetVersionMajor;
221
0
      }
222
0
      return "0";
223
0
    }
224
0
    if (variable == "TARGET_VERSION_MINOR") {
225
0
      if (this->ReplaceValues->TargetVersionMinor) {
226
0
        return this->ReplaceValues->TargetVersionMinor;
227
0
      }
228
0
      return "0";
229
0
    }
230
0
    if (this->ReplaceValues->Target) {
231
0
      if (variable == "TARGET_BASE") {
232
        // Strip the last extension off the target name.
233
0
        std::string targetBase = this->ReplaceValues->Target;
234
0
        std::string::size_type pos = targetBase.rfind('.');
235
0
        if (pos != std::string::npos) {
236
0
          return targetBase.substr(0, pos);
237
0
        }
238
0
        return targetBase;
239
0
      }
240
0
    }
241
0
  }
242
0
  if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
243
0
      variable == "TARGET_INSTALLNAME_DIR") {
244
    // All these variables depend on TargetSOName
245
0
    if (this->ReplaceValues->TargetSOName) {
246
0
      if (variable == "TARGET_SONAME") {
247
0
        return this->ReplaceValues->TargetSOName;
248
0
      }
249
0
      if (variable == "SONAME_FLAG" && this->ReplaceValues->SONameFlag) {
250
0
        return this->ReplaceValues->SONameFlag;
251
0
      }
252
0
      if (this->ReplaceValues->TargetInstallNameDir &&
253
0
          variable == "TARGET_INSTALLNAME_DIR") {
254
0
        return this->ReplaceValues->TargetInstallNameDir;
255
0
      }
256
0
    }
257
0
    return "";
258
0
  }
259
0
  if (this->ReplaceValues->LinkLibraries) {
260
0
    if (variable == "LINK_LIBRARIES") {
261
0
      return this->ReplaceValues->LinkLibraries;
262
0
    }
263
0
  }
264
0
  if (this->ReplaceValues->Language) {
265
0
    if (variable == "LANGUAGE") {
266
0
      return this->ReplaceValues->Language;
267
0
    }
268
0
  }
269
0
  if (this->ReplaceValues->CMTargetName) {
270
0
    if (variable == "TARGET_NAME") {
271
0
      return this->ReplaceValues->CMTargetName;
272
0
    }
273
0
  }
274
0
  if (this->ReplaceValues->CMTargetType) {
275
0
    if (variable == "TARGET_TYPE") {
276
0
      return this->ReplaceValues->CMTargetType;
277
0
    }
278
0
  }
279
0
  if (this->ReplaceValues->Output) {
280
0
    if (variable == "OUTPUT") {
281
0
      return this->ReplaceValues->Output;
282
0
    }
283
0
  }
284
0
  if (variable == "CMAKE_COMMAND") {
285
0
    return this->OutputConverter->ConvertToOutputFormat(
286
0
      cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
287
0
  }
288
0
  if (variable == "ROLE") {
289
0
    if (this->ReplaceValues->Role) {
290
0
      return this->ReplaceValues->Role;
291
0
    }
292
0
    return "";
293
0
  }
294
0
  if (variable == "CONFIG") {
295
0
    if (this->ReplaceValues->Config) {
296
0
      return this->ReplaceValues->Config;
297
0
    }
298
0
    return "";
299
0
  }
300
301
0
  auto compIt = this->Compilers.find(variable);
302
303
0
  if (compIt != this->Compilers.end()) {
304
0
    std::string ret = this->OutputConverter->ConvertToOutputForExisting(
305
0
      this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER"]);
306
0
    std::string const& compilerArg1 =
307
0
      this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_ARG1"];
308
0
    std::string const& compilerTarget =
309
0
      this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_TARGET"];
310
0
    std::string const& compilerOptionTarget =
311
0
      this->VariableMappings["CMAKE_" + compIt->second +
312
0
                             "_COMPILE_OPTIONS_TARGET"];
313
0
    std::string const& compilerExternalToolchain =
314
0
      this->VariableMappings["CMAKE_" + compIt->second +
315
0
                             "_COMPILER_EXTERNAL_TOOLCHAIN"];
316
0
    std::string const& compilerOptionExternalToolchain =
317
0
      this->VariableMappings["CMAKE_" + compIt->second +
318
0
                             "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN"];
319
0
    std::string const& compilerOptionSysroot =
320
0
      this->VariableMappings["CMAKE_" + compIt->second +
321
0
                             "_COMPILE_OPTIONS_SYSROOT"];
322
323
0
    if (compIt->second == this->ReplaceValues->Language &&
324
0
        this->ReplaceValues->Launcher) {
325
      // Add launcher as part of expansion so that it always appears
326
      // immediately before the command itself, regardless of whether the
327
      // overall rule template contains other content at the front.
328
0
      ret = cmStrCat(this->ReplaceValues->Launcher, ' ', ret);
329
0
    }
330
331
    // if there are required arguments to the compiler add it
332
    // to the compiler string
333
0
    if (!compilerArg1.empty()) {
334
0
      ret += " ";
335
0
      ret += compilerArg1;
336
0
    }
337
0
    if (!compilerTarget.empty() && !compilerOptionTarget.empty()) {
338
0
      ret += " ";
339
0
      ret += compilerOptionTarget;
340
0
      ret += compilerTarget;
341
0
    }
342
0
    if (!compilerExternalToolchain.empty() &&
343
0
        !compilerOptionExternalToolchain.empty()) {
344
0
      ret += " ";
345
0
      ret += compilerOptionExternalToolchain;
346
0
      ret +=
347
0
        this->OutputConverter->EscapeForShell(compilerExternalToolchain, true);
348
0
    }
349
0
    std::string sysroot;
350
    // Some platforms may use separate sysroots for compiling and linking.
351
    // When the build step is link, pass the link sysroot instead.
352
0
    if (this->BuildStep == cmBuildStep::Link) {
353
0
      sysroot = this->LinkerSysroot;
354
0
    } else {
355
0
      sysroot = this->CompilerSysroot;
356
0
    }
357
0
    if (!sysroot.empty() && !compilerOptionSysroot.empty()) {
358
0
      ret += " ";
359
0
      ret += compilerOptionSysroot;
360
0
      ret += this->OutputConverter->EscapeForShell(sysroot, true);
361
0
    }
362
0
    return ret;
363
0
  }
364
365
0
  auto mapIt = this->VariableMappings.find(variable);
366
0
  if (mapIt != this->VariableMappings.end()) {
367
0
    if (variable.find("_FLAG") == std::string::npos) {
368
0
      return this->OutputConverter->ConvertToOutputForExisting(mapIt->second);
369
0
    }
370
0
    return mapIt->second;
371
0
  }
372
0
  return variable;
373
0
}
374
375
void cmRulePlaceholderExpander::ExpandRuleVariables(
376
  cmOutputConverter* outputConverter, std::string& s,
377
  RuleVariables const& replaceValues)
378
0
{
379
0
  this->OutputConverter = outputConverter;
380
0
  this->ReplaceValues = &replaceValues;
381
382
0
  this->ExpandVariables(s);
383
0
}