Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmake.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 "cmake.h"
4
5
#include <algorithm>
6
#include <array>
7
#include <cassert>
8
#include <chrono>
9
#include <climits>
10
#include <cstdio>
11
#include <cstdlib>
12
#include <initializer_list>
13
#include <iostream>
14
#include <iterator>
15
#include <sstream>
16
#include <stdexcept>
17
#include <utility>
18
19
#include <cm/memory>
20
#include <cm/optional>
21
#include <cm/string_view>
22
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
23
#  include <cm/iterator>
24
#endif
25
26
#include <cmext/algorithm>
27
#include <cmext/string_view>
28
29
#include <sys/types.h>
30
31
#include "cmsys/FStream.hxx"
32
#include "cmsys/Glob.hxx"
33
#include "cmsys/RegularExpression.hxx"
34
35
#include "cm_sys_stat.h"
36
37
#include "cmBuildOptions.h"
38
#include "cmCMakePath.h"
39
#include "cmCMakePresetsGraph.h"
40
#include "cmCacheDocumentationTable.h"
41
#include "cmCommandLineArgument.h"
42
#include "cmCommands.h"
43
#include "cmDocumentation.h"
44
#include "cmDocumentationEntry.h"
45
#include "cmDuration.h"
46
#include "cmExternalMakefileProjectGenerator.h"
47
#include "cmFileTimeCache.h"
48
#include "cmGeneratorExpression.h"
49
#include "cmGeneratorTarget.h"
50
#include "cmGlobCacheEntry.h" // IWYU pragma: keep
51
#include "cmGlobalGenerator.h"
52
#include "cmGlobalGeneratorFactory.h"
53
#include "cmJSONState.h"
54
#include "cmLinkLineComputer.h"
55
#include "cmList.h"
56
#include "cmLocalGenerator.h"
57
#include "cmMakefile.h"
58
#include "cmMessenger.h"
59
#include "cmPolicies.h"
60
#include "cmState.h"
61
#include "cmStateDirectory.h"
62
#include "cmStringAlgorithms.h"
63
#include "cmSystemTools.h"
64
#include "cmTarget.h"
65
#include "cmTargetLinkLibraryType.h"
66
#include "cmUVProcessChain.h"
67
#include "cmUtils.hxx"
68
#include "cmVersionConfig.h"
69
#include "cmWorkingDirectory.h"
70
71
#ifdef CMake_ENABLE_DEBUGGER
72
#  include "cmDebuggerAdapter.h"
73
#  ifdef _WIN32
74
#    include "cmDebuggerWindowsPipeConnection.h"
75
#  else //!_WIN32
76
#    include "cmDebuggerPosixPipeConnection.h"
77
#  endif //_WIN32
78
#endif
79
80
#if !defined(CMAKE_BOOTSTRAP)
81
#  include <unordered_map>
82
83
#  include <cm3p/curl/curl.h>
84
#  include <cm3p/json/writer.h>
85
86
#  include "cmCMakePresetsArgs.h"
87
#  include "cmConfigureLog.h"
88
#  include "cmFileAPI.h"
89
#  include "cmGraphVizWriter.h"
90
#  include "cmInstrumentation.h"
91
#  include "cmInstrumentationInterrupt.h"
92
#  include "cmInstrumentationQuery.h"
93
#  include "cmMakefileProfilingData.h"
94
#  include "cmVariableWatch.h"
95
#endif
96
97
#if defined(__MINGW32__) && defined(CMAKE_BOOTSTRAP)
98
#  define CMAKE_BOOT_MINGW
99
#endif
100
101
// include the generator
102
#if defined(_WIN32) && !defined(__CYGWIN__)
103
#  if !defined(CMAKE_BOOT_MINGW)
104
#    include <cmext/memory>
105
106
#    include "cmGlobalBorlandMakefileGenerator.h"
107
#    include "cmGlobalFastbuildGenerator.h"
108
#    include "cmGlobalJOMMakefileGenerator.h"
109
#    include "cmGlobalNMakeMakefileGenerator.h"
110
#    include "cmGlobalVisualStudioVersionedGenerator.h"
111
#    include "cmVSSetupHelper.h"
112
113
#    define CMAKE_HAVE_VS_GENERATORS
114
#  endif
115
#  include "cmGlobalMSYSMakefileGenerator.h"
116
#  include "cmGlobalMinGWMakefileGenerator.h"
117
#else
118
#endif
119
#if defined(CMAKE_USE_WMAKE)
120
#  include "cmGlobalWatcomWMakeGenerator.h"
121
#endif
122
#if !defined(CMAKE_BOOTSTRAP)
123
#  include "cmGlobalNinjaGenerator.h"
124
#  include "cmGlobalUnixMakefileGenerator3.h"
125
#elif defined(CMAKE_BOOTSTRAP_MAKEFILES)
126
#  include "cmGlobalUnixMakefileGenerator3.h"
127
#elif defined(CMAKE_BOOTSTRAP_NINJA)
128
#  include "cmGlobalNinjaGenerator.h"
129
#endif
130
#include "cmGlobalFastbuildGenerator.h"
131
132
#if !defined(CMAKE_BOOTSTRAP)
133
#  include "cmExtraCodeBlocksGenerator.h"
134
#  include "cmExtraCodeLiteGenerator.h"
135
#  include "cmExtraEclipseCDT4Generator.h"
136
#  include "cmExtraKateGenerator.h"
137
#  include "cmExtraSublimeTextGenerator.h"
138
139
// NOTE: the __linux__ macro is predefined on Android host too, but
140
// main CMakeLists.txt filters out this generator by host name.
141
#  if (defined(__linux__) && !defined(__ANDROID__)) || defined(_WIN32)
142
#    include "cmGlobalGhsMultiGenerator.h"
143
#  endif
144
#endif
145
146
#if defined(__APPLE__)
147
#  if !defined(CMAKE_BOOTSTRAP)
148
#    include "cmGlobalXCodeGenerator.h"
149
150
#    define CMAKE_USE_XCODE 1
151
#  endif
152
#  include <sys/resource.h>
153
#  include <sys/time.h>
154
#endif
155
156
namespace {
157
158
#if !defined(CMAKE_BOOTSTRAP)
159
using JsonValueMapType = std::unordered_map<std::string, Json::Value>;
160
#endif
161
162
35
auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool {
163
35
  return true;
164
35
};
165
166
using CommandArgument =
167
  cmCommandLineArgument<bool(std::string const& value, cmake* state)>;
168
169
#ifndef CMAKE_BOOTSTRAP
170
void cmWarnUnusedCliWarning(std::string const& variable,
171
                            cmVariableWatch::AccessType /*unused*/, void* ctx,
172
                            char const* /*unused*/,
173
                            cmMakefile const* /*unused*/)
174
0
{
175
0
  cmake* cm = reinterpret_cast<cmake*>(ctx);
176
0
  cm->MarkCliAsUsed(variable);
177
0
}
178
179
void cmDeprecatedWatch(std::string const& /*unused*/,
180
                       cmVariableWatch::AccessType /*unused*/,
181
                       void* /*unused*/, char const* /*unused*/,
182
                       cmMakefile const* mf)
183
0
{
184
0
  if (mf->GetPolicyStatus(cmPolicies::CMP0218) == cmPolicies::WARN) {
185
0
    mf->IssuePolicyWarning(cmPolicies::CMP0218);
186
0
  }
187
0
}
188
#endif
189
190
void warnDeprecated(cm::string_view oldOption, cm::string_view newOption)
191
0
{
192
0
  std::cerr << "The "_s << oldOption << " option is deprecated.  Use "_s
193
0
            << newOption << " instead.\n"_s;
194
0
}
195
196
std::string normalizeCliWarningName(cm::string_view cliName)
197
0
{
198
0
  std::string out = cmStrCat("CMD_"_s, cmSystemTools::UpperCase(cliName));
199
0
  std::replace(out.begin(), out.end(), '-', '_');
200
0
  return out;
201
0
}
202
203
std::string findClosestOption(std::string const& arg,
204
                              std::vector<CommandArgument> const& arguments)
205
0
{
206
0
  return cmFindClosestCommandLineArgument(arg, arguments);
207
0
}
208
209
bool cmakeCheckStampFile(std::string const& stampName)
210
0
{
211
  // The stamp file does not exist.  Use the stamp dependencies to
212
  // determine whether it is really out of date.  This works in
213
  // conjunction with cmLocalVisualStudio7Generator to avoid
214
  // repeatedly re-running CMake when the user rebuilds the entire
215
  // solution.
216
0
  std::string stampDepends = cmStrCat(stampName, ".depend");
217
#if defined(_WIN32) || defined(__CYGWIN__)
218
  cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
219
#else
220
0
  cmsys::ifstream fin(stampDepends.c_str());
221
0
#endif
222
0
  if (!fin) {
223
    // The stamp dependencies file cannot be read.  Just assume the
224
    // build system is really out of date.
225
0
    std::cout << "CMake is re-running because " << stampName
226
0
              << " dependency file is missing.\n";
227
0
    return false;
228
0
  }
229
230
  // Compare the stamp dependencies against the dependency file itself.
231
0
  {
232
0
    cmFileTimeCache ftc;
233
0
    std::string dep;
234
0
    while (cmSystemTools::GetLineFromStream(fin, dep)) {
235
0
      int result;
236
0
      if (!dep.empty() && dep[0] != '#' &&
237
0
          (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
238
        // The stamp depends file is older than this dependency.  The
239
        // build system is really out of date.
240
        /* clang-format off */
241
0
        std::cout << "CMake is re-running because " << stampName
242
0
                  << " is out-of-date.\n"
243
0
                     "  the file '" << dep << "'\n"
244
0
                     "  is newer than '" << stampDepends << "'\n"
245
0
                     "  result='" << result << "'\n";
246
        /* clang-format on */
247
0
        return false;
248
0
      }
249
0
    }
250
0
  }
251
252
  // The build system is up to date.  The stamp file has been removed
253
  // by the VS IDE due to a "rebuild" request.  Restore it atomically.
254
0
  std::string stampTemp =
255
0
    cmStrCat(stampName, ".tmp", cmSystemTools::RandomNumber());
256
0
  {
257
    // TODO: Teach cmGeneratedFileStream to use a random temp file (with
258
    // multiple tries in unlikely case of conflict) and use that here.
259
0
    cmsys::ofstream stamp(stampTemp);
260
0
    stamp << "# CMake generation timestamp file for this directory.\n";
261
0
  }
262
0
  std::string err;
263
0
  if (cmSystemTools::RenameFile(stampTemp, stampName,
264
0
                                cmSystemTools::Replace::Yes, &err) ==
265
0
      cmSystemTools::RenameResult::Success) {
266
    // CMake does not need to re-run because the stamp file is up-to-date.
267
0
    return true;
268
0
  }
269
0
  cmSystemTools::RemoveFile(stampTemp);
270
0
  cmSystemTools::Error(
271
0
    cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err));
272
0
  return false;
273
0
}
274
275
bool cmakeCheckStampList(std::string const& stampList)
276
0
{
277
  // If the stamp list does not exist CMake must rerun to generate it.
278
0
  if (!cmSystemTools::FileExists(stampList)) {
279
0
    std::cout << "CMake is re-running because generate.stamp.list "
280
0
                 "is missing.\n";
281
0
    return false;
282
0
  }
283
0
  cmsys::ifstream fin(stampList.c_str());
284
0
  if (!fin) {
285
0
    std::cout << "CMake is re-running because generate.stamp.list "
286
0
                 "could not be read.\n";
287
0
    return false;
288
0
  }
289
290
  // Check each stamp.
291
0
  std::string stampName;
292
0
  while (cmSystemTools::GetLineFromStream(fin, stampName)) {
293
0
    if (!cmakeCheckStampFile(stampName)) {
294
0
      return false;
295
0
    }
296
0
  }
297
0
  return true;
298
0
}
299
300
} // namespace
301
302
cmDocumentationEntry cmake::CMAKE_STANDARD_OPTIONS_TABLE[15] = {
303
  { "-S <path-to-source>", "Explicitly specify a source directory." },
304
  { "-B <path-to-build>", "Explicitly specify a build directory." },
305
  { "-C <initial-cache>", "Pre-load a script to populate the cache." },
306
  { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." },
307
  { "-U <globbing_expr>", "Remove matching entries from CMake cache." },
308
  { "-G <generator-name>", "Specify a build system generator." },
309
  { "-T <toolset-name>", "Specify toolset name if supported by generator." },
310
  { "-A <platform-name>", "Specify platform name if supported by generator." },
311
  { "--toolchain <file>", "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." },
312
  { "--install-prefix <directory>",
313
    "Specify install directory [CMAKE_INSTALL_PREFIX]." },
314
  { "--project-file <project-file-name>",
315
    "Specify an alternate project file name." },
316
  { "-W<category>", "Enable the specified category of warnings." },
317
  { "-Wno-<category>", "Suppress the specified category of warnings." },
318
  { "-Werror=<category>", "Make the specified category of warnings errors." },
319
  { "-Wno-error=<category>",
320
    "Make the specified category of warnings not errors." },
321
};
322
323
cmake::cmake(cmState::Role role, cmState::TryCompile isTryCompile)
324
19.9k
  : CMakeWorkingDirectory(cmSystemTools::GetLogicalWorkingDirectory())
325
19.9k
  , FileTimeCache(cm::make_unique<cmFileTimeCache>())
326
  , GeneratorExpressionParseCache(
327
19.9k
      cm::make_unique<cmGeneratorExpressionParseCache>())
328
#ifndef CMAKE_BOOTSTRAP
329
19.9k
  , VariableWatch(cm::make_unique<cmVariableWatch>())
330
#endif
331
19.9k
  , State(cm::make_unique<cmState>(role, isTryCompile))
332
19.9k
  , Messenger(cm::make_unique<cmMessenger>())
333
19.9k
{
334
19.9k
  this->TraceFile.close();
335
19.9k
  this->CurrentSnapshot = this->State->CreateBaseSnapshot();
336
337
#ifdef __APPLE__
338
  struct rlimit rlp;
339
  if (!getrlimit(RLIMIT_STACK, &rlp)) {
340
    if (rlp.rlim_cur != rlp.rlim_max) {
341
      rlp.rlim_cur = rlp.rlim_max;
342
      setrlimit(RLIMIT_STACK, &rlp);
343
    }
344
  }
345
#endif
346
347
19.9k
  this->AddDefaultGenerators();
348
19.9k
  this->AddDefaultExtraGenerators();
349
19.9k
  if (role == cmState::Role::Project || role == cmState::Role::FindPackage ||
350
35
      role == cmState::Role::Script || role == cmState::Role::CTest ||
351
19.9k
      role == cmState::Role::CPack) {
352
19.9k
    this->AddScriptingCommands();
353
19.9k
  }
354
19.9k
  if (role == cmState::Role::Project || role == cmState::Role::FindPackage) {
355
19.8k
    this->AddProjectCommands();
356
19.8k
  }
357
358
19.9k
  if (role == cmState::Role::Project || role == cmState::Role::Help) {
359
19.8k
    this->LoadEnvironmentPresets();
360
19.8k
  }
361
362
  // Make sure we can capture the build tool output.
363
19.9k
  cmSystemTools::EnableVSConsoleOutput();
364
365
  // Set up a list of source and header extensions.
366
  // These are used to find files when the extension is not given.
367
19.9k
  {
368
19.9k
    auto setupExts = [](FileExtensions& exts,
369
119k
                        std::initializer_list<cm::string_view> extList) {
370
      // Fill ordered vector
371
119k
      exts.ordered.reserve(extList.size());
372
677k
      for (cm::string_view ext : extList) {
373
677k
        exts.ordered.emplace_back(ext);
374
677k
      }
375
      // Fill unordered set
376
119k
      exts.unordered.insert(exts.ordered.begin(), exts.ordered.end());
377
119k
    };
378
379
    // The "c" extension MUST precede the "C" extension.
380
19.9k
    setupExts(this->CLikeSourceFileExtensions,
381
19.9k
              { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M",
382
19.9k
                "mm", "ixx", "cppm", "ccm", "cxxm", "c++m" });
383
19.9k
    setupExts(this->HeaderFileExtensions,
384
19.9k
              { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" });
385
19.9k
    setupExts(this->CudaFileExtensions, { "cu" });
386
19.9k
    setupExts(this->FortranFileExtensions,
387
19.9k
              { "f", "F", "for", "f77", "f90", "f95", "f03" });
388
19.9k
    setupExts(this->HipFileExtensions, { "hip" });
389
19.9k
    setupExts(this->ISPCFileExtensions, { "ispc" });
390
19.9k
  }
391
19.9k
}
392
393
19.9k
cmake::~cmake() = default;
394
395
#if !defined(CMAKE_BOOTSTRAP)
396
Json::Value cmake::ReportVersionJson() const
397
0
{
398
0
  Json::Value version = Json::objectValue;
399
0
  version["string"] = CMake_VERSION;
400
0
  version["major"] = CMake_VERSION_MAJOR;
401
0
  version["minor"] = CMake_VERSION_MINOR;
402
0
  version["suffix"] = CMake_VERSION_SUFFIX;
403
0
  version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1);
404
0
  version["patch"] = CMake_VERSION_PATCH;
405
0
  return version;
406
0
}
407
408
Json::Value cmake::ReportCapabilitiesJson() const
409
0
{
410
0
  Json::Value obj = Json::objectValue;
411
412
  // Version information:
413
0
  obj["version"] = this->ReportVersionJson();
414
415
  // Generators:
416
0
  std::vector<cmake::GeneratorInfo> generatorInfoList;
417
0
  this->GetRegisteredGenerators(generatorInfoList);
418
419
0
  auto* curlVersion = curl_version_info(CURLVERSION_FIRST);
420
421
0
  JsonValueMapType generatorMap;
422
0
  for (cmake::GeneratorInfo const& gi : generatorInfoList) {
423
0
    if (gi.isAlias) { // skip aliases, they are there for compatibility reasons
424
                      // only
425
0
      continue;
426
0
    }
427
428
0
    if (gi.extraName.empty()) {
429
0
      Json::Value gen = Json::objectValue;
430
0
      gen["name"] = gi.name;
431
0
      gen["toolsetSupport"] = gi.supportsToolset;
432
0
      gen["platformSupport"] = gi.supportsPlatform;
433
0
      if (!gi.supportedPlatforms.empty()) {
434
0
        Json::Value supportedPlatforms = Json::arrayValue;
435
0
        for (std::string const& platform : gi.supportedPlatforms) {
436
0
          supportedPlatforms.append(platform);
437
0
        }
438
0
        gen["supportedPlatforms"] = std::move(supportedPlatforms);
439
0
      }
440
0
      gen["extraGenerators"] = Json::arrayValue;
441
0
      generatorMap[gi.name] = gen;
442
0
    } else {
443
0
      Json::Value& gen = generatorMap[gi.baseName];
444
0
      gen["extraGenerators"].append(gi.extraName);
445
0
    }
446
0
  }
447
448
0
  Json::Value generators = Json::arrayValue;
449
0
  for (auto const& i : generatorMap) {
450
0
    generators.append(i.second);
451
0
  }
452
0
  obj["generators"] = generators;
453
0
  obj["fileApi"] = cmFileAPI::ReportCapabilities();
454
0
  cmInstrumentationQuery::Version const dataVersion =
455
0
    cmInstrumentationQuery::LatestDataVersion();
456
0
  obj["instrumentation"]["apiVersion"] = 1;
457
0
  obj["instrumentation"]["dataVersion"]["major"] = dataVersion.Major;
458
0
  obj["instrumentation"]["dataVersion"]["minor"] = dataVersion.Minor;
459
0
  obj["serverMode"] = false;
460
0
  obj["tls"] = static_cast<bool>(curlVersion->features & CURL_VERSION_SSL);
461
0
#  ifdef CMake_ENABLE_DEBUGGER
462
0
  obj["debugger"] = true;
463
#  else
464
  obj["debugger"] = false;
465
#  endif
466
467
0
  return obj;
468
0
}
469
#endif
470
471
std::string cmake::ReportCapabilities() const
472
0
{
473
0
  std::string result;
474
0
#if !defined(CMAKE_BOOTSTRAP)
475
0
  Json::FastWriter writer;
476
0
  result = writer.write(this->ReportCapabilitiesJson());
477
#else
478
  result = "Not supported";
479
#endif
480
0
  return result;
481
0
}
482
483
bool cmake::RoleSupportsExitCode() const
484
0
{
485
0
  cmState::Role const role = this->State->GetRole();
486
0
  return role == cmState::Role::Script || role == cmState::Role::CTest;
487
0
}
488
489
cmake::CommandFailureAction cmake::GetCommandFailureAction() const
490
0
{
491
0
  switch (this->State->GetRole()) {
492
0
    case cmState::Role::Project:
493
0
    case cmState::Role::CTest:
494
0
      return CommandFailureAction::EXIT_CODE;
495
0
    default:
496
0
      return CommandFailureAction::FATAL_ERROR;
497
0
  }
498
0
}
499
500
void cmake::CleanupCommandsAndMacros()
501
0
{
502
0
  this->CurrentSnapshot = this->State->Reset(this->CurrentSnapshot);
503
0
  this->State->RemoveUserDefinedCommands();
504
0
  this->CurrentSnapshot.SetDefaultDefinitions();
505
  // FIXME: InstalledFiles probably belongs in the global generator.
506
0
  this->InstalledFiles.clear();
507
0
}
508
509
#ifndef CMAKE_BOOTSTRAP
510
void cmake::SetDiagnosticsFromPreset(
511
  std::map<cmDiagnosticCategory, bool> const& warnings,
512
  std::map<cmDiagnosticCategory, bool> const& errors)
513
0
{
514
0
  for (unsigned i = 1; i < cmDiagnostics::CategoryCount; ++i) {
515
0
    auto const category = static_cast<cmDiagnosticCategory>(i);
516
517
0
    auto const wi = warnings.find(category);
518
0
    if (wi != warnings.end()) {
519
0
      if (wi->second) {
520
0
        this->AlterDiagnostic(&cmStateSnapshot::PromoteDiagnostic, category,
521
0
                              cmDiagnostics::Warn, true);
522
0
      } else {
523
0
        this->AlterDiagnostic(&cmStateSnapshot::DemoteDiagnostic, category,
524
0
                              cmDiagnostics::Ignore, true);
525
0
      }
526
0
    }
527
528
0
    auto const ei = errors.find(category);
529
0
    if (ei != errors.end()) {
530
0
      if (ei->second) {
531
0
        this->AlterDiagnostic(&cmStateSnapshot::PromoteDiagnostic, category,
532
0
                              cmDiagnostics::SendError, true);
533
0
      } else {
534
0
        this->AlterDiagnostic(&cmStateSnapshot::DemoteDiagnostic, category,
535
0
                              cmDiagnostics::Warn, true);
536
0
      }
537
0
    }
538
0
  }
539
0
}
540
541
void cmake::ProcessPresetVariables()
542
1
{
543
1
  for (auto const& var : this->UnprocessedPresetVariables) {
544
0
    if (!var.second) {
545
0
      continue;
546
0
    }
547
0
    cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
548
0
    if (!var.second->Type.empty()) {
549
0
      type = cmState::StringToCacheEntryType(var.second->Type);
550
0
    }
551
0
    this->ProcessCacheArg(var.first, var.second->Value, type);
552
0
  }
553
1
}
554
555
void cmake::PrintPresetVariables()
556
0
{
557
0
  bool first = true;
558
0
  for (auto const& var : this->UnprocessedPresetVariables) {
559
0
    if (!var.second) {
560
0
      continue;
561
0
    }
562
0
    cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
563
0
    if (!var.second->Type.empty()) {
564
0
      type = cmState::StringToCacheEntryType(var.second->Type);
565
0
    }
566
0
    if (first) {
567
0
      std::cout << "Preset CMake variables:\n\n";
568
0
      first = false;
569
0
    }
570
0
    std::cout << "  " << var.first;
571
0
    if (type != cmStateEnums::UNINITIALIZED) {
572
0
      std::cout << ':' << cmState::CacheEntryTypeToString(type);
573
0
    }
574
0
    std::cout << "=\"" << var.second->Value << "\"\n";
575
0
  }
576
0
  if (!first) {
577
0
    std::cout << '\n';
578
0
  }
579
0
  this->UnprocessedPresetVariables.clear();
580
0
}
581
582
void cmake::ProcessPresetEnvironment()
583
1
{
584
1
  for (auto const& var : this->UnprocessedPresetEnvironment) {
585
0
    if (var.second) {
586
0
      cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second));
587
0
    }
588
0
  }
589
1
}
590
591
void cmake::PrintPresetEnvironment()
592
0
{
593
0
  bool first = true;
594
0
  for (auto const& var : this->UnprocessedPresetEnvironment) {
595
0
    if (!var.second) {
596
0
      continue;
597
0
    }
598
0
    if (first) {
599
0
      std::cout << "Preset environment variables:\n\n";
600
0
      first = false;
601
0
    }
602
0
    std::cout << "  " << var.first << "=\"" << *var.second << "\"\n";
603
0
  }
604
0
  if (!first) {
605
0
    std::cout << '\n';
606
0
  }
607
0
  this->UnprocessedPresetEnvironment.clear();
608
0
}
609
#endif
610
611
// Parse the args
612
bool cmake::SetCacheArgs(std::vector<std::string> const& args)
613
1
{
614
1
  static std::string const kCMAKE_POLICY_VERSION_MINIMUM =
615
1
    "CMAKE_POLICY_VERSION_MINIMUM";
616
1
  if (!this->State->GetInitializedCacheValue(kCMAKE_POLICY_VERSION_MINIMUM)) {
617
1
    cm::optional<std::string> policyVersion =
618
1
      cmSystemTools::GetEnvVar(kCMAKE_POLICY_VERSION_MINIMUM);
619
1
    if (policyVersion && !policyVersion->empty()) {
620
0
      this->AddCacheEntry(
621
0
        kCMAKE_POLICY_VERSION_MINIMUM, *policyVersion,
622
0
        "Override policy version for cmake_minimum_required calls.",
623
0
        cmStateEnums::STRING);
624
0
      this->State->SetCacheEntryProperty(kCMAKE_POLICY_VERSION_MINIMUM,
625
0
                                         "ADVANCED", "1");
626
0
    }
627
1
  }
628
629
1
  auto DefineLambda = [](std::string const& entry, cmake* state) -> bool {
630
0
    std::string var;
631
0
    std::string value;
632
0
    cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
633
0
    if (cmState::ParseCacheEntry(entry, var, value, type)) {
634
0
#ifndef CMAKE_BOOTSTRAP
635
0
      state->UnprocessedPresetVariables.erase(var);
636
0
#endif
637
0
      state->ProcessCacheArg(var, value, type);
638
0
    } else {
639
0
      cmSystemTools::Error(cmStrCat("Parse error in command line argument: ",
640
0
                                    entry, "\n Should be: VAR:type=value\n"));
641
0
      return false;
642
0
    }
643
0
    return true;
644
0
  };
645
646
1
  auto WarningLambda = [](cm::string_view option, cmake* state) -> bool {
647
0
    bool foundNo = false;
648
0
    bool foundError = false;
649
650
0
    cm::string_view cname = option;
651
0
    if (cmHasLiteralPrefix(cname, "no-")) {
652
0
      foundNo = true;
653
0
      cname.remove_prefix(3);
654
0
    }
655
656
0
    if (cmHasLiteralPrefix(cname, "error=")) {
657
0
      foundError = true;
658
0
      cname.remove_prefix(6);
659
0
    }
660
661
0
    if (cname.empty()) {
662
0
      cmSystemTools::Error("No warning name provided.");
663
0
      return false;
664
0
    }
665
666
0
    cm::optional<cmDiagnosticCategory> category;
667
0
    if (cname == "dev"_s) {
668
0
      warnDeprecated(
669
0
        option,
670
0
        cmStrCat("-W"_s, option.substr(0, option.size() - 3), "author"_s));
671
0
      category = cmDiagnostics::CMD_AUTHOR;
672
0
    } else {
673
0
      category =
674
0
        cmDiagnostics::GetDiagnosticCategory(normalizeCliWarningName(cname));
675
0
      if (!category) {
676
0
        cmSystemTools::Error(
677
0
          cmStrCat("The warning category \""_s, cname, "\" is not known."));
678
0
        return false;
679
0
      }
680
0
    }
681
682
0
    if (foundNo) {
683
0
      state->AlterDiagnostic(
684
0
        &cmStateSnapshot::DemoteDiagnostic, *category,
685
0
        foundError ? cmDiagnostics::Warn : cmDiagnostics::Ignore, true);
686
0
    } else {
687
0
      state->AlterDiagnostic(
688
0
        &cmStateSnapshot::PromoteDiagnostic, *category,
689
0
        foundError ? cmDiagnostics::SendError : cmDiagnostics::Warn, true);
690
0
    }
691
0
    return true;
692
0
  };
693
694
1
  auto UnSetLambda = [](std::string const& entryPattern,
695
1
                        cmake* state) -> bool {
696
0
    cmsys::RegularExpression regex(
697
0
      cmsys::Glob::PatternToRegex(entryPattern, true, true));
698
    // go through all cache entries and collect the vars which will be
699
    // removed
700
0
    std::vector<std::string> entriesToDelete;
701
0
    std::vector<std::string> cacheKeys = state->State->GetCacheEntryKeys();
702
0
    for (std::string const& ck : cacheKeys) {
703
0
      cmStateEnums::CacheEntryType t = state->State->GetCacheEntryType(ck);
704
0
      if (t != cmStateEnums::STATIC) {
705
0
        if (regex.find(ck)) {
706
0
          entriesToDelete.push_back(ck);
707
0
        }
708
0
      }
709
0
    }
710
711
    // now remove them from the cache
712
0
    for (std::string const& currentEntry : entriesToDelete) {
713
0
#ifndef CMAKE_BOOTSTRAP
714
0
      state->UnprocessedPresetVariables.erase(currentEntry);
715
0
#endif
716
0
      state->State->RemoveCacheEntry(currentEntry);
717
0
    }
718
0
    return true;
719
0
  };
720
721
1
  auto ScriptLambda = [&](std::string const& path, cmake* state) -> bool {
722
1
    assert(this->State->GetRole() == cmState::Role::Script);
723
1
#ifdef CMake_ENABLE_DEBUGGER
724
    // Script mode doesn't hit the usual code path in cmake::Run() that starts
725
    // the debugger, so start it manually here instead.
726
1
    if (!this->StartDebuggerIfEnabled()) {
727
0
      return false;
728
0
    }
729
1
#endif
730
    // Register fake project commands that hint misuse in script mode.
731
1
    GetProjectCommandsInScriptMode(state->GetState());
732
    // Documented behavior of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
733
    // set to $PWD for -P mode.
734
1
    state->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
735
1
    state->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
736
1
    state->ReadListFile(args, cmSystemTools::ToNormalizedPathOnDisk(path));
737
1
    return true;
738
1
  };
739
740
1
  auto PrefixLambda = [&](std::string const& path, cmake* state) -> bool {
741
0
    std::string const var = "CMAKE_INSTALL_PREFIX";
742
0
    cmStateEnums::CacheEntryType type = cmStateEnums::PATH;
743
0
    cmCMakePath absolutePath(path);
744
0
    if (absolutePath.IsAbsolute()) {
745
0
#ifndef CMAKE_BOOTSTRAP
746
0
      state->UnprocessedPresetVariables.erase(var);
747
0
#endif
748
0
      state->ProcessCacheArg(var, path, type);
749
0
      return true;
750
0
    }
751
0
    cmSystemTools::Error("Absolute paths are required for --install-prefix");
752
0
    return false;
753
0
  };
754
755
1
  auto ToolchainLambda = [&](std::string const& path, cmake* state) -> bool {
756
0
    std::string const var = "CMAKE_TOOLCHAIN_FILE";
757
0
    cmStateEnums::CacheEntryType type = cmStateEnums::FILEPATH;
758
0
#ifndef CMAKE_BOOTSTRAP
759
0
    state->UnprocessedPresetVariables.erase(var);
760
0
#endif
761
0
    state->ProcessCacheArg(var, path, type);
762
0
    return true;
763
0
  };
764
765
1
  std::vector<CommandArgument> arguments = {
766
1
    CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
767
1
                     CommandArgument::Values::One,
768
1
                     CommandArgument::RequiresSeparator::No, DefineLambda },
769
1
    CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
770
1
                     CommandArgument::Values::One,
771
1
                     CommandArgument::RequiresSeparator::No, WarningLambda },
772
1
    CommandArgument{ "-U", "-U must be followed with VAR.",
773
1
                     CommandArgument::Values::One,
774
1
                     CommandArgument::RequiresSeparator::No, UnSetLambda },
775
1
    CommandArgument{
776
1
      "-C", "-C must be followed by a file name.",
777
1
      CommandArgument::Values::One, CommandArgument::RequiresSeparator::No,
778
1
      [&](std::string const& value, cmake* state) -> bool {
779
0
        if (value.empty()) {
780
0
          cmSystemTools::Error("No file name specified for -C");
781
0
          return false;
782
0
        }
783
0
        state->SetInInitialCache(true);
784
0
        cmSystemTools::Stdout(
785
0
          cmStrCat("loading initial cache file ", value, '\n'));
786
        // Resolve script path specified on command line
787
        // relative to $PWD.
788
0
        auto path = cmSystemTools::ToNormalizedPathOnDisk(value);
789
0
        state->InitializeFileAPI();
790
0
        state->ReadListFile(args, path);
791
0
        state->SetInInitialCache(false);
792
0
        return true;
793
0
      } },
794
795
1
    CommandArgument{ "-P", "-P must be followed by a file name.",
796
1
                     CommandArgument::Values::One,
797
1
                     CommandArgument::RequiresSeparator::No, ScriptLambda },
798
1
    CommandArgument{ "--toolchain", "No file specified for --toolchain",
799
1
                     CommandArgument::Values::One, ToolchainLambda },
800
1
    CommandArgument{ "--install-prefix",
801
1
                     "No install directory specified for --install-prefix",
802
1
                     CommandArgument::Values::One, PrefixLambda },
803
1
    CommandArgument{ "--find-package", CommandArgument::Values::Zero,
804
1
                     IgnoreAndTrueLambda },
805
1
  };
806
2
  for (decltype(args.size()) i = 1; i < args.size(); ++i) {
807
1
    std::string const& arg = args[i];
808
809
1
    if (arg == "--" && this->State->GetRole() == cmState::Role::Script) {
810
      // Stop processing CMake args and avoid possible errors
811
      // when arbitrary args are given to CMake script.
812
0
      break;
813
0
    }
814
8
    for (auto const& m : arguments) {
815
8
      if (m.matches(arg)) {
816
1
        bool const parsedCorrectly = m.parse(arg, i, args, this);
817
1
        if (!parsedCorrectly) {
818
0
          return false;
819
0
        }
820
1
      }
821
8
    }
822
1
  }
823
824
1
  if (this->State->GetRole() == cmState::Role::FindPackage) {
825
0
    return this->FindPackage(args);
826
0
  }
827
828
1
  return true;
829
1
}
830
831
void cmake::ProcessCacheArg(std::string const& var, std::string const& value,
832
                            cmStateEnums::CacheEntryType type)
833
0
{
834
0
  cmDiagnosticAction const warnUnusedCli =
835
0
    this->CurrentSnapshot.GetDiagnostic(cmDiagnostics::CMD_UNUSED_CLI);
836
837
  // The value is transformed if it is a filepath for example, so
838
  // we can't compare whether the value is already in the cache until
839
  // after we call AddCacheEntry.
840
0
  bool haveValue = false;
841
0
  std::string cachedValue;
842
0
  if (warnUnusedCli != cmDiagnostics::Ignore) {
843
0
    if (cmValue v = this->State->GetInitializedCacheValue(var)) {
844
0
      haveValue = true;
845
0
      cachedValue = *v;
846
0
    }
847
0
  }
848
849
  // See also CMP0218.
850
0
  if (var == "CMAKE_WARN_DEPRECATED") {
851
0
    std::cerr << "The CMAKE_WARN_DEPRECATED variable is deprecated.  "
852
0
                 "Use -W[no-]deprecated instead.\n"_s;
853
0
  } else if (var == "CMAKE_ERROR_DEPRECATED") {
854
0
    std::cerr << "The CMAKE_ERROR_DEPRECATED variable is deprecated.  "
855
0
                 "Use -W[no-]error=deprecated instead.\n"_s;
856
0
  }
857
858
0
  auto const builtIn = cmCacheDocumentationTable::Get(var);
859
0
  std::string const helpString = builtIn.Summary.empty()
860
0
    ? std::string("No help, variable specified on the command line.")
861
0
    : std::string(builtIn.Summary);
862
863
0
  this->AddCacheEntry(var, value, helpString, type);
864
865
0
  if (warnUnusedCli != cmDiagnostics::Ignore) {
866
0
    if (!haveValue ||
867
0
        cachedValue != *this->State->GetInitializedCacheValue(var)) {
868
0
      this->WatchUnusedCli(var);
869
0
    }
870
0
  }
871
0
}
872
873
void cmake::ReadListFile(std::vector<std::string> const& args,
874
                         std::string const& path)
875
1
{
876
  // if a generator was not yet created, temporarily create one
877
1
  cmGlobalGenerator* gg = this->GetGlobalGenerator();
878
879
  // if a generator was not specified use a generic one
880
1
  std::unique_ptr<cmGlobalGenerator> gen;
881
1
  if (!gg) {
882
1
    gen = cm::make_unique<cmGlobalGenerator>(this);
883
1
    gg = gen.get();
884
1
  }
885
886
  // read in the list file to fill the cache
887
1
  if (!path.empty()) {
888
1
    this->CurrentSnapshot = this->State->Reset(this->CurrentSnapshot);
889
1
    cmStateSnapshot snapshot = this->GetCurrentSnapshot();
890
1
    snapshot.GetDirectory().SetCurrentBinary(this->GetHomeOutputDirectory());
891
1
    snapshot.GetDirectory().SetCurrentSource(this->GetHomeDirectory());
892
1
    snapshot.SetDefaultDefinitions();
893
1
    cmMakefile mf(gg, snapshot);
894
1
    if (this->State->GetRole() == cmState::Role::Script) {
895
1
      mf.SetScriptModeFile(path);
896
1
      mf.SetArgcArgv(args);
897
1
    }
898
1
    if (!cmSystemTools::FileExists(path, true)) {
899
0
      cmSystemTools::Error("Not a file: " + path);
900
0
    }
901
1
    if (!mf.ReadListFile(path)) {
902
1
      cmSystemTools::Error("Error processing file: " + path);
903
1
    }
904
1
  }
905
1
}
906
907
bool cmake::FindPackage(std::vector<std::string> const& args)
908
0
{
909
0
  this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
910
0
  this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
911
912
0
  this->SetGlobalGenerator(cm::make_unique<cmGlobalGenerator>(this));
913
914
0
  cmStateSnapshot snapshot = this->GetCurrentSnapshot();
915
0
  snapshot.GetDirectory().SetCurrentBinary(
916
0
    cmSystemTools::GetLogicalWorkingDirectory());
917
0
  snapshot.GetDirectory().SetCurrentSource(
918
0
    cmSystemTools::GetLogicalWorkingDirectory());
919
  // read in the list file to fill the cache
920
0
  snapshot.SetDefaultDefinitions();
921
0
  auto mfu = cm::make_unique<cmMakefile>(this->GetGlobalGenerator(), snapshot);
922
0
  cmMakefile* mf = mfu.get();
923
0
  this->GlobalGenerator->AddMakefile(std::move(mfu));
924
925
0
  mf->SetArgcArgv(args);
926
927
0
  std::string systemFile = mf->GetModulesFile("CMakeFindPackageMode.cmake");
928
0
  mf->ReadListFile(systemFile);
929
930
0
  std::string language = mf->GetSafeDefinition("LANGUAGE");
931
0
  std::string mode = mf->GetSafeDefinition("MODE");
932
0
  std::string packageName = mf->GetSafeDefinition("NAME");
933
0
  bool packageFound = mf->IsOn("PACKAGE_FOUND");
934
0
  bool quiet = mf->IsOn("PACKAGE_QUIET");
935
936
0
  if (!packageFound) {
937
0
    if (!quiet) {
938
0
      printf("%s not found.\n", packageName.c_str());
939
0
    }
940
0
  } else if (mode == "EXIST"_s) {
941
0
    if (!quiet) {
942
0
      printf("%s found.\n", packageName.c_str());
943
0
    }
944
0
  } else if (mode == "COMPILE"_s) {
945
0
    std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
946
0
    cmList includeDirs{ includes };
947
948
0
    this->GlobalGenerator->CreateGenerationObjects();
949
0
    auto const& lg = this->GlobalGenerator->LocalGenerators[0];
950
0
    std::string includeFlags =
951
0
      lg->GetIncludeFlags(includeDirs, nullptr, language, std::string());
952
953
0
    std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
954
0
    printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
955
0
  } else if (mode == "LINK"_s) {
956
0
    char const* targetName = "dummy";
957
0
    std::vector<std::string> srcs;
958
0
    cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
959
0
    tgt->SetProperty("LINKER_LANGUAGE", language);
960
961
0
    std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
962
0
    cmList libList{ libs };
963
0
    for (std::string const& lib : libList) {
964
0
      tgt->AddLinkLibrary(*mf, lib, GENERAL_LibraryType);
965
0
    }
966
967
0
    std::string buildType = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
968
0
    buildType = cmSystemTools::UpperCase(buildType);
969
970
0
    std::string linkLibs;
971
0
    std::string frameworkPath;
972
0
    std::string linkPath;
973
0
    std::string flags;
974
0
    std::string linkFlags;
975
0
    this->GlobalGenerator->CreateGenerationObjects();
976
0
    cmGeneratorTarget* gtgt =
977
0
      this->GlobalGenerator->FindGeneratorTarget(tgt->GetName());
978
0
    cmLocalGenerator* lg = gtgt->GetLocalGenerator();
979
0
    cmLinkLineComputer linkLineComputer(lg,
980
0
                                        lg->GetStateSnapshot().GetDirectory());
981
0
    lg->GetTargetFlags(&linkLineComputer, buildType, linkLibs, flags,
982
0
                       linkFlags, frameworkPath, linkPath, gtgt);
983
0
    linkLibs = cmStrCat(frameworkPath, linkPath, std::move(linkLibs));
984
985
0
    printf("%s\n", linkLibs.c_str());
986
987
    /*    if ( use_win32 )
988
          {
989
          tgt->SetProperty("WIN32_EXECUTABLE", "ON");
990
          }
991
        if ( use_macbundle)
992
          {
993
          tgt->SetProperty("MACOSX_BUNDLE", "ON");
994
          }*/
995
0
  }
996
997
0
  return packageFound;
998
0
}
999
1000
void cmake::LoadEnvironmentPresets()
1001
19.8k
{
1002
19.8k
  std::string envGenVar;
1003
19.8k
  bool hasEnvironmentGenerator = false;
1004
19.8k
  if (cmSystemTools::GetEnv("CMAKE_GENERATOR", envGenVar)) {
1005
0
    hasEnvironmentGenerator = true;
1006
0
    this->EnvironmentGenerator = envGenVar;
1007
0
  }
1008
1009
59.6k
  auto readGeneratorVar = [&](std::string const& name, std::string& key) {
1010
59.6k
    std::string varValue;
1011
59.6k
    if (cmSystemTools::GetEnv(name, varValue)) {
1012
0
      if (hasEnvironmentGenerator) {
1013
0
        key = varValue;
1014
0
      } else if (!this->GetIsInTryCompile()) {
1015
0
        std::string message =
1016
0
          cmStrCat("Warning: Environment variable ", name,
1017
0
                   " will be ignored, because CMAKE_GENERATOR is not set.");
1018
0
        cmSystemTools::Message(message, "Warning");
1019
0
      }
1020
0
    }
1021
59.6k
  };
1022
1023
19.8k
  readGeneratorVar("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance);
1024
19.8k
  readGeneratorVar("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform);
1025
19.8k
  readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
1026
19.8k
  this->IntermediateDirStrategy =
1027
19.8k
    cmSystemTools::GetEnvVar("CMAKE_INTERMEDIATE_DIR_STRATEGY");
1028
19.8k
  this->AutogenIntermediateDirStrategy =
1029
19.8k
    cmSystemTools::GetEnvVar("CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY");
1030
19.8k
}
1031
1032
// Parse the args
1033
void cmake::SetArgs(std::vector<std::string> const& args)
1034
35
{
1035
35
  this->cmdArgs = args;
1036
35
  bool haveToolset = false;
1037
35
  bool havePlatform = false;
1038
35
  bool haveBArg = false;
1039
35
  bool haveCMLName = false;
1040
35
  std::string possibleUnknownArg;
1041
35
  std::string extraProvidedPath;
1042
35
#if !defined(CMAKE_BOOTSTRAP)
1043
35
  std::string profilingFormat;
1044
35
  std::string profilingOutput;
1045
1046
35
  cmCMakePresetsConfigureArgs presetsArgs;
1047
35
  using ListPresets = cmCMakePresetsConfigureArgs::ListPresetsOption;
1048
35
#endif
1049
1050
35
  auto EmptyStringArgLambda = [](std::string const&, cmake* state) -> bool {
1051
0
    state->IssueMessage(
1052
0
      MessageType::WARNING,
1053
0
      "Ignoring empty string (\"\") provided on the command line.");
1054
0
    return true;
1055
0
  };
1056
1057
35
  auto SourceArgLambda = [](std::string const& value, cmake* state) -> bool {
1058
0
    if (value.empty()) {
1059
0
      cmSystemTools::Error("No source directory specified for -S");
1060
0
      return false;
1061
0
    }
1062
0
    state->SetHomeDirectoryViaCommandLine(
1063
0
      cmSystemTools::ToNormalizedPathOnDisk(value));
1064
0
    return true;
1065
0
  };
1066
1067
35
  auto BuildArgLambda = [&](std::string const& value, cmake* state) -> bool {
1068
0
    if (value.empty()) {
1069
0
      cmSystemTools::Error("No build directory specified for -B");
1070
0
      return false;
1071
0
    }
1072
0
    state->SetHomeOutputDirectory(
1073
0
      cmSystemTools::ToNormalizedPathOnDisk(value));
1074
0
    haveBArg = true;
1075
0
    return true;
1076
0
  };
1077
1078
35
  auto PlatformLambda = [&](std::string const& value, cmake* state) -> bool {
1079
0
    if (havePlatform) {
1080
0
      cmSystemTools::Error("Multiple -A options not allowed");
1081
0
      return false;
1082
0
    }
1083
0
    state->SetGeneratorPlatform(value);
1084
0
    havePlatform = true;
1085
0
    return true;
1086
0
  };
1087
1088
35
  auto ToolsetLambda = [&](std::string const& value, cmake* state) -> bool {
1089
0
    if (haveToolset) {
1090
0
      cmSystemTools::Error("Multiple -T options not allowed");
1091
0
      return false;
1092
0
    }
1093
0
    state->SetGeneratorToolset(value);
1094
0
    haveToolset = true;
1095
0
    return true;
1096
0
  };
1097
1098
35
  auto CMakeListsFileLambda = [&](std::string const& value,
1099
35
                                  cmake* state) -> bool {
1100
0
    if (haveCMLName) {
1101
0
      cmSystemTools::Error("Multiple --project-file options not allowed");
1102
0
      return false;
1103
0
    }
1104
0
    state->SetCMakeListName(value);
1105
0
    haveCMLName = true;
1106
0
    return true;
1107
0
  };
1108
1109
35
  std::vector<CommandArgument> arguments = {
1110
35
    CommandArgument{ "", CommandArgument::Values::Zero, EmptyStringArgLambda },
1111
35
    CommandArgument{ "-S", "No source directory specified for -S",
1112
35
                     CommandArgument::Values::One,
1113
35
                     CommandArgument::RequiresSeparator::No, SourceArgLambda },
1114
35
    CommandArgument{ "-H", "No source directory specified for -H",
1115
35
                     CommandArgument::Values::One,
1116
35
                     CommandArgument::RequiresSeparator::No,
1117
35
                     [&](std::string const& value, cmake* state) -> bool {
1118
0
                       warnDeprecated("-H", "-S");
1119
0
                       return SourceArgLambda(value, state);
1120
0
                     } },
1121
35
    CommandArgument{ "-O", CommandArgument::Values::Zero,
1122
35
                     IgnoreAndTrueLambda },
1123
35
    CommandArgument{ "-B", "No build directory specified for -B",
1124
35
                     CommandArgument::Values::One,
1125
35
                     CommandArgument::RequiresSeparator::No, BuildArgLambda },
1126
35
    CommandArgument{ "--fresh", CommandArgument::Values::Zero,
1127
35
                     [](std::string const&, cmake* cm) -> bool {
1128
0
                       cm->FreshCache = true;
1129
0
                       return true;
1130
0
                     } },
1131
35
    CommandArgument{ "-P", "-P must be followed by a file name.",
1132
35
                     CommandArgument::Values::One,
1133
35
                     CommandArgument::RequiresSeparator::No,
1134
35
                     IgnoreAndTrueLambda },
1135
35
    CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
1136
35
                     CommandArgument::Values::One,
1137
35
                     CommandArgument::RequiresSeparator::No,
1138
35
                     IgnoreAndTrueLambda },
1139
35
    CommandArgument{ "-C", "-C must be followed by a file name.",
1140
35
                     CommandArgument::Values::One,
1141
35
                     CommandArgument::RequiresSeparator::No,
1142
35
                     IgnoreAndTrueLambda },
1143
35
    CommandArgument{
1144
35
      "-U", "-U must be followed with VAR.", CommandArgument::Values::One,
1145
35
      CommandArgument::RequiresSeparator::No, IgnoreAndTrueLambda },
1146
35
    CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
1147
35
                     CommandArgument::Values::One,
1148
35
                     CommandArgument::RequiresSeparator::No,
1149
35
                     IgnoreAndTrueLambda },
1150
35
    CommandArgument{ "-A", "No platform specified for -A",
1151
35
                     CommandArgument::Values::One,
1152
35
                     CommandArgument::RequiresSeparator::No, PlatformLambda },
1153
35
    CommandArgument{ "-T", "No toolset specified for -T",
1154
35
                     CommandArgument::Values::One,
1155
35
                     CommandArgument::RequiresSeparator::No, ToolsetLambda },
1156
35
    CommandArgument{ "--toolchain", "No file specified for --toolchain",
1157
35
                     CommandArgument::Values::One, IgnoreAndTrueLambda },
1158
35
    CommandArgument{ "--install-prefix",
1159
35
                     "No install directory specified for --install-prefix",
1160
35
                     CommandArgument::Values::One, IgnoreAndTrueLambda },
1161
1162
35
    CommandArgument{ "--check-build-system", CommandArgument::Values::Two,
1163
35
                     [](std::string const& value, cmake* state) -> bool {
1164
0
                       cmList values{ value };
1165
0
                       state->CheckBuildSystemArgument = values[0];
1166
0
                       state->ClearBuildSystem = (atoi(values[1].c_str()) > 0);
1167
0
                       return true;
1168
0
                     } },
1169
35
    CommandArgument{ "--check-stamp-file", CommandArgument::Values::One,
1170
35
                     [](std::string const& value, cmake* state) -> bool {
1171
0
                       state->CheckStampFile = value;
1172
0
                       return true;
1173
0
                     } },
1174
35
    CommandArgument{ "--check-stamp-list", CommandArgument::Values::One,
1175
35
                     [](std::string const& value, cmake* state) -> bool {
1176
0
                       state->CheckStampList = value;
1177
0
                       return true;
1178
0
                     } },
1179
35
    CommandArgument{ "--regenerate-during-build",
1180
35
                     CommandArgument::Values::Zero,
1181
35
                     [](std::string const&, cmake* state) -> bool {
1182
0
                       state->RegenerateDuringBuild = true;
1183
0
                       return true;
1184
0
                     } },
1185
1186
35
    CommandArgument{ "--find-package", CommandArgument::Values::Zero,
1187
35
                     IgnoreAndTrueLambda },
1188
1189
35
    CommandArgument{ "--graphviz", "No file specified for --graphviz",
1190
35
                     CommandArgument::Values::One,
1191
35
                     [](std::string const& value, cmake* state) -> bool {
1192
0
                       state->SetGraphVizFile(
1193
0
                         cmSystemTools::ToNormalizedPathOnDisk(value));
1194
0
                       return true;
1195
0
                     } },
1196
1197
35
    CommandArgument{ "--debug-trycompile", CommandArgument::Values::Zero,
1198
35
                     [](std::string const&, cmake* state) -> bool {
1199
0
                       std::cout << "debug trycompile on\n";
1200
0
                       state->DebugTryCompileOn();
1201
0
                       return true;
1202
0
                     } },
1203
35
    CommandArgument{ "--debug-output", CommandArgument::Values::Zero,
1204
35
                     [](std::string const&, cmake* state) -> bool {
1205
0
                       std::cout << "Running with debug output on.\n";
1206
0
                       state->SetDebugOutputOn(true);
1207
0
                       return true;
1208
0
                     } },
1209
1210
35
    CommandArgument{ "--log-level", "Invalid level specified for --log-level",
1211
35
                     CommandArgument::Values::One,
1212
35
                     [](std::string const& value, cmake* state) -> bool {
1213
0
                       auto const logLevel = StringToLogLevel(value);
1214
0
                       if (logLevel == Message::LogLevel::LOG_UNDEFINED) {
1215
0
                         cmSystemTools::Error(
1216
0
                           "Invalid level specified for --log-level");
1217
0
                         return false;
1218
0
                       }
1219
0
                       state->SetLogLevel(logLevel);
1220
0
                       state->LogLevelWasSetViaCLI = true;
1221
0
                       return true;
1222
0
                     } },
1223
    // This is supported for backward compatibility. This option only
1224
    // appeared in the 3.15.x release series and was renamed to
1225
    // --log-level in 3.16.0
1226
35
    CommandArgument{ "--loglevel", "Invalid level specified for --loglevel",
1227
35
                     CommandArgument::Values::One,
1228
35
                     [](std::string const& value, cmake* state) -> bool {
1229
0
                       auto const logLevel = StringToLogLevel(value);
1230
0
                       if (logLevel == Message::LogLevel::LOG_UNDEFINED) {
1231
0
                         cmSystemTools::Error(
1232
0
                           "Invalid level specified for --loglevel");
1233
0
                         return false;
1234
0
                       }
1235
0
                       state->SetLogLevel(logLevel);
1236
0
                       state->LogLevelWasSetViaCLI = true;
1237
0
                       return true;
1238
0
                     } },
1239
1240
35
    CommandArgument{ "--log-context", CommandArgument::Values::Zero,
1241
35
                     [](std::string const&, cmake* state) -> bool {
1242
0
                       state->SetShowLogContext(true);
1243
0
                       return true;
1244
0
                     } },
1245
35
    CommandArgument{ "--project-file",
1246
35
                     "No filename specified for --project-file",
1247
35
                     CommandArgument::Values::One, CMakeListsFileLambda },
1248
35
    CommandArgument{
1249
35
      "--debug-find", CommandArgument::Values::Zero,
1250
35
      [](std::string const&, cmake* state) -> bool {
1251
0
        std::cout << "Running with debug output on for the `find` commands.\n";
1252
0
        state->SetDebugFindOutput(true);
1253
0
        return true;
1254
0
      } },
1255
35
    CommandArgument{
1256
35
      "--debug-find-pkg", "Provide a package argument for --debug-find-pkg",
1257
35
      CommandArgument::Values::One, CommandArgument::RequiresSeparator::Yes,
1258
35
      [](std::string const& value, cmake* state) -> bool {
1259
0
        std::vector<std::string> find_pkgs(cmTokenize(value, ','));
1260
0
        std::cout << "Running with debug output on for the 'find' commands "
1261
0
                     "for package(s)";
1262
0
        for (auto const& v : find_pkgs) {
1263
0
          std::cout << ' ' << v;
1264
0
          state->SetDebugFindOutputPkgs(v);
1265
0
        }
1266
0
        std::cout << ".\n";
1267
0
        return true;
1268
0
      } },
1269
35
    CommandArgument{
1270
35
      "--debug-find-var", CommandArgument::Values::One,
1271
35
      CommandArgument::RequiresSeparator::Yes,
1272
35
      [](std::string const& value, cmake* state) -> bool {
1273
0
        std::vector<std::string> find_vars(cmTokenize(value, ','));
1274
0
        std::cout << "Running with debug output on for the variable(s)";
1275
0
        for (auto const& v : find_vars) {
1276
0
          std::cout << ' ' << v;
1277
0
          state->SetDebugFindOutputVars(v);
1278
0
        }
1279
0
        std::cout << ".\n";
1280
0
        return true;
1281
0
      } },
1282
35
    CommandArgument{ "--trace", CommandArgument::Values::Zero,
1283
35
                     [](std::string const&, cmake* state) -> bool {
1284
0
                       std::cout << "Put cmake in trace mode.\n";
1285
0
                       state->SetTrace(true);
1286
0
                       state->SetTraceExpand(false);
1287
0
                       return true;
1288
0
                     } },
1289
35
    CommandArgument{ "--trace-expand", CommandArgument::Values::Zero,
1290
35
                     [](std::string const&, cmake* state) -> bool {
1291
0
                       std::cout << "Put cmake in trace mode, but with "
1292
0
                                    "variables expanded.\n";
1293
0
                       state->SetTrace(true);
1294
0
                       state->SetTraceExpand(true);
1295
0
                       return true;
1296
0
                     } },
1297
35
    CommandArgument{
1298
35
      "--trace-format", "Invalid format specified for --trace-format",
1299
35
      CommandArgument::Values::One,
1300
35
      [](std::string const& value, cmake* state) -> bool {
1301
0
        std::cout << "Put cmake in trace mode and sets the "
1302
0
                     "trace output format.\n";
1303
0
        state->SetTrace(true);
1304
0
        auto const traceFormat = StringToTraceFormat(value);
1305
0
        if (traceFormat == TraceFormat::Undefined) {
1306
0
          cmSystemTools::Error("Invalid format specified for --trace-format. "
1307
0
                               "Valid formats are human, json-v1.");
1308
0
          return false;
1309
0
        }
1310
0
        state->SetTraceFormat(traceFormat);
1311
0
        return true;
1312
0
      } },
1313
35
    CommandArgument{ "--trace-source", "No file specified for --trace-source",
1314
35
                     CommandArgument::Values::OneOrMore,
1315
35
                     [](std::string const& values, cmake* state) -> bool {
1316
0
                       std::cout << "Put cmake in trace mode, but output only "
1317
0
                                    "lines of a specified file. Multiple "
1318
0
                                    "options are allowed.\n";
1319
0
                       for (auto file :
1320
0
                            cmSystemTools::SplitString(values, ';')) {
1321
0
                         cmSystemTools::ConvertToUnixSlashes(file);
1322
0
                         state->AddTraceSource(file);
1323
0
                       }
1324
0
                       state->SetTrace(true);
1325
0
                       return true;
1326
0
                     } },
1327
35
    CommandArgument{ "--trace-redirect",
1328
35
                     "No file specified for --trace-redirect",
1329
35
                     CommandArgument::Values::One,
1330
35
                     [](std::string const& value, cmake* state) -> bool {
1331
0
                       std::cout
1332
0
                         << "Put cmake in trace mode and redirect trace "
1333
0
                            "output to a file instead of stderr.\n";
1334
0
                       std::string file(value);
1335
0
                       cmSystemTools::ConvertToUnixSlashes(file);
1336
0
                       state->SetTraceFile(file);
1337
0
                       state->SetTrace(true);
1338
0
                       return true;
1339
0
                     } },
1340
35
    CommandArgument{
1341
35
      "--warn-uninitialized", CommandArgument::Values::Zero,
1342
35
      [](std::string const&, cmake* state) -> bool {
1343
0
        warnDeprecated("--warn-uninitialized"_s, "-Wuninitialized"_s);
1344
0
        state->AlterDiagnostic(&cmStateSnapshot::PromoteDiagnostic,
1345
0
                               cmDiagnostics::CMD_UNINITIALIZED,
1346
0
                               cmDiagnostics::Warn, true);
1347
0
        return true;
1348
0
      } },
1349
35
    CommandArgument{ "--warn-unused-vars", CommandArgument::Values::Zero,
1350
35
                     IgnoreAndTrueLambda }, // Option was removed.
1351
35
    CommandArgument{
1352
35
      "--no-warn-unused-cli", CommandArgument::Values::Zero,
1353
35
      [](std::string const&, cmake* state) -> bool {
1354
0
        warnDeprecated("--no-warn-unused-cli"_s, "-Wno-unused-cli"_s);
1355
0
        state->AlterDiagnostic(&cmStateSnapshot::DemoteDiagnostic,
1356
0
                               cmDiagnostics::CMD_UNUSED_CLI,
1357
0
                               cmDiagnostics::Ignore, true);
1358
0
        return true;
1359
0
      } },
1360
35
    CommandArgument{
1361
35
      "--check-system-vars", CommandArgument::Values::Zero,
1362
35
      [](std::string const&, cmake* state) -> bool {
1363
0
        std::cout << "Also check system files when warning about unused and "
1364
0
                     "uninitialized variables.\n";
1365
0
        state->SetCheckSystemVars(true);
1366
0
        return true;
1367
0
      } },
1368
35
    CommandArgument{
1369
35
      "--compile-no-warning-as-error", CommandArgument::Values::Zero,
1370
35
      [](std::string const&, cmake* state) -> bool {
1371
0
        std::cout << "Ignoring COMPILE_WARNING_AS_ERROR target property and "
1372
0
                     "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n";
1373
0
        state->SetIgnoreCompileWarningAsError(true);
1374
0
        return true;
1375
0
      } },
1376
35
    CommandArgument{
1377
35
      "--link-no-warning-as-error", CommandArgument::Values::Zero,
1378
35
      [](std::string const&, cmake* state) -> bool {
1379
0
        std::cout << "Ignoring LINK_WARNING_AS_ERROR target property and "
1380
0
                     "CMAKE_LINK_WARNING_AS_ERROR variable.\n";
1381
0
        state->SetIgnoreLinkWarningAsError(true);
1382
0
        return true;
1383
0
      } },
1384
35
    CommandArgument{ "--debugger", CommandArgument::Values::Zero,
1385
35
                     [](std::string const&, cmake* state) -> bool {
1386
0
#ifdef CMake_ENABLE_DEBUGGER
1387
0
                       std::cout << "Running with debugger on.\n";
1388
0
                       state->SetDebuggerOn(true);
1389
0
                       return true;
1390
#else
1391
                       static_cast<void>(state);
1392
                       cmSystemTools::Error(
1393
                         "CMake was not built with support for --debugger");
1394
                       return false;
1395
#endif
1396
0
                     } },
1397
35
    CommandArgument{ "--debugger-pipe",
1398
35
                     "No path specified for --debugger-pipe",
1399
35
                     CommandArgument::Values::One,
1400
35
                     [](std::string const& value, cmake* state) -> bool {
1401
0
#ifdef CMake_ENABLE_DEBUGGER
1402
0
                       state->DebuggerPipe = value;
1403
0
                       return true;
1404
#else
1405
                       static_cast<void>(value);
1406
                       static_cast<void>(state);
1407
                       cmSystemTools::Error("CMake was not built with support "
1408
                                            "for --debugger-pipe");
1409
                       return false;
1410
#endif
1411
0
                     } },
1412
35
    CommandArgument{ "--debugger-dap-log",
1413
35
                     "No file specified for --debugger-dap-log",
1414
35
                     CommandArgument::Values::One,
1415
35
                     [](std::string const& value, cmake* state) -> bool {
1416
0
#ifdef CMake_ENABLE_DEBUGGER
1417
0
                       state->DebuggerDapLogFile =
1418
0
                         cmSystemTools::ToNormalizedPathOnDisk(value);
1419
0
                       return true;
1420
#else
1421
                       static_cast<void>(value);
1422
                       static_cast<void>(state);
1423
                       cmSystemTools::Error("CMake was not built with support "
1424
                                            "for --debugger-dap-log");
1425
                       return false;
1426
#endif
1427
0
                     } },
1428
35
  };
1429
1430
#if defined(CMAKE_HAVE_VS_GENERATORS)
1431
  arguments.emplace_back("--vs-solution-file", CommandArgument::Values::One,
1432
                         [](std::string const& value, cmake* state) -> bool {
1433
                           state->VSSolutionFile = value;
1434
                           return true;
1435
                         });
1436
#endif
1437
1438
35
#if !defined(CMAKE_BOOTSTRAP)
1439
35
  arguments.emplace_back("--profiling-format",
1440
35
                         "No format specified for --profiling-format",
1441
35
                         CommandArgument::Values::One,
1442
35
                         [&](std::string const& value, cmake*) -> bool {
1443
0
                           profilingFormat = value;
1444
0
                           return true;
1445
0
                         });
1446
35
  arguments.emplace_back(
1447
35
    "--profiling-output", "No path specified for --profiling-output",
1448
35
    CommandArgument::Values::One,
1449
35
    [&profilingOutput](std::string const& value, cmake*) -> bool {
1450
0
      profilingOutput = cmSystemTools::ToNormalizedPathOnDisk(value);
1451
0
      return true;
1452
0
    });
1453
35
  arguments.emplace_back("--preset", "No preset specified for --preset",
1454
35
                         CommandArgument::Values::One,
1455
35
                         [&](std::string const& value, cmake*) -> bool {
1456
0
                           presetsArgs.PresetName = value;
1457
0
                           return true;
1458
0
                         });
1459
35
  arguments.emplace_back(
1460
35
    "--presets-file", "No file specified for --presets-file",
1461
35
    CommandArgument::Values::One,
1462
35
    [&presetsArgs](std::string const& value, cmake*) -> bool {
1463
0
      presetsArgs.PresetsFile = cmSystemTools::ToNormalizedPathOnDisk(value);
1464
0
      return true;
1465
0
    });
1466
35
  arguments.emplace_back(
1467
35
    "--list-presets", CommandArgument::Values::ZeroOrOne,
1468
35
    [&](std::string const& value, cmake*) -> bool {
1469
0
      std::string type = value;
1470
0
      auto const mode = presetsArgs.ParseListPresetsMode(type);
1471
1472
0
      if (type.empty() || type == "configure") {
1473
0
        presetsArgs.ListPresets = ListPresets::Configure;
1474
0
      } else if (type == "build") {
1475
0
        presetsArgs.ListPresets = ListPresets::Build;
1476
0
      } else if (type == "test") {
1477
0
        presetsArgs.ListPresets = ListPresets::Test;
1478
0
      } else if (type == "package") {
1479
0
        presetsArgs.ListPresets = ListPresets::Package;
1480
0
      } else if (type == "workflow") {
1481
0
        presetsArgs.ListPresets = ListPresets::Workflow;
1482
0
      } else if (type == "all") {
1483
0
        presetsArgs.ListPresets = ListPresets::All;
1484
0
      } else {
1485
0
        cmSystemTools::Error(
1486
0
          "Invalid value specified for --list-presets.\n"
1487
0
          "Valid values are configure, build, test, package, workflow, all, "
1488
0
          "defined, or any of the type values suffixed with -defined. When "
1489
0
          "no value is passed the default is configure.");
1490
0
        return false;
1491
0
      }
1492
1493
0
      presetsArgs.ListPresetsMode = mode;
1494
0
      return true;
1495
0
    });
1496
1497
35
#endif
1498
1499
35
  bool badGeneratorName = false;
1500
35
  CommandArgument generatorCommand(
1501
35
    "-G", "No generator specified for -G", CommandArgument::Values::One,
1502
35
    CommandArgument::RequiresSeparator::No,
1503
35
    [&](std::string const& value, cmake* state) -> bool {
1504
0
      bool valid = state->CreateAndSetGlobalGenerator(value);
1505
0
      badGeneratorName = !valid;
1506
0
      return valid;
1507
0
    });
1508
1509
70
  for (decltype(args.size()) i = 1; i < args.size(); ++i) {
1510
    // iterate each argument
1511
35
    std::string const& arg = args[i];
1512
1513
35
    if (this->State->GetRole() == cmState::Role::Script && arg == "--") {
1514
      // Stop processing CMake args and avoid possible errors
1515
      // when arbitrary args are given to CMake script.
1516
0
      break;
1517
0
    }
1518
1519
    // Generator flag has special handling for when to print help
1520
    // so it becomes the exception
1521
35
    if (generatorCommand.matches(arg)) {
1522
0
      bool parsed = generatorCommand.parse(arg, i, args, this);
1523
0
      if (!parsed && !badGeneratorName) {
1524
0
        this->PrintGeneratorList();
1525
0
        return;
1526
0
      }
1527
0
      continue;
1528
0
    }
1529
1530
35
    bool matched = false;
1531
35
    bool parsedCorrectly = true; // needs to be true so we can ignore
1532
                                 // arguments so as -E
1533
245
    for (auto const& m : arguments) {
1534
245
      if (m.matches(arg)) {
1535
35
        matched = true;
1536
35
        parsedCorrectly = m.parse(arg, i, args, this);
1537
35
        break;
1538
35
      }
1539
245
    }
1540
1541
    // We have an issue where arguments to a "-P" script mode
1542
    // can be provided before the "-P" argument. This means
1543
    // that we need to lazily check this argument after checking
1544
    // all args.
1545
    // Additionally it can't be the source/binary tree location
1546
35
    if (!parsedCorrectly) {
1547
0
      cmSystemTools::Error("Run 'cmake --help' for all supported options.");
1548
0
      exit(1);
1549
35
    } else if (!matched && cmHasPrefix(arg, '-')) {
1550
0
      possibleUnknownArg = arg;
1551
35
    } else if (!matched) {
1552
0
      bool parsedDirectory = this->SetDirectoriesFromFile(arg);
1553
0
      if (!parsedDirectory) {
1554
0
        extraProvidedPath = arg;
1555
0
      }
1556
0
    }
1557
35
  }
1558
1559
35
  if (!extraProvidedPath.empty() &&
1560
0
      this->State->GetRole() == cmState::Role::Project) {
1561
0
    this->IssueMessage(MessageType::WARNING,
1562
0
                       cmStrCat("Ignoring extra path from command line:\n \"",
1563
0
                                extraProvidedPath, '"'));
1564
0
  }
1565
35
  if (!possibleUnknownArg.empty() &&
1566
0
      this->State->GetRole() != cmState::Role::Script) {
1567
0
    std::string error = cmStrCat("Unknown argument ", possibleUnknownArg);
1568
0
    std::string const suggestion =
1569
0
      findClosestOption(possibleUnknownArg, arguments);
1570
0
    if (!suggestion.empty()) {
1571
0
      error = cmStrCat(std::move(error), ". Did you mean: ", suggestion, '?');
1572
0
    }
1573
0
    cmSystemTools::Error(error);
1574
0
    cmSystemTools::Error("Run 'cmake --help' for all supported options.");
1575
0
    exit(1);
1576
0
  }
1577
1578
  // Empty instance, platform and toolset if only a generator is specified
1579
35
  if (this->GlobalGenerator) {
1580
0
    this->GeneratorInstance = "";
1581
0
    if (!this->GeneratorPlatformSet) {
1582
0
      this->GeneratorPlatform = "";
1583
0
    }
1584
0
    if (!this->GeneratorToolsetSet) {
1585
0
      this->GeneratorToolset = "";
1586
0
    }
1587
0
  }
1588
1589
35
#if !defined(CMAKE_BOOTSTRAP)
1590
35
  if (!profilingOutput.empty() || !profilingFormat.empty()) {
1591
0
    if (profilingOutput.empty()) {
1592
0
      cmSystemTools::Error(
1593
0
        "--profiling-format specified but no --profiling-output!");
1594
0
      return;
1595
0
    }
1596
0
    if (profilingFormat == "google-trace"_s) {
1597
0
      try {
1598
0
        this->ProfilingOutput =
1599
0
          cm::make_unique<cmMakefileProfilingData>(profilingOutput);
1600
0
      } catch (std::runtime_error& e) {
1601
0
        cmSystemTools::Error(
1602
0
          cmStrCat("Could not start profiling: ", e.what()));
1603
0
        return;
1604
0
      }
1605
0
    } else {
1606
0
      cmSystemTools::Error("Invalid format specified for --profiling-format");
1607
0
      return;
1608
0
    }
1609
0
  }
1610
35
#endif
1611
1612
35
  bool const haveSourceDir = !this->GetHomeDirectory().empty();
1613
35
  bool const haveBinaryDir = !this->GetHomeOutputDirectory().empty();
1614
35
  bool const havePreset =
1615
#ifdef CMAKE_BOOTSTRAP
1616
    false;
1617
#else
1618
35
    !presetsArgs.PresetName.empty();
1619
35
#endif
1620
1621
35
  if (this->State->GetRole() == cmState::Role::Project && !haveSourceDir &&
1622
0
      !haveBinaryDir && !havePreset) {
1623
0
    this->IssueMessage(
1624
0
      MessageType::WARNING,
1625
0
      "No source or binary directory provided. Both will be assumed to be "
1626
0
      "the same as the current working directory, but note that this "
1627
0
      "warning will become a fatal error in future CMake releases.");
1628
0
  }
1629
1630
35
  if (!haveSourceDir) {
1631
0
    this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
1632
0
  }
1633
35
  if (!haveBinaryDir) {
1634
0
    this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
1635
0
  }
1636
1637
35
  if (this->State->GetRole() == cmState::Role::Script && havePreset) {
1638
0
    this->IssueMessage(MessageType::FATAL_ERROR,
1639
0
                       "Presets are not supported in CMake script mode.");
1640
0
  }
1641
1642
35
#if !defined(CMAKE_BOOTSTRAP)
1643
35
  if (presetsArgs.HasPresetsArg()) {
1644
0
    this->SetArgsFromPreset(presetsArgs, haveBArg);
1645
0
  }
1646
35
#endif
1647
35
}
1648
1649
namespace {
1650
using LevelsPair = std::pair<cm::string_view, Message::LogLevel>;
1651
using LevelsPairArray = std::array<LevelsPair, 7>;
1652
LevelsPairArray const& getStringToLogLevelPairs()
1653
0
{
1654
0
  static LevelsPairArray const levels = {
1655
0
    { { "error", Message::LogLevel::LOG_ERROR },
1656
0
      { "warning", Message::LogLevel::LOG_WARNING },
1657
0
      { "notice", Message::LogLevel::LOG_NOTICE },
1658
0
      { "status", Message::LogLevel::LOG_STATUS },
1659
0
      { "verbose", Message::LogLevel::LOG_VERBOSE },
1660
0
      { "debug", Message::LogLevel::LOG_DEBUG },
1661
0
      { "trace", Message::LogLevel::LOG_TRACE } }
1662
0
  };
1663
0
  return levels;
1664
0
}
1665
} // namespace
1666
1667
Message::LogLevel cmake::StringToLogLevel(cm::string_view levelStr)
1668
0
{
1669
0
  LevelsPairArray const& levels = getStringToLogLevelPairs();
1670
1671
0
  auto const levelStrLowCase =
1672
0
    cmSystemTools::LowerCase(std::string{ levelStr });
1673
1674
  // NOLINTNEXTLINE(readability-qualified-auto)
1675
0
  auto const it = std::find_if(levels.cbegin(), levels.cend(),
1676
0
                               [&levelStrLowCase](LevelsPair const& p) {
1677
0
                                 return p.first == levelStrLowCase;
1678
0
                               });
1679
0
  return (it != levels.cend()) ? it->second : Message::LogLevel::LOG_UNDEFINED;
1680
0
}
1681
1682
std::string cmake::LogLevelToString(Message::LogLevel level)
1683
0
{
1684
0
  LevelsPairArray const& levels = getStringToLogLevelPairs();
1685
1686
  // NOLINTNEXTLINE(readability-qualified-auto)
1687
0
  auto const it =
1688
0
    std::find_if(levels.cbegin(), levels.cend(),
1689
0
                 [&level](LevelsPair const& p) { return p.second == level; });
1690
0
  cm::string_view const levelStrLowerCase =
1691
0
    (it != levels.cend()) ? it->first : "undefined";
1692
0
  std::string levelStrUpperCase =
1693
0
    cmSystemTools::UpperCase(std::string{ levelStrLowerCase });
1694
0
  return levelStrUpperCase;
1695
0
}
1696
1697
cmake::TraceFormat cmake::StringToTraceFormat(std::string const& traceStr)
1698
0
{
1699
0
  using TracePair = std::pair<std::string, TraceFormat>;
1700
0
  static std::vector<TracePair> const levels = {
1701
0
    { "human", TraceFormat::Human },
1702
0
    { "json-v1", TraceFormat::JSONv1 },
1703
0
  };
1704
1705
0
  auto const traceStrLowCase = cmSystemTools::LowerCase(traceStr);
1706
1707
0
  auto const it = std::find_if(levels.cbegin(), levels.cend(),
1708
0
                               [&traceStrLowCase](TracePair const& p) {
1709
0
                                 return p.first == traceStrLowCase;
1710
0
                               });
1711
0
  return (it != levels.cend()) ? it->second : TraceFormat::Undefined;
1712
0
}
1713
1714
bool cmake::PopTraceCmd()
1715
0
{
1716
0
  if (this->cmakeLangTraceCmdStack.empty()) {
1717
    // Nothing to pop! A caller should report an error.
1718
0
    return false;
1719
0
  }
1720
0
  this->cmakeLangTraceCmdStack.pop();
1721
0
  return true;
1722
0
}
1723
1724
void cmake::SetTraceFile(std::string const& file)
1725
0
{
1726
0
  this->TraceFile.close();
1727
0
  this->TraceFile.open(file.c_str());
1728
0
  if (!this->TraceFile) {
1729
0
    cmSystemTools::Error(cmStrCat("Error opening trace file ", file, ": ",
1730
0
                                  cmSystemTools::GetLastSystemError()));
1731
0
    return;
1732
0
  }
1733
0
  std::cout << "Trace will be written to " << file << '\n';
1734
0
}
1735
1736
void cmake::PrintTraceFormatVersion()
1737
0
{
1738
0
  if (!this->GetTrace()) {
1739
0
    return;
1740
0
  }
1741
1742
0
  std::string msg;
1743
1744
0
  switch (this->GetTraceFormat()) {
1745
0
    case TraceFormat::JSONv1: {
1746
0
#ifndef CMAKE_BOOTSTRAP
1747
0
      Json::Value val;
1748
0
      Json::Value version;
1749
0
      Json::StreamWriterBuilder builder;
1750
0
      builder["indentation"] = "";
1751
0
      version["major"] = 1;
1752
0
      version["minor"] = 2;
1753
0
      val["version"] = version;
1754
0
      msg = Json::writeString(builder, val);
1755
0
#endif
1756
0
      break;
1757
0
    }
1758
0
    case TraceFormat::Human:
1759
0
      msg = "";
1760
0
      break;
1761
0
    case TraceFormat::Undefined:
1762
0
      msg = "INTERNAL ERROR: Trace format is Undefined";
1763
0
      break;
1764
0
  }
1765
1766
0
  if (msg.empty()) {
1767
0
    return;
1768
0
  }
1769
1770
0
  auto& f = this->GetTraceFile();
1771
0
  if (f) {
1772
0
    f << msg << '\n';
1773
0
  } else {
1774
0
    cmSystemTools::Message(msg);
1775
0
  }
1776
0
}
1777
1778
void cmake::SetTraceRedirect(cmake* other)
1779
0
{
1780
0
  this->Trace = other->Trace;
1781
0
  this->TraceExpand = other->TraceExpand;
1782
0
  this->TraceFormatVar = other->TraceFormatVar;
1783
0
  this->TraceOnlyThisSources = other->TraceOnlyThisSources;
1784
1785
0
  this->TraceRedirect = other;
1786
0
}
1787
1788
bool cmake::SetDirectoriesFromFile(std::string const& arg)
1789
0
{
1790
  // Check if the argument refers to a CMakeCache.txt or CMakeLists.txt file.
1791
  // Do not check for the custom project filename CMAKE_LIST_FILE_NAME, as it
1792
  // cannot be determined until after reading the CMakeCache.txt
1793
0
  std::string listPath;
1794
0
  std::string cachePath;
1795
0
  bool is_source_dir = false;
1796
0
  bool is_empty_directory = false;
1797
0
  if (cmSystemTools::FileIsDirectory(arg)) {
1798
0
    std::string path = cmSystemTools::ToNormalizedPathOnDisk(arg);
1799
0
    std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
1800
0
    std::string listFile = this->GetCMakeListFile(path);
1801
1802
0
    is_empty_directory = true;
1803
0
    if (cmSystemTools::FileExists(cacheFile)) {
1804
0
      cachePath = path;
1805
0
      is_empty_directory = false;
1806
0
    }
1807
0
    if (cmSystemTools::FileExists(listFile)) {
1808
0
      listPath = path;
1809
0
      is_empty_directory = false;
1810
0
      is_source_dir = true;
1811
0
    }
1812
0
  } else if (cmSystemTools::FileExists(arg)) {
1813
0
    std::string fullPath = cmSystemTools::ToNormalizedPathOnDisk(arg);
1814
0
    std::string name = cmSystemTools::GetFilenameName(fullPath);
1815
0
    name = cmSystemTools::LowerCase(name);
1816
0
    if (name == "cmakecache.txt"_s) {
1817
0
      cachePath = cmSystemTools::GetFilenamePath(fullPath);
1818
0
    } else if (name == "cmakelists.txt"_s) {
1819
0
      listPath = cmSystemTools::GetFilenamePath(fullPath);
1820
0
    }
1821
0
  } else {
1822
    // Specified file or directory does not exist.  Try to set things
1823
    // up to produce a meaningful error message.
1824
0
    std::string fullPath = cmSystemTools::CollapseFullPath(arg);
1825
0
    std::string name = cmSystemTools::GetFilenameName(fullPath);
1826
0
    name = cmSystemTools::LowerCase(name);
1827
0
    if (name == "cmakecache.txt"_s || name == "cmakelists.txt"_s) {
1828
0
      listPath = cmSystemTools::GetFilenamePath(fullPath);
1829
0
    } else {
1830
0
      listPath = fullPath;
1831
0
    }
1832
0
  }
1833
1834
  // If there is a CMakeCache.txt file, use its settings.
1835
0
  if (!cachePath.empty()) {
1836
0
    if (this->LoadCache(cachePath)) {
1837
0
      cmValue existingValue =
1838
0
        this->State->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
1839
0
      if (existingValue && !existingValue.IsEmpty()) {
1840
0
        this->SetHomeOutputDirectory(cachePath);
1841
0
        this->SetHomeDirectory(*existingValue);
1842
0
        return true;
1843
0
      }
1844
0
    }
1845
0
  }
1846
1847
0
  bool no_source_tree = this->GetHomeDirectory().empty();
1848
0
  bool no_build_tree = this->GetHomeOutputDirectory().empty();
1849
1850
  // When invoked with a path that points to an existing CMakeCache
1851
  // This function is called multiple times with the same path
1852
0
  bool const passed_same_path = (listPath == this->GetHomeDirectory()) ||
1853
0
    (listPath == this->GetHomeOutputDirectory());
1854
0
  bool used_provided_path =
1855
0
    (passed_same_path || is_source_dir || no_build_tree);
1856
1857
  // If there is a CMakeLists.txt file, use it as the source tree.
1858
0
  if (!listPath.empty()) {
1859
    // When invoked with a path that points to an existing CMakeCache
1860
    // This function is called multiple times with the same path
1861
0
    if (is_source_dir) {
1862
0
      this->SetHomeDirectoryViaCommandLine(listPath);
1863
0
      if (no_build_tree) {
1864
0
        this->SetHomeOutputDirectory(
1865
0
          cmSystemTools::GetLogicalWorkingDirectory());
1866
0
      }
1867
0
    } else if (no_source_tree && no_build_tree) {
1868
0
      this->SetHomeDirectory(listPath);
1869
0
      this->SetHomeOutputDirectory(
1870
0
        cmSystemTools::GetLogicalWorkingDirectory());
1871
0
    } else if (no_build_tree) {
1872
0
      this->SetHomeOutputDirectory(listPath);
1873
0
    }
1874
0
  } else {
1875
0
    if (no_source_tree) {
1876
      // We didn't find a CMakeLists.txt and it wasn't specified
1877
      // with -S. Assume it is the path to the source tree
1878
0
      this->SetHomeDirectory(cmSystemTools::ToNormalizedPathOnDisk(arg));
1879
0
    }
1880
0
    if (no_build_tree && !no_source_tree && is_empty_directory) {
1881
      // passed `-S <path> <build_dir> when build_dir is an empty directory
1882
0
      this->SetHomeOutputDirectory(cmSystemTools::ToNormalizedPathOnDisk(arg));
1883
0
    } else if (no_build_tree) {
1884
      // We didn't find a CMakeCache.txt and it wasn't specified
1885
      // with -B. Assume the current working directory as the build tree.
1886
0
      this->SetHomeOutputDirectory(
1887
0
        cmSystemTools::GetLogicalWorkingDirectory());
1888
0
      used_provided_path = false;
1889
0
    }
1890
0
  }
1891
1892
0
  return used_provided_path;
1893
0
}
1894
1895
// at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the
1896
// cache
1897
int cmake::AddCMakePaths()
1898
1
{
1899
  // Save the value in the cache
1900
1
  this->AddCacheEntry("CMAKE_COMMAND", cmSystemTools::GetCMakeCommand(),
1901
1
                      "Path to CMake executable.", cmStateEnums::INTERNAL);
1902
1
#ifndef CMAKE_BOOTSTRAP
1903
1
  this->AddCacheEntry("CMAKE_CTEST_COMMAND", cmSystemTools::GetCTestCommand(),
1904
1
                      "Path to ctest program executable.",
1905
1
                      cmStateEnums::INTERNAL);
1906
1
  this->AddCacheEntry("CMAKE_CPACK_COMMAND", cmSystemTools::GetCPackCommand(),
1907
1
                      "Path to cpack program executable.",
1908
1
                      cmStateEnums::INTERNAL);
1909
1
#endif
1910
1
  if (!cmSystemTools::FileExists(
1911
1
        (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake"))) {
1912
    // couldn't find modules
1913
1
    cmSystemTools::Error(
1914
1
      cmStrCat("Could not find CMAKE_ROOT !!!\n"
1915
1
               "CMake has most likely not been installed correctly.\n"
1916
1
               "Modules directory not found in\n",
1917
1
               cmSystemTools::GetCMakeRoot()));
1918
1
    return 0;
1919
1
  }
1920
0
  this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot(),
1921
0
                      "Path to CMake installation.", cmStateEnums::INTERNAL);
1922
1923
0
  return 1;
1924
1
}
1925
1926
void cmake::AddDefaultExtraGenerators()
1927
19.9k
{
1928
19.9k
#if !defined(CMAKE_BOOTSTRAP)
1929
19.9k
  this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::GetFactory());
1930
19.9k
  this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::GetFactory());
1931
19.9k
  this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory());
1932
19.9k
  this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory());
1933
19.9k
  this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory());
1934
19.9k
#endif
1935
19.9k
}
1936
1937
void cmake::GetRegisteredGenerators(
1938
  std::vector<GeneratorInfo>& generators) const
1939
0
{
1940
0
  for (auto const& gen : this->Generators) {
1941
0
    std::vector<std::string> names = gen->GetGeneratorNames();
1942
1943
0
    for (std::string const& name : names) {
1944
0
      GeneratorInfo info;
1945
0
      info.supportsToolset = gen->SupportsToolset();
1946
0
      info.supportsPlatform = gen->SupportsPlatform();
1947
0
      info.supportedPlatforms = gen->GetKnownPlatforms();
1948
0
      info.defaultPlatform = gen->GetDefaultPlatformName();
1949
0
      info.name = name;
1950
0
      info.baseName = name;
1951
0
      info.isAlias = false;
1952
0
      generators.push_back(std::move(info));
1953
0
    }
1954
0
  }
1955
1956
0
  for (cmExternalMakefileProjectGeneratorFactory* eg : this->ExtraGenerators) {
1957
0
    std::vector<std::string> const genList =
1958
0
      eg->GetSupportedGlobalGenerators();
1959
0
    for (std::string const& gen : genList) {
1960
0
      GeneratorInfo info;
1961
0
      info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
1962
0
        gen, eg->GetName());
1963
0
      info.baseName = gen;
1964
0
      info.extraName = eg->GetName();
1965
0
      info.supportsPlatform = false;
1966
0
      info.supportsToolset = false;
1967
0
      info.isAlias = false;
1968
0
      generators.push_back(std::move(info));
1969
0
    }
1970
0
    for (std::string const& a : eg->Aliases) {
1971
0
      GeneratorInfo info;
1972
0
      info.name = a;
1973
0
      if (!genList.empty()) {
1974
0
        info.baseName = genList.at(0);
1975
0
      }
1976
0
      info.extraName = eg->GetName();
1977
0
      info.supportsPlatform = false;
1978
0
      info.supportsToolset = false;
1979
0
      info.isAlias = true;
1980
0
      generators.push_back(std::move(info));
1981
0
    }
1982
0
  }
1983
0
}
1984
1985
static std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>,
1986
                 std::string>
1987
createExtraGenerator(
1988
  std::vector<cmExternalMakefileProjectGeneratorFactory*> const& in,
1989
  std::string const& name)
1990
0
{
1991
0
  for (cmExternalMakefileProjectGeneratorFactory* i : in) {
1992
0
    std::vector<std::string> const generators =
1993
0
      i->GetSupportedGlobalGenerators();
1994
0
    if (i->GetName() == name) { // Match aliases
1995
0
      return { i->CreateExternalMakefileProjectGenerator(), generators.at(0) };
1996
0
    }
1997
0
    for (std::string const& g : generators) {
1998
0
      std::string const fullName =
1999
0
        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
2000
0
          g, i->GetName());
2001
0
      if (fullName == name) {
2002
0
        return { i->CreateExternalMakefileProjectGenerator(), g };
2003
0
      }
2004
0
    }
2005
0
  }
2006
0
  return { nullptr, name };
2007
0
}
2008
2009
std::unique_ptr<cmGlobalGenerator> cmake::CreateGlobalGenerator(
2010
  std::string const& gname)
2011
0
{
2012
0
  std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>, std::string>
2013
0
    extra = createExtraGenerator(this->ExtraGenerators, gname);
2014
0
  std::unique_ptr<cmExternalMakefileProjectGenerator>& extraGenerator =
2015
0
    extra.first;
2016
0
  std::string const& name = extra.second;
2017
2018
0
  std::unique_ptr<cmGlobalGenerator> generator;
2019
0
  for (auto const& g : this->Generators) {
2020
0
    generator = g->CreateGlobalGenerator(name, this);
2021
0
    if (generator) {
2022
0
      break;
2023
0
    }
2024
0
  }
2025
2026
0
  if (generator) {
2027
0
    generator->SetExternalMakefileProjectGenerator(std::move(extraGenerator));
2028
0
  }
2029
2030
0
  return generator;
2031
0
}
2032
2033
bool cmake::CreateAndSetGlobalGenerator(std::string const& name)
2034
0
{
2035
0
  auto gen = this->CreateGlobalGenerator(name);
2036
0
  if (!gen) {
2037
0
    std::string kdevError;
2038
0
    std::string vsError;
2039
0
    if (name.find("KDevelop3", 0) != std::string::npos) {
2040
0
      kdevError = "\nThe KDevelop3 generator is not supported anymore.";
2041
0
    }
2042
0
    if (cmHasLiteralPrefix(name, "Visual Studio ") &&
2043
0
        name.length() >= cmStrLen("Visual Studio xx xxxx ")) {
2044
0
      vsError = "\nUsing platforms in Visual Studio generator names is not "
2045
0
                "supported in CMakePresets.json.";
2046
0
    }
2047
2048
0
    cmSystemTools::Error(
2049
0
      cmStrCat("Could not create named generator ", name, kdevError, vsError));
2050
0
    this->PrintGeneratorList();
2051
0
    return false;
2052
0
  }
2053
2054
0
  this->SetGlobalGenerator(std::move(gen));
2055
0
  return true;
2056
0
}
2057
2058
#ifndef CMAKE_BOOTSTRAP
2059
bool cmake::SetArgsFromPreset(cmCMakePresetsConfigureArgs const& args,
2060
                              bool haveBinaryDirArg)
2061
0
{
2062
0
  using ListPresets = cmCMakePresetsConfigureArgs::ListPresetsOption;
2063
2064
0
  cmCMakePresetsGraph presetsGraph;
2065
0
  auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory(),
2066
0
                                                args.PresetsFile);
2067
0
  if (result != true) {
2068
0
    std::string errorMsg =
2069
0
      cmStrCat("Could not read presets from ", this->GetHomeDirectory(), ":\n",
2070
0
               presetsGraph.parseState.GetErrorMessage());
2071
0
    cmSystemTools::Error(errorMsg);
2072
0
    return false;
2073
0
  }
2074
2075
0
  if (args.ListPresets != ListPresets::None) {
2076
0
    auto configureUsabilityCheck = this->CreateConfigurePresetUsabilityCheck();
2077
0
    switch (args.ListPresets) {
2078
0
      case ListPresets::Configure:
2079
0
        presetsGraph.PrintConfigurePresetList(args.ListPresetsMode,
2080
0
                                              configureUsabilityCheck);
2081
0
        break;
2082
0
      case ListPresets::Build:
2083
0
        presetsGraph.PrintBuildPresetList(args.ListPresetsMode,
2084
0
                                          configureUsabilityCheck);
2085
0
        break;
2086
0
      case ListPresets::Test:
2087
0
        presetsGraph.PrintTestPresetList(args.ListPresetsMode,
2088
0
                                         configureUsabilityCheck);
2089
0
        break;
2090
0
      case ListPresets::Package:
2091
0
        presetsGraph.PrintPackagePresetList(args.ListPresetsMode,
2092
0
                                            configureUsabilityCheck);
2093
0
        break;
2094
0
      case ListPresets::Workflow:
2095
0
        presetsGraph.PrintWorkflowPresetList(args.ListPresetsMode,
2096
0
                                             configureUsabilityCheck);
2097
0
        break;
2098
0
      case ListPresets::All:
2099
0
        presetsGraph.PrintConfigurePresetList(args.ListPresetsMode,
2100
0
                                              configureUsabilityCheck);
2101
0
        presetsGraph.PrintBuildPresetList(args.ListPresetsMode,
2102
0
                                          configureUsabilityCheck);
2103
0
        presetsGraph.PrintTestPresetList(args.ListPresetsMode,
2104
0
                                         configureUsabilityCheck);
2105
0
        presetsGraph.PrintPackagePresetList(args.ListPresetsMode,
2106
0
                                            configureUsabilityCheck);
2107
0
        presetsGraph.PrintWorkflowPresetList(args.ListPresetsMode,
2108
0
                                             configureUsabilityCheck);
2109
0
        break;
2110
0
      default:
2111
0
        break;
2112
0
    }
2113
2114
0
    this->State->SetRoleToHelpForListPresets();
2115
0
    return false;
2116
0
  }
2117
2118
0
  auto resolveResult =
2119
0
    presetsGraph.ResolvePreset(args.PresetName, presetsGraph.ConfigurePresets);
2120
0
  using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
2121
0
  using S = cmCMakePresetsGraph::PresetResolveStatus;
2122
0
  auto resolveError = cmCMakePresetsGraph::FormatPresetError<ConfigurePreset>(
2123
0
    resolveResult.StatusCode, resolveResult.ErrorPresetName,
2124
0
    this->GetHomeDirectory());
2125
0
  if (resolveError) {
2126
0
    cmSystemTools::Error(*resolveError);
2127
0
    if (resolveResult.StatusCode == S::NotFound ||
2128
0
        resolveResult.StatusCode == S::Hidden) {
2129
0
      this->PrintPresetList(presetsGraph);
2130
0
    }
2131
0
    return false;
2132
0
  }
2133
0
  auto const* expandedPreset = resolveResult.Preset;
2134
2135
0
  if (!this->State->IsCacheLoaded() && !haveBinaryDirArg &&
2136
0
      !expandedPreset->BinaryDir.empty()) {
2137
0
    this->SetHomeOutputDirectory(expandedPreset->BinaryDir);
2138
0
  }
2139
0
  if (!this->GlobalGenerator && !expandedPreset->Generator.empty()) {
2140
0
    if (!this->CreateAndSetGlobalGenerator(expandedPreset->Generator)) {
2141
0
      return false;
2142
0
    }
2143
0
  }
2144
0
  this->UnprocessedPresetVariables = expandedPreset->CacheVariables;
2145
0
  this->UnprocessedPresetEnvironment = expandedPreset->Environment;
2146
2147
0
  if (!expandedPreset->InstallDir.empty() &&
2148
0
      !this->State->GetInitializedCacheValue("CMAKE_INSTALL_PREFIX")) {
2149
0
    this->UnprocessedPresetVariables["CMAKE_INSTALL_PREFIX"] = {
2150
0
      "PATH", expandedPreset->InstallDir
2151
0
    };
2152
0
  }
2153
0
  if (!expandedPreset->ToolchainFile.empty() &&
2154
0
      !this->State->GetInitializedCacheValue("CMAKE_TOOLCHAIN_FILE")) {
2155
0
    this->UnprocessedPresetVariables["CMAKE_TOOLCHAIN_FILE"] = {
2156
0
      "FILEPATH", expandedPreset->ToolchainFile
2157
0
    };
2158
0
  }
2159
2160
0
  if (!expandedPreset->ArchitectureStrategy ||
2161
0
      expandedPreset->ArchitectureStrategy ==
2162
0
        cmCMakePresetsGraph::ArchToolsetStrategy::Set) {
2163
0
    if (!this->GeneratorPlatformSet && !expandedPreset->Architecture.empty()) {
2164
0
      this->SetGeneratorPlatform(expandedPreset->Architecture);
2165
0
    }
2166
0
  }
2167
0
  if (!expandedPreset->ToolsetStrategy ||
2168
0
      expandedPreset->ToolsetStrategy ==
2169
0
        cmCMakePresetsGraph::ArchToolsetStrategy::Set) {
2170
0
    if (!this->GeneratorToolsetSet && !expandedPreset->Toolset.empty()) {
2171
0
      this->SetGeneratorToolset(expandedPreset->Toolset);
2172
0
    }
2173
0
  }
2174
2175
0
  if (!expandedPreset->GraphVizFile.empty()) {
2176
0
    if (this->GraphVizFile.empty()) {
2177
0
      this->SetGraphVizFile(
2178
0
        cmSystemTools::CollapseFullPath(expandedPreset->GraphVizFile));
2179
0
    }
2180
0
  }
2181
2182
0
  this->SetDiagnosticsFromPreset(expandedPreset->Warnings,
2183
0
                                 expandedPreset->Errors);
2184
0
  if (expandedPreset->WarnSystemVars == true) {
2185
0
    this->SetCheckSystemVars(true);
2186
0
  }
2187
0
  if (expandedPreset->DebugOutput == true) {
2188
0
    this->SetDebugOutputOn(true);
2189
0
  }
2190
0
  if (expandedPreset->DebugTryCompile == true) {
2191
0
    this->DebugTryCompileOn();
2192
0
  }
2193
0
  if (expandedPreset->DebugFind == true) {
2194
0
    this->SetDebugFindOutput(true);
2195
0
  }
2196
0
  if (expandedPreset->TraceMode &&
2197
0
      expandedPreset->TraceMode !=
2198
0
        cmCMakePresetsGraph::TraceEnableMode::Disable) {
2199
0
    this->SetTrace(true);
2200
0
    if (expandedPreset->TraceMode ==
2201
0
        cmCMakePresetsGraph::TraceEnableMode::Expand) {
2202
0
      this->SetTraceExpand(true);
2203
0
    }
2204
0
  }
2205
0
  if (expandedPreset->TraceFormat) {
2206
0
    this->SetTrace(true);
2207
0
    this->SetTraceFormat(*expandedPreset->TraceFormat);
2208
0
  }
2209
0
  if (!expandedPreset->TraceSource.empty()) {
2210
0
    this->SetTrace(true);
2211
0
    for (std::string const& filePaths : expandedPreset->TraceSource) {
2212
0
      this->AddTraceSource(filePaths);
2213
0
    }
2214
0
  }
2215
0
  if (!expandedPreset->TraceRedirect.empty()) {
2216
0
    this->SetTrace(true);
2217
0
    this->SetTraceFile(expandedPreset->TraceRedirect);
2218
0
  }
2219
2220
  // Store preset variables in case of cache reset.
2221
0
  this->InitialPresetVariables = this->UnprocessedPresetVariables;
2222
2223
0
  return true;
2224
0
}
2225
2226
cmCMakePresetsGraph::ConfigurePresetUsabilityCheck
2227
cmake::CreateConfigurePresetUsabilityCheck() const
2228
0
{
2229
0
  std::vector<GeneratorInfo> generators;
2230
0
  this->GetRegisteredGenerators(generators);
2231
2232
0
  std::set<std::string> generatorNames;
2233
0
  for (auto const& generator : generators) {
2234
0
    generatorNames.insert(generator.name);
2235
0
  }
2236
2237
0
  return [generatorNames](cmCMakePresetsGraph::ConfigurePreset const& preset)
2238
0
           -> cm::optional<std::string> {
2239
0
    if (preset.Generator.empty() ||
2240
0
        generatorNames.count(preset.Generator) != 0) {
2241
0
      return cm::nullopt;
2242
0
    }
2243
0
    return cmStrCat("generator \"", preset.Generator, "\" is not available");
2244
0
  };
2245
0
}
2246
2247
void cmake::PrintPresetList(cmCMakePresetsGraph const& graph,
2248
                            cmCMakePresetsGraph::PresetListMode mode) const
2249
0
{
2250
0
  graph.PrintConfigurePresetList(mode,
2251
0
                                 this->CreateConfigurePresetUsabilityCheck());
2252
0
}
2253
#endif
2254
2255
void cmake::SetHomeDirectoryViaCommandLine(std::string const& path)
2256
0
{
2257
0
  if (path.empty()) {
2258
0
    return;
2259
0
  }
2260
2261
0
  auto prev_path = this->GetHomeDirectory();
2262
0
  if (prev_path != path && !prev_path.empty() &&
2263
0
      this->State->GetRole() == cmState::Role::Project) {
2264
0
    this->IssueMessage(
2265
0
      MessageType::WARNING,
2266
0
      cmStrCat("Ignoring extra path from command line:\n \"", prev_path, '"'));
2267
0
  }
2268
0
  this->SetHomeDirectory(path);
2269
0
}
2270
2271
void cmake::SetHomeDirectory(std::string const& dir)
2272
19.9k
{
2273
19.9k
  assert(!dir.empty());
2274
19.9k
  this->State->SetSourceDirectory(dir);
2275
19.9k
  if (this->CurrentSnapshot.IsValid()) {
2276
19.9k
    this->CurrentSnapshot.SetDefinition("CMAKE_SOURCE_DIR", dir);
2277
19.9k
  }
2278
2279
19.9k
  if (this->State->GetIsTryCompile() == cmState::TryCompile::No) {
2280
19.9k
    this->Messenger->SetTopSource(this->GetHomeDirectory());
2281
19.9k
  } else {
2282
0
    this->Messenger->SetTopSource(cm::nullopt);
2283
0
  }
2284
19.9k
}
2285
2286
std::string const& cmake::GetHomeDirectory() const
2287
19.9k
{
2288
19.9k
  return this->State->GetSourceDirectory();
2289
19.9k
}
2290
2291
void cmake::SetHomeOutputDirectory(std::string const& dir)
2292
19.9k
{
2293
19.9k
  assert(!dir.empty());
2294
19.9k
  this->State->SetBinaryDirectory(dir);
2295
19.9k
  if (this->CurrentSnapshot.IsValid()) {
2296
19.9k
    this->CurrentSnapshot.SetDefinition("CMAKE_BINARY_DIR", dir);
2297
19.9k
  }
2298
19.9k
}
2299
2300
std::string const& cmake::GetHomeOutputDirectory() const
2301
36
{
2302
36
  return this->State->GetBinaryDirectory();
2303
36
}
2304
2305
std::string cmake::FindCacheFile(std::string const& binaryDir)
2306
0
{
2307
0
  std::string cachePath = binaryDir;
2308
0
  cmSystemTools::ConvertToUnixSlashes(cachePath);
2309
0
  std::string cacheFile = cmStrCat(cachePath, "/CMakeCache.txt");
2310
0
  if (!cmSystemTools::FileExists(cacheFile)) {
2311
    // search in parent directories for cache
2312
0
    std::string cmakeFiles = cmStrCat(cachePath, "/CMakeFiles");
2313
0
    if (cmSystemTools::FileExists(cmakeFiles)) {
2314
0
      std::string cachePathFound =
2315
0
        cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt",
2316
0
                                                     cachePath, "/");
2317
0
      if (!cachePathFound.empty()) {
2318
0
        cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
2319
0
      }
2320
0
    }
2321
0
  }
2322
0
  return cachePath;
2323
0
}
2324
2325
void cmake::SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator> gg)
2326
5.92k
{
2327
5.92k
  if (!gg) {
2328
0
    cmSystemTools::Error("Error SetGlobalGenerator called with null");
2329
0
    return;
2330
0
  }
2331
5.92k
  if (this->GlobalGenerator) {
2332
    // restore the original environment variables CXX and CC
2333
0
    std::string env = "CC=";
2334
0
    if (!this->CCEnvironment.empty()) {
2335
0
      env += this->CCEnvironment;
2336
0
      cmSystemTools::PutEnv(env);
2337
0
    } else {
2338
0
      cmSystemTools::UnPutEnv(env);
2339
0
    }
2340
0
    env = "CXX=";
2341
0
    if (!this->CXXEnvironment.empty()) {
2342
0
      env += this->CXXEnvironment;
2343
0
      cmSystemTools::PutEnv(env);
2344
0
    } else {
2345
0
      cmSystemTools::UnPutEnv(env);
2346
0
    }
2347
0
  }
2348
2349
  // set the new
2350
5.92k
  this->GlobalGenerator = std::move(gg);
2351
2352
  // set the global flag for unix style paths on cmSystemTools as soon as
2353
  // the generator is set.  This allows gmake to be used on windows.
2354
5.92k
  cmSystemTools::SetForceUnixPaths(this->GlobalGenerator->GetForceUnixPaths());
2355
2356
  // Save the environment variables CXX and CC
2357
5.92k
  if (!cmSystemTools::GetEnv("CXX", this->CXXEnvironment)) {
2358
5.92k
    this->CXXEnvironment.clear();
2359
5.92k
  }
2360
5.92k
  if (!cmSystemTools::GetEnv("CC", this->CCEnvironment)) {
2361
5.92k
    this->CCEnvironment.clear();
2362
5.92k
  }
2363
5.92k
}
2364
2365
int cmake::DoPreConfigureChecks()
2366
0
{
2367
  // Make sure the Source directory contains a CMakeLists.txt file.
2368
0
  std::string srcList =
2369
0
    cmStrCat(this->GetHomeDirectory(), '/', this->CMakeListName);
2370
0
  if (!cmSystemTools::FileExists(srcList)) {
2371
0
    std::string err;
2372
0
    if (cmSystemTools::FileIsDirectory(this->GetHomeDirectory())) {
2373
0
      err =
2374
0
        cmStrCat("The source directory \"", this->GetHomeDirectory(),
2375
0
                 "\" does not appear to contain ", this->CMakeListName, ".\n");
2376
0
    } else if (cmSystemTools::FileExists(this->GetHomeDirectory())) {
2377
0
      err = cmStrCat("The source directory \"", this->GetHomeDirectory(),
2378
0
                     "\" is a file, not a directory.\n");
2379
0
    } else {
2380
0
      err = cmStrCat("The source directory \"", this->GetHomeDirectory(),
2381
0
                     "\" does not exist.\n");
2382
0
    }
2383
0
    err += "Specify --help for usage, or press the help button on the CMake "
2384
0
           "GUI.";
2385
0
    cmSystemTools::Error(err);
2386
0
    return -2;
2387
0
  }
2388
2389
  // do a sanity check on some values
2390
0
  if (cmValue dir =
2391
0
        this->State->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY")) {
2392
0
    std::string cacheStart = cmStrCat(*dir, '/', this->CMakeListName);
2393
0
    if (!cmSystemTools::SameFile(cacheStart, srcList)) {
2394
0
      std::string message =
2395
0
        cmStrCat("The source \"", srcList, "\" does not match the source \"",
2396
0
                 cacheStart,
2397
0
                 "\" used to generate cache.  Re-run cmake with a different "
2398
0
                 "source directory.");
2399
0
      cmSystemTools::Error(message);
2400
0
      return -2;
2401
0
    }
2402
0
  } else {
2403
0
    return 0;
2404
0
  }
2405
0
  return 1;
2406
0
}
2407
struct SaveCacheEntry
2408
{
2409
  std::string key;
2410
  std::string value;
2411
  std::string help;
2412
  cmStateEnums::CacheEntryType type;
2413
};
2414
2415
int cmake::HandleDeleteCacheVariables(
2416
  std::map<std::string, std::string> const& vars)
2417
0
{
2418
  // erase the set to avoid infinite recursion
2419
0
  this->State->ClearDeleteCacheChangeVars();
2420
0
  if (this->GetIsInTryCompile()) {
2421
0
    return 0;
2422
0
  }
2423
0
  std::vector<SaveCacheEntry> saved;
2424
0
  std::string warning(
2425
0
    "You have changed variables that require your cache to be deleted.\n"
2426
0
    "Configure will be re-run and you may have to reset some variables.\n"
2427
0
    "The following variables have changed:\n");
2428
0
  for (auto const& var : vars) {
2429
0
    SaveCacheEntry save;
2430
0
    save.key = var.first;
2431
0
    save.value = var.second;
2432
0
    warning = cmStrCat(std::move(warning), save.key, "= ", save.value, '\n');
2433
0
    cmValue existingValue = this->State->GetCacheEntryValue(save.key);
2434
0
    if (existingValue) {
2435
0
      save.type = this->State->GetCacheEntryType(save.key);
2436
0
      if (cmValue help =
2437
0
            this->State->GetCacheEntryProperty(save.key, "HELPSTRING")) {
2438
0
        save.help = *help;
2439
0
      }
2440
0
    } else {
2441
0
      save.type = cmStateEnums::CacheEntryType::UNINITIALIZED;
2442
0
    }
2443
0
    saved.push_back(std::move(save));
2444
0
  }
2445
2446
  // remove the cache
2447
0
  this->DeleteCache(this->GetHomeOutputDirectory());
2448
  // load the empty cache
2449
0
  this->LoadCache();
2450
0
#ifndef CMAKE_BOOTSTRAP
2451
  // Restore preset cache variables.
2452
0
  this->UnprocessedPresetVariables = this->InitialPresetVariables;
2453
0
  this->ProcessPresetVariables();
2454
0
#endif
2455
  // Restore command line cache variables (from this invocation cmake only).
2456
0
  bool resetArgsSuccess = this->SetCacheArgs(this->cmdArgs);
2457
0
  assert(resetArgsSuccess);
2458
0
  (void)resetArgsSuccess;
2459
  // restore the changed compilers
2460
0
  for (SaveCacheEntry const& i : saved) {
2461
0
    this->AddCacheEntry(i.key, i.value, i.help, i.type);
2462
0
  }
2463
0
  cmSystemTools::Message(warning);
2464
  // avoid reconfigure if there were errors
2465
0
  if (!cmSystemTools::GetErrorOccurredFlag()) {
2466
    // re-run configure
2467
0
    this->State->SetReconfiguring(true);
2468
0
    return this->Configure();
2469
0
  }
2470
2471
  // Toolchain changes trigger a fatal error, but reconfiguring with the new
2472
  // toolchain should fix them.
2473
0
  if (vars.count("CMAKE_TOOLCHAIN_FILE") && !this->State->IsReconfiguring()) {
2474
0
    cmSystemTools::ResetErrorOccurredFlag();
2475
0
    this->State->SetReconfiguring(true);
2476
0
    return this->Configure();
2477
0
  }
2478
0
  return 0;
2479
0
}
2480
2481
int cmake::Configure()
2482
0
{
2483
0
#if !defined(CMAKE_BOOTSTRAP)
2484
0
  auto profilingRAII = this->CreateProfilingEntry("project", "configure");
2485
0
#endif
2486
2487
  // We now need to harmonize the previous initial diagnostic state with any
2488
  // changes requested via command line options and/or presets. We do this by
2489
  // first applying the prior (cached) state, then applying all deferred
2490
  // alterations.
2491
2492
0
  if (cmValue cachedDiagnostics =
2493
0
        this->State->GetCacheEntryValue("CMAKE_DIAGNOSTIC_INIT")) {
2494
0
    for (std::string const& item : cmList{ cachedDiagnostics }) {
2495
0
      std::string::size_type n = item.find('=');
2496
0
      if (n != std::string::npos) {
2497
0
        cm::string_view v = item;
2498
0
        cm::optional<cmDiagnosticCategory> const& category =
2499
0
          cmDiagnostics::GetDiagnosticCategory(v.substr(0, n));
2500
0
        cm::optional<cmDiagnosticAction> const& action =
2501
0
          cmDiagnostics::GetDiagnosticAction(v.substr(n + 1));
2502
2503
0
        if (category && action) {
2504
0
          this->CurrentSnapshot.SetDiagnostic(*category, *action, false);
2505
0
        }
2506
0
      }
2507
0
    }
2508
0
  }
2509
2510
0
  cmValue cachedWarnDeprecated =
2511
0
    this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
2512
0
  if (cachedWarnDeprecated) {
2513
0
    if (cachedWarnDeprecated.IsOn()) {
2514
0
      this->CurrentSnapshot.PromoteDiagnostic(cmDiagnostics::CMD_DEPRECATED,
2515
0
                                              cmDiagnostics::Warn, false);
2516
0
    } else {
2517
0
      this->CurrentSnapshot.DemoteDiagnostic(cmDiagnostics::CMD_DEPRECATED,
2518
0
                                             cmDiagnostics::Ignore, false);
2519
0
    }
2520
0
  }
2521
2522
0
  cmValue cachedErrorDeprecated =
2523
0
    this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
2524
0
  if (cachedErrorDeprecated) {
2525
0
    if (cachedErrorDeprecated.IsOn()) {
2526
0
      this->CurrentSnapshot.PromoteDiagnostic(cmDiagnostics::CMD_DEPRECATED,
2527
0
                                              cmDiagnostics::SendError, false);
2528
0
    } else {
2529
0
      this->CurrentSnapshot.DemoteDiagnostic(cmDiagnostics::CMD_DEPRECATED,
2530
0
                                             cmDiagnostics::Warn, false);
2531
0
    }
2532
0
  }
2533
2534
0
  for (DiagnosticAlteration const& da : this->DiagnosticAlterations) {
2535
0
    (this->CurrentSnapshot.*da.Alteration)(da.Category, da.DesiredAction,
2536
0
                                           da.Recurse);
2537
0
  }
2538
2539
  // Now write the diagnostic state back to the cache.
2540
0
  cmList diagnostics;
2541
0
  for (unsigned i = 1; i < cmDiagnostics::CategoryCount; ++i) {
2542
0
    auto const category = static_cast<cmDiagnosticCategory>(i);
2543
0
    auto const action = this->CurrentSnapshot.GetDiagnostic(category);
2544
2545
0
    diagnostics.emplace_back(
2546
0
      cmStrCat(cmDiagnostics::GetCategoryString(category), '=',
2547
0
               cmDiagnostics::GetActionString(action)));
2548
2549
0
    if (category == cmDiagnostics::CMD_DEPRECATED) {
2550
0
      std::string const warnValue =
2551
0
        (action >= cmDiagnostics::Warn ? "ON" : "OFF");
2552
0
      this->AddCacheEntry("CMAKE_WARN_DEPRECATED", warnValue,
2553
0
                          "Deprecated.  Use -W[no-]deprecated instead.",
2554
0
                          cmStateEnums::INTERNAL);
2555
0
      std::string const errorValue =
2556
0
        (action >= cmDiagnostics::SendError ? "ON" : "OFF");
2557
0
      this->AddCacheEntry("CMAKE_ERROR_DEPRECATED", errorValue,
2558
0
                          "Deprecated.  Use -W[no-]error=deprecated instead.",
2559
0
                          cmStateEnums::INTERNAL);
2560
0
    }
2561
0
  }
2562
2563
0
  this->AddCacheEntry("CMAKE_DIAGNOSTIC_INIT", cmJoin(diagnostics, ";"_s),
2564
0
                      "Set initial state for CMake diagnostics; "
2565
0
                      "used to persist state set by command-line options "
2566
0
                      "across invocations.",
2567
0
                      cmStateEnums::INTERNAL);
2568
2569
0
  int ret = this->ActualConfigure();
2570
0
  std::map<std::string, std::string> delCacheVars =
2571
0
    this->State->GetDeleteCacheChangeVars();
2572
0
  if (!delCacheVars.empty()) {
2573
0
    return this->HandleDeleteCacheVariables(delCacheVars);
2574
0
  }
2575
0
  return ret;
2576
0
}
2577
2578
void cmake::InvalidateFileSystemCaches()
2579
0
{
2580
0
  this->ActualCaseCache.clear();
2581
0
  if (this->GlobalGenerator) {
2582
0
    this->GlobalGenerator->ClearSourceFileExistsCache();
2583
0
  }
2584
0
}
2585
2586
int cmake::ActualConfigure()
2587
0
{
2588
  // Construct right now our path conversion table before it's too late:
2589
0
  this->CleanupCommandsAndMacros();
2590
2591
  // The file system may have changed since a previous configure in the
2592
  // same process.
2593
0
  this->InvalidateFileSystemCaches();
2594
2595
  // Do not keep the parse trees of a previous configure in the same
2596
  // process alive.  Compiled expressions still referring to them share
2597
  // their ownership.
2598
0
  this->GeneratorExpressionParseCache->Clear();
2599
2600
0
  cmSystemTools::RemoveADirectory(this->GetHomeOutputDirectory() +
2601
0
                                  "/CMakeFiles/CMakeScratch");
2602
2603
0
  std::string cmlNameCache =
2604
0
    this->State->GetInitializedCacheValue("CMAKE_LIST_FILE_NAME");
2605
0
  if (!cmlNameCache.empty() && !this->CMakeListName.empty() &&
2606
0
      cmlNameCache != this->CMakeListName) {
2607
0
    std::string message =
2608
0
      cmStrCat("CMakeLists filename : \"", this->CMakeListName,
2609
0
               "\"\nDoes not match the previous: \"", cmlNameCache,
2610
0
               "\"\nEither remove the CMakeCache.txt file and CMakeFiles "
2611
0
               "directory or choose a different binary directory.");
2612
0
    cmSystemTools::Error(message);
2613
0
    return -2;
2614
0
  }
2615
0
  if (this->CMakeListName.empty()) {
2616
0
    this->CMakeListName =
2617
0
      cmlNameCache.empty() ? "CMakeLists.txt" : cmlNameCache;
2618
0
  }
2619
0
  if (this->CMakeListName != "CMakeLists.txt") {
2620
0
    this->IssueMessage(
2621
0
      MessageType::WARNING,
2622
0
      "This project has been configured with a project file other than "
2623
0
      "CMakeLists.txt. This feature is intended for temporary use during "
2624
0
      "development and not for publication of a final product.");
2625
0
  }
2626
0
  this->AddCacheEntry("CMAKE_LIST_FILE_NAME", this->CMakeListName,
2627
0
                      "Name of CMakeLists files to read",
2628
0
                      cmStateEnums::INTERNAL);
2629
2630
0
  int res = this->DoPreConfigureChecks();
2631
0
  if (res < 0) {
2632
0
    return -2;
2633
0
  }
2634
0
  if (!res) {
2635
0
    this->AddCacheEntry(
2636
0
      "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory(),
2637
0
      "Source directory with the top level CMakeLists.txt file for this "
2638
0
      "project",
2639
0
      cmStateEnums::INTERNAL);
2640
0
  }
2641
2642
  // We want to create the package redirects directory as early as possible,
2643
  // but not before pre-configure checks have passed. This ensures we get
2644
  // errors about inappropriate source/binary directories first.
2645
0
  auto const redirectsDir =
2646
0
    cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles/pkgRedirects");
2647
0
  cmSystemTools::RemoveADirectory(redirectsDir);
2648
0
  if (!cmSystemTools::MakeDirectory(redirectsDir)) {
2649
0
    cmSystemTools::Error(
2650
0
      cmStrCat("Unable to (re)create the private pkgRedirects directory:\n  ",
2651
0
               redirectsDir,
2652
0
               "\n"
2653
0
               "This may be caused by not having read/write access to "
2654
0
               "the build directory.\n"
2655
0
               "Try specifying a location with read/write access like:\n"
2656
0
               "  cmake -B build\n"
2657
0
               "If using a CMake presets file, ensure that preset parameter\n"
2658
0
               "'binaryDir' expands to a writable directory.\n"));
2659
0
    return -1;
2660
0
  }
2661
0
  this->AddCacheEntry("CMAKE_FIND_PACKAGE_REDIRECTS_DIR", redirectsDir,
2662
0
                      "Value Computed by CMake.", cmStateEnums::STATIC);
2663
2664
  // no generator specified on the command line
2665
0
  if (!this->GlobalGenerator) {
2666
0
    cmValue genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
2667
0
    cmValue extraGenName =
2668
0
      this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
2669
0
    if (genName) {
2670
0
      std::string fullName =
2671
0
        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
2672
0
          *genName, extraGenName ? *extraGenName : "");
2673
0
      this->GlobalGenerator = this->CreateGlobalGenerator(fullName);
2674
0
    }
2675
0
    if (this->GlobalGenerator) {
2676
      // set the global flag for unix style paths on cmSystemTools as
2677
      // soon as the generator is set.  This allows gmake to be used
2678
      // on windows.
2679
0
      cmSystemTools::SetForceUnixPaths(
2680
0
        this->GlobalGenerator->GetForceUnixPaths());
2681
0
    } else {
2682
0
      this->CreateDefaultGlobalGenerator();
2683
0
    }
2684
0
    if (!this->GlobalGenerator) {
2685
0
      cmSystemTools::Error("Could not create generator");
2686
0
      return -1;
2687
0
    }
2688
0
  }
2689
2690
0
  cmValue genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
2691
0
  if (genName) {
2692
0
    if (!this->GlobalGenerator->MatchesGeneratorName(*genName)) {
2693
0
      std::string message =
2694
0
        cmStrCat("Error: generator : ", this->GlobalGenerator->GetName(),
2695
0
                 "\n"
2696
0
                 "Does not match the generator used previously: ",
2697
0
                 *genName,
2698
0
                 "\n"
2699
0
                 "Either remove the CMakeCache.txt file and CMakeFiles "
2700
0
                 "directory or choose a different binary directory.");
2701
0
      cmSystemTools::Error(message);
2702
0
      return -2;
2703
0
    }
2704
0
  }
2705
0
  if (!genName) {
2706
0
    this->AddCacheEntry("CMAKE_GENERATOR", this->GlobalGenerator->GetName(),
2707
0
                        "Name of generator.", cmStateEnums::INTERNAL);
2708
0
    this->AddCacheEntry(
2709
0
      "CMAKE_EXTRA_GENERATOR", this->GlobalGenerator->GetExtraGeneratorName(),
2710
0
      "Name of external makefile project generator.", cmStateEnums::INTERNAL);
2711
2712
0
    if (!this->State->GetInitializedCacheValue("CMAKE_TOOLCHAIN_FILE")) {
2713
0
      std::string envToolchain;
2714
0
      if (cmSystemTools::GetEnv("CMAKE_TOOLCHAIN_FILE", envToolchain) &&
2715
0
          !envToolchain.empty()) {
2716
0
        this->AddCacheEntry("CMAKE_TOOLCHAIN_FILE", envToolchain,
2717
0
                            "The CMake toolchain file",
2718
0
                            cmStateEnums::FILEPATH);
2719
0
      }
2720
0
    }
2721
0
  }
2722
2723
0
  if (cmValue instance =
2724
0
        this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) {
2725
0
    if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) {
2726
0
      std::string message =
2727
0
        cmStrCat("Error: generator instance: ", this->GeneratorInstance,
2728
0
                 "\n"
2729
0
                 "Does not match the instance used previously: ",
2730
0
                 *instance,
2731
0
                 "\n"
2732
0
                 "Either remove the CMakeCache.txt file and CMakeFiles "
2733
0
                 "directory or choose a different binary directory.");
2734
0
      cmSystemTools::Error(message);
2735
0
      return -2;
2736
0
    }
2737
0
  } else {
2738
0
    this->AddCacheEntry("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance,
2739
0
                        "Generator instance identifier.",
2740
0
                        cmStateEnums::INTERNAL);
2741
0
  }
2742
2743
0
  if (cmValue platformName =
2744
0
        this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
2745
0
    if (this->GeneratorPlatformSet &&
2746
0
        this->GeneratorPlatform != *platformName) {
2747
0
      std::string message =
2748
0
        cmStrCat("Error: generator platform: ", this->GeneratorPlatform,
2749
0
                 "\n"
2750
0
                 "Does not match the platform used previously: ",
2751
0
                 *platformName,
2752
0
                 "\n"
2753
0
                 "Either remove the CMakeCache.txt file and CMakeFiles "
2754
0
                 "directory or choose a different binary directory.");
2755
0
      cmSystemTools::Error(message);
2756
0
      return -2;
2757
0
    }
2758
0
  } else {
2759
0
    this->AddCacheEntry("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform,
2760
0
                        "Name of generator platform.", cmStateEnums::INTERNAL);
2761
0
  }
2762
2763
0
  if (cmValue tsName =
2764
0
        this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
2765
0
    if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) {
2766
0
      std::string message =
2767
0
        cmStrCat("Error: generator toolset: ", this->GeneratorToolset,
2768
0
                 "\n"
2769
0
                 "Does not match the toolset used previously: ",
2770
0
                 *tsName,
2771
0
                 "\n"
2772
0
                 "Either remove the CMakeCache.txt file and CMakeFiles "
2773
0
                 "directory or choose a different binary directory.");
2774
0
      cmSystemTools::Error(message);
2775
0
      return -2;
2776
0
    }
2777
0
  } else {
2778
0
    this->AddCacheEntry("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset,
2779
0
                        "Name of generator toolset.", cmStateEnums::INTERNAL);
2780
0
  }
2781
2782
0
  if (!this->State->GetInitializedCacheValue(
2783
0
        "CMAKE_INTERMEDIATE_DIR_STRATEGY") &&
2784
0
      this->IntermediateDirStrategy) {
2785
0
    this->AddCacheEntry(
2786
0
      "CMAKE_INTERMEDIATE_DIR_STRATEGY", *this->IntermediateDirStrategy,
2787
0
      "Select the intermediate directory strategy", cmStateEnums::INTERNAL);
2788
0
  }
2789
0
  if (!this->State->GetInitializedCacheValue(
2790
0
        "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY") &&
2791
0
      this->AutogenIntermediateDirStrategy) {
2792
0
    this->AddCacheEntry(
2793
0
      "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY",
2794
0
      *this->AutogenIntermediateDirStrategy,
2795
0
      "Select the intermediate directory strategy for Autogen",
2796
0
      cmStateEnums::INTERNAL);
2797
0
  }
2798
2799
0
  if (!this->State->GetInitializedCacheValue("CMAKE_TEST_LAUNCHER")) {
2800
0
    cm::optional<std::string> testLauncher =
2801
0
      cmSystemTools::GetEnvVar("CMAKE_TEST_LAUNCHER");
2802
0
    if (testLauncher && !testLauncher->empty()) {
2803
0
      std::string message = "Test launcher to run tests executable.";
2804
0
      this->AddCacheEntry("CMAKE_TEST_LAUNCHER", *testLauncher, message,
2805
0
                          cmStateEnums::STRING);
2806
0
    }
2807
0
  }
2808
2809
0
  if (!this->State->GetInitializedCacheValue(
2810
0
        "CMAKE_CROSSCOMPILING_EMULATOR")) {
2811
0
    cm::optional<std::string> emulator =
2812
0
      cmSystemTools::GetEnvVar("CMAKE_CROSSCOMPILING_EMULATOR");
2813
0
    if (emulator && !emulator->empty()) {
2814
0
      std::string message =
2815
0
        "Emulator to run executables and tests when cross compiling.";
2816
0
      this->AddCacheEntry("CMAKE_CROSSCOMPILING_EMULATOR", *emulator, message,
2817
0
                          cmStateEnums::STRING);
2818
0
    }
2819
0
  }
2820
2821
0
  if (!this->State->GetInitializedCacheValue(
2822
0
        "CMAKE_DISABLE_PRECOMPILE_HEADERS")) {
2823
0
    cm::optional<std::string> disablePrecompileHeaders =
2824
0
      cmSystemTools::GetEnvVar("CMAKE_DISABLE_PRECOMPILE_HEADERS");
2825
0
    if (disablePrecompileHeaders && !disablePrecompileHeaders->empty()) {
2826
0
      std::string message =
2827
0
        "Default value for DISABLE_PRECOMPILE_HEADERS of targets.";
2828
0
      this->AddCacheEntry("CMAKE_DISABLE_PRECOMPILE_HEADERS",
2829
0
                          *disablePrecompileHeaders, message,
2830
0
                          cmStateEnums::BOOL);
2831
0
    }
2832
0
  }
2833
2834
  // reset any system configuration information, except for when we are
2835
  // InTryCompile. With TryCompile the system info is taken from the parent's
2836
  // info to save time
2837
0
  if (!this->GetIsInTryCompile()) {
2838
0
    this->GlobalGenerator->ClearEnabledLanguages();
2839
0
  }
2840
2841
0
#if !defined(CMAKE_BOOTSTRAP)
2842
0
  this->InitializeFileAPI();
2843
0
  this->FileAPI->ReadQueries();
2844
0
  this->InitializeInstrumentation();
2845
2846
0
  if (!this->GetIsInTryCompile()) {
2847
0
    this->TruncateOutputLog("CMakeConfigureLog.yaml");
2848
0
    this->ConfigureLog = cm::make_unique<cmConfigureLog>(
2849
0
      cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s),
2850
0
      this->FileAPI->GetConfigureLogVersions());
2851
0
    this->Instrumentation->ClearGeneratedQueries();
2852
0
    this->Instrumentation->CheckCDashVariable();
2853
0
  }
2854
0
#endif
2855
2856
  // actually do the configure
2857
0
  auto startTime = std::chrono::steady_clock::now();
2858
0
#if !defined(CMAKE_BOOTSTRAP)
2859
0
  if (this->Instrumentation->HasErrors()) {
2860
0
    return 1;
2861
0
  }
2862
0
  auto doConfigure = [this]() -> int {
2863
0
    this->GlobalGenerator->Configure();
2864
0
    return 0;
2865
0
  };
2866
0
  int ret = this->Instrumentation->InstrumentCommand(
2867
0
    "configure", this->cmdArgs,
2868
0
    [doConfigure]() -> cmInstrumentation::CommandResult {
2869
0
      return { doConfigure(), cm::nullopt, cm::nullopt, cm::nullopt };
2870
0
    },
2871
0
    cm::nullopt, cm::nullopt,
2872
0
    this->GetIsInTryCompile() ? cmInstrumentation::LoadQueriesAfter::No
2873
0
                              : cmInstrumentation::LoadQueriesAfter::Yes);
2874
0
  if (ret != 0) {
2875
0
    return ret;
2876
0
  }
2877
#else
2878
  this->GlobalGenerator->Configure();
2879
#endif
2880
0
  auto endTime = std::chrono::steady_clock::now();
2881
2882
  // configure result
2883
0
  if (this->State->GetRole() == cmState::Role::Project) {
2884
0
    std::string msg;
2885
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
2886
0
      msg = "Configuring incomplete, errors occurred!";
2887
0
    } else {
2888
0
      auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
2889
0
        endTime - startTime);
2890
0
      msg.resize(128);
2891
      // NOLINTNEXTLINE(readability-container-data-pointer)
2892
0
      msg.resize(snprintf(&msg[0], msg.size(), "Configuring done (%.1fs)",
2893
0
                          static_cast<double>(ms.count()) * 1e-3));
2894
0
    }
2895
0
    this->UpdateProgress(msg, -1);
2896
0
  }
2897
2898
0
#if !defined(CMAKE_BOOTSTRAP)
2899
0
  this->ConfigureLog.reset();
2900
0
#endif
2901
2902
  // Before saving the cache
2903
  // if the project did not define one of the entries below, add them now
2904
  // so users can edit the values in the cache:
2905
2906
0
  auto const& mf = this->GlobalGenerator->GetMakefiles()[0];
2907
2908
0
  if (mf->IsOn("CTEST_USE_LAUNCHERS") &&
2909
0
      !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) {
2910
0
    this->IssueMessage(MessageType::FATAL_ERROR,
2911
0
                       "CTEST_USE_LAUNCHERS is enabled, but the "
2912
0
                       "RULE_LAUNCH_COMPILE global property is not defined.\n"
2913
0
                       "Did you forget to include(CTest) in the toplevel "
2914
0
                       "CMakeLists.txt ?");
2915
0
  }
2916
  // Setup launchers for instrumentation
2917
0
#if !defined(CMAKE_BOOTSTRAP)
2918
0
  if (this->Instrumentation->HasQuery()) {
2919
0
    std::string launcher;
2920
0
    if (mf->IsOn("CTEST_USE_LAUNCHERS")) {
2921
0
      launcher = cmStrCat('"', cmSystemTools::GetCTestCommand(),
2922
0
                          "\" --launch "
2923
0
                          "--current-build-dir <CMAKE_CURRENT_BINARY_DIR> "
2924
0
                          "--object-dir <TARGET_SUPPORT_DIR> ");
2925
0
    } else {
2926
0
      launcher =
2927
0
        cmStrCat('"', cmSystemTools::GetCTestCommand(), "\" --instrument ");
2928
0
    }
2929
0
    std::string common_args =
2930
0
      cmStrCat(" --target-name <TARGET_NAME> --config <CONFIG> --build-dir \"",
2931
0
               this->State->GetBinaryDirectory(), "\" ");
2932
0
    this->State->SetGlobalProperty(
2933
0
      "RULE_LAUNCH_COMPILE",
2934
0
      cmStrCat(
2935
0
        launcher, "--command-type compile", common_args,
2936
0
        "--output <OBJECT> --source <SOURCE> --language <LANGUAGE> -- "));
2937
0
    this->State->SetGlobalProperty(
2938
0
      "RULE_LAUNCH_LINK",
2939
0
      cmStrCat(
2940
0
        launcher, "--command-type link", common_args,
2941
0
        "--output <TARGET> --config <CONFIG> --language <LANGUAGE> -- "));
2942
0
    this->State->SetGlobalProperty(
2943
0
      "RULE_LAUNCH_CUSTOM",
2944
0
      cmStrCat(
2945
0
        launcher, "--command-type custom", common_args,
2946
0
        "--output-as-file-name \"<OUTPUT_STORE_TO_FILE>\" --role <ROLE> -- "));
2947
0
  }
2948
0
#endif
2949
2950
0
  this->State->SaveVerificationScript(this->GetHomeOutputDirectory(),
2951
0
                                      this->Messenger.get());
2952
0
  this->SaveCache(this->GetHomeOutputDirectory());
2953
0
  if (cmSystemTools::GetErrorOccurredFlag()) {
2954
0
#if !defined(CMAKE_BOOTSTRAP)
2955
0
    this->FileAPI->WriteReplies(cmFileAPI::IndexFor::FailedConfigure);
2956
0
#endif
2957
0
    return -1;
2958
0
  }
2959
0
  return 0;
2960
0
}
2961
2962
std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
2963
0
{
2964
0
  if (!this->EnvironmentGenerator.empty()) {
2965
0
    auto gen = this->CreateGlobalGenerator(this->EnvironmentGenerator);
2966
0
    if (!gen) {
2967
0
      cmSystemTools::Error("CMAKE_GENERATOR was set but the specified "
2968
0
                           "generator doesn't exist. Using CMake default.");
2969
0
    } else {
2970
0
      return gen;
2971
0
    }
2972
0
  }
2973
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
2974
  std::string found;
2975
  // Try to find the newest VS installed on the computer and
2976
  // use that as a default if -G is not specified
2977
  if (cmVSSetupAPIHelper(18).IsVSInstalled()) {
2978
    found = "Visual Studio 18 2026";
2979
  } else if (cmVSSetupAPIHelper(17).IsVSInstalled()) {
2980
    found = "Visual Studio 17 2022";
2981
  } else if (cmVSSetupAPIHelper(16).IsVSInstalled()) {
2982
    found = "Visual Studio 16 2019";
2983
  } else if (cmVSSetupAPIHelper(15).IsVSInstalled()) {
2984
    found = "Visual Studio 15 2017";
2985
  }
2986
  auto gen = this->CreateGlobalGenerator(found);
2987
  if (!gen) {
2988
    gen = cm::make_unique<cmGlobalNMakeMakefileGenerator>(this);
2989
  }
2990
  return std::unique_ptr<cmGlobalGenerator>(std::move(gen));
2991
#elif defined(CMAKE_BOOTSTRAP_NINJA)
2992
  return std::unique_ptr<cmGlobalGenerator>(
2993
    cm::make_unique<cmGlobalNinjaGenerator>(this));
2994
#else
2995
0
  return std::unique_ptr<cmGlobalGenerator>(
2996
0
    cm::make_unique<cmGlobalUnixMakefileGenerator3>(this));
2997
0
#endif
2998
0
}
2999
3000
void cmake::CreateDefaultGlobalGenerator()
3001
0
{
3002
0
  auto gen = this->EvaluateDefaultGlobalGenerator();
3003
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
3004
  // This print could be unified for all platforms
3005
  std::cout << "-- Building for: " << gen->GetName() << '\n';
3006
#endif
3007
0
  this->SetGlobalGenerator(std::move(gen));
3008
0
}
3009
3010
void cmake::PreLoadCMakeFiles()
3011
0
{
3012
0
  std::vector<std::string> args;
3013
0
  std::string pre_load = this->GetHomeDirectory();
3014
0
  if (!pre_load.empty()) {
3015
0
    pre_load += "/PreLoad.cmake";
3016
0
    if (cmSystemTools::FileExists(pre_load)) {
3017
0
      this->ReadListFile(args, pre_load);
3018
0
    }
3019
0
  }
3020
0
  pre_load = this->GetHomeOutputDirectory();
3021
0
  if (!pre_load.empty()) {
3022
0
    pre_load += "/PreLoad.cmake";
3023
0
    if (cmSystemTools::FileExists(pre_load)) {
3024
0
      this->ReadListFile(args, pre_load);
3025
0
    }
3026
0
  }
3027
0
}
3028
3029
#ifdef CMake_ENABLE_DEBUGGER
3030
3031
bool cmake::StartDebuggerIfEnabled()
3032
1
{
3033
1
  if (!this->GetDebuggerOn()) {
3034
1
    return true;
3035
1
  }
3036
3037
0
  if (!DebugAdapter) {
3038
0
    if (this->GetDebuggerPipe().empty()) {
3039
0
      std::cerr
3040
0
        << "Error: --debugger-pipe must be set when debugging is enabled.\n";
3041
0
      return false;
3042
0
    }
3043
3044
0
    try {
3045
0
      DebugAdapter = std::make_shared<cmDebugger::cmDebuggerAdapter>(
3046
0
        std::make_shared<cmDebugger::cmDebuggerPipeConnection>(
3047
0
          this->GetDebuggerPipe()),
3048
0
        this->GetDebuggerDapLogFile());
3049
0
    } catch (std::runtime_error const& error) {
3050
0
      std::cerr << "Error: Failed to create debugger adapter.\n";
3051
0
      std::cerr << error.what() << "\n";
3052
0
      return false;
3053
0
    }
3054
0
    Messenger->SetDebuggerAdapter(DebugAdapter);
3055
0
  }
3056
3057
0
  return true;
3058
0
}
3059
3060
void cmake::StopDebuggerIfNeeded(int exitCode)
3061
0
{
3062
0
  if (!this->GetDebuggerOn()) {
3063
0
    return;
3064
0
  }
3065
3066
  // The debug adapter may have failed to start (e.g. invalid pipe path).
3067
0
  if (DebugAdapter) {
3068
0
    DebugAdapter->ReportExitCode(exitCode);
3069
0
    DebugAdapter.reset();
3070
0
  }
3071
0
}
3072
3073
#endif
3074
3075
void cmake::InitializeFileAPI()
3076
0
{
3077
0
#ifndef CMAKE_BOOTSTRAP
3078
0
  if (!this->FileAPI) {
3079
0
    this->FileAPI = cm::make_unique<cmFileAPI>(this);
3080
0
  }
3081
0
#endif
3082
0
}
3083
3084
void cmake::InitializeInstrumentation()
3085
0
{
3086
0
#ifndef CMAKE_BOOTSTRAP
3087
0
  if (!this->Instrumentation) {
3088
0
    this->Instrumentation = cm::make_unique<cmInstrumentation>(
3089
0
      this->State->GetBinaryDirectory(),
3090
0
      cmInstrumentation::LoadQueriesAfter::No);
3091
0
  }
3092
0
#endif
3093
0
}
3094
3095
int cmake::HandleDifferentSystemEnvironmentId(std::string envId,
3096
                                              std::string cachedId)
3097
0
{
3098
0
  enum class Action
3099
0
  {
3100
0
    Ignore,
3101
0
    Warn,
3102
0
    Refresh,
3103
0
  } action = Action::Warn;
3104
0
  static std::string const actionEnvName = "CMAKE_SYSTEM_ENVIRONMENT_ACTION";
3105
0
  if (cmSystemTools::HasEnv(actionEnvName)) {
3106
0
    std::string actionEnv;
3107
0
    cmSystemTools::GetEnv(actionEnvName, actionEnv);
3108
0
    if (actionEnv == "IGNORE") {
3109
0
      action = Action::Ignore;
3110
0
    } else if (actionEnv == "WARN") {
3111
0
      action = Action::Warn;
3112
0
    } else if (actionEnv == "REFRESH") {
3113
0
      action = Action::Refresh;
3114
0
    } else {
3115
0
      this->IssueMessage(
3116
0
        MessageType::FATAL_ERROR,
3117
0
        cmStrCat("Unsupported ", actionEnvName, " '", actionEnv, '\''));
3118
0
      return -1;
3119
0
    }
3120
0
  }
3121
0
  switch (action) {
3122
0
    case Action::Ignore:
3123
0
      break;
3124
0
    case Action::Warn: {
3125
0
      std::string msg = cmStrCat(
3126
0
        "CMAKE_SYSTEM_ENVIRONMENT_ID: ", envId,
3127
0
        "\nDoes not match the previous value: ", cachedId,
3128
0
        "\nThe configure results are probably outdated. Consider running"
3129
0
        " cmake with --fresh, removing the CMakeCache.txt file and"
3130
0
        " CMakeFiles directory, or choosing a different binary"
3131
0
        " directory.");
3132
0
      this->IssueMessage(MessageType::WARNING, msg);
3133
0
      break;
3134
0
    }
3135
0
    case Action::Refresh: {
3136
0
      std::string msg =
3137
0
        cmStrCat("CMAKE_SYSTEM_ENVIRONMENT_ID: ", envId,
3138
0
                 "\nDoes not match the previous value: ", cachedId,
3139
0
                 "\nThe cache will be refreshed automatically.");
3140
0
      this->IssueMessage(MessageType::MESSAGE, msg);
3141
0
      this->DeleteCache(this->GetHomeOutputDirectory());
3142
0
      if (this->LoadCache() < 0) {
3143
0
        cmSystemTools::Error(
3144
0
          "Error executing cmake::LoadCache(). Aborting.\n");
3145
0
        return -1;
3146
0
      }
3147
0
      this->AddCacheEntry(
3148
0
        "CMAKE_SYSTEM_ENVIRONMENT_ID", envId,
3149
0
        "Opaque identifier for the current system environment",
3150
0
        cmStateEnums::INTERNAL);
3151
0
      break;
3152
0
    }
3153
0
  }
3154
0
  return 0;
3155
0
}
3156
3157
// handle a command line invocation
3158
int cmake::Run(std::vector<std::string> const& args, bool noconfigure)
3159
35
{
3160
  // Process the arguments
3161
35
  this->SetArgs(args);
3162
35
  if (cmSystemTools::GetErrorOccurredFlag()) {
3163
34
    return -1;
3164
34
  }
3165
1
  if (this->State->GetRole() == cmState::Role::Help) {
3166
0
    return 0;
3167
0
  }
3168
3169
1
#ifndef CMAKE_BOOTSTRAP
3170
1
  if (this->State->GetRole() == cmState::Role::Project) {
3171
0
    this->MarkCliAsUsed("CMAKE_EXPORT_SARIF");
3172
0
  }
3173
3174
1
  this->VariableWatch->AddWatch("CMAKE_WARN_DEPRECATED", cmDeprecatedWatch);
3175
1
  this->VariableWatch->AddWatch("CMAKE_ERROR_DEPRECATED", cmDeprecatedWatch);
3176
1
#endif
3177
3178
  // Log the trace format version to the desired output
3179
1
  if (this->GetTrace()) {
3180
0
    this->PrintTraceFormatVersion();
3181
0
  }
3182
3183
  // If we are given a stamp list file check if it is really out of date.
3184
1
  if (!this->CheckStampList.empty() &&
3185
0
      cmakeCheckStampList(this->CheckStampList)) {
3186
0
    return 0;
3187
0
  }
3188
3189
  // If we are given a stamp file check if it is really out of date.
3190
1
  if (!this->CheckStampFile.empty() &&
3191
0
      cmakeCheckStampFile(this->CheckStampFile)) {
3192
0
    return 0;
3193
0
  }
3194
3195
1
  if (this->State->GetRole() == cmState::Role::Project) {
3196
0
    if (this->FreshCache) {
3197
0
      this->DeleteCache(this->GetHomeOutputDirectory());
3198
0
    }
3199
    // load the cache
3200
0
    if (this->LoadCache() < 0) {
3201
0
      cmSystemTools::Error("Error executing cmake::LoadCache(). Aborting.\n");
3202
0
      return -1;
3203
0
    }
3204
0
    std::string const idKey = "CMAKE_SYSTEM_ENVIRONMENT_ID";
3205
0
    cmValue cachedEnvId = this->State->GetInitializedCacheValue(idKey);
3206
0
    std::string sysEnvId;
3207
0
    cmSystemTools::GetEnv(idKey, sysEnvId);
3208
0
    if (cachedEnvId) {
3209
0
      if (sysEnvId != *cachedEnvId) {
3210
0
        if (this->HandleDifferentSystemEnvironmentId(sysEnvId, *cachedEnvId) <
3211
0
            0) {
3212
          // Failed to LoadCache()
3213
0
          return -1;
3214
0
        }
3215
0
      }
3216
0
    } else {
3217
0
      this->AddCacheEntry(
3218
0
        idKey, sysEnvId,
3219
0
        "Opaque identifier for the current system environment",
3220
0
        cmStateEnums::INTERNAL);
3221
0
    }
3222
1
  } else {
3223
1
    if (this->FreshCache) {
3224
0
      cmSystemTools::Error("--fresh allowed only when configuring a project");
3225
0
      return -1;
3226
0
    }
3227
1
    this->AddCMakePaths();
3228
1
  }
3229
3230
1
#ifndef CMAKE_BOOTSTRAP
3231
1
  this->ProcessPresetVariables();
3232
1
  this->ProcessPresetEnvironment();
3233
1
#endif
3234
  // Add any cache args
3235
1
  if (!this->SetCacheArgs(args)) {
3236
0
    cmSystemTools::Error("Run 'cmake --help' for all supported options.");
3237
0
    return -1;
3238
0
  }
3239
1
#ifndef CMAKE_BOOTSTRAP
3240
1
  if (this->GetLogLevel() == Message::LogLevel::LOG_VERBOSE ||
3241
1
      this->GetLogLevel() == Message::LogLevel::LOG_DEBUG ||
3242
1
      this->GetLogLevel() == Message::LogLevel::LOG_TRACE) {
3243
0
    this->PrintPresetVariables();
3244
0
    this->PrintPresetEnvironment();
3245
0
  }
3246
1
#endif
3247
3248
  // In script mode we terminate after running the script.
3249
1
  if (this->State->GetRole() != cmState::Role::Project) {
3250
1
    if (cmSystemTools::GetErrorOccurredFlag()) {
3251
1
      return -1;
3252
1
    }
3253
0
    return this->HasScriptModeExitCode() ? this->GetScriptModeExitCode() : 0;
3254
1
  }
3255
3256
  // If MAKEFLAGS are given in the environment, remove the environment
3257
  // variable.  This will prevent try-compile from succeeding when it
3258
  // should fail (if "-i" is an option).  We cannot simply test
3259
  // whether "-i" is given and remove it because some make programs
3260
  // encode the MAKEFLAGS variable in a strange way.
3261
0
  if (cmSystemTools::HasEnv("MAKEFLAGS")) {
3262
0
    cmSystemTools::PutEnv("MAKEFLAGS=");
3263
0
  }
3264
3265
0
  this->PreLoadCMakeFiles();
3266
3267
0
  if (noconfigure) {
3268
0
    return 0;
3269
0
  }
3270
3271
  // now run the global generate
3272
  // Check the state of the build system to see if we need to regenerate.
3273
0
  if (!this->CheckBuildSystem()) {
3274
0
    return 0;
3275
0
  }
3276
  // After generating fbuild.bff, FastBuild sees rebuild-bff as outdated since
3277
  // it hasn’t built the target yet. To make it a no-op for future runs, we
3278
  // trigger a dummy fbuild invocation that creates this marker file and runs
3279
  // CMake, marking rebuild-bff as up-to-date.
3280
0
  std::string const FBuildRestatFile =
3281
0
    cmStrCat(this->GetHomeOutputDirectory(), '/', FASTBUILD_RESTAT_FILE);
3282
0
  if (cmSystemTools::FileExists(FBuildRestatFile)) {
3283
0
    cmsys::ifstream restat(FBuildRestatFile.c_str(),
3284
0
                           std::ios::in | std::ios::binary);
3285
0
    std::string const file((std::istreambuf_iterator<char>(restat)),
3286
0
                           std::istreambuf_iterator<char>());
3287
    // On Windows can not delete file if it's still opened.
3288
0
    restat.close();
3289
0
    cmSystemTools::Touch(file, true);
3290
0
    cmSystemTools::RemoveFile(FBuildRestatFile);
3291
0
    return 0;
3292
0
  }
3293
3294
0
#ifdef CMake_ENABLE_DEBUGGER
3295
0
  if (!this->StartDebuggerIfEnabled()) {
3296
0
    return -1;
3297
0
  }
3298
0
#endif
3299
3300
0
  int ret = this->Configure();
3301
0
  if (ret) {
3302
#if defined(CMAKE_HAVE_VS_GENERATORS)
3303
    if (!this->VSSolutionFile.empty() && this->GlobalGenerator) {
3304
      // CMake is running to regenerate a Visual Studio build tree
3305
      // during a build from the VS IDE.  The build files cannot be
3306
      // regenerated, so we should stop the build.
3307
      cmSystemTools::Message("CMake Configure step failed.  "
3308
                             "Build files cannot be regenerated correctly.  "
3309
                             "Attempting to stop IDE build.");
3310
      cmGlobalVisualStudioGenerator& gg =
3311
        cm::static_reference_cast<cmGlobalVisualStudioGenerator>(
3312
          this->GlobalGenerator);
3313
      gg.CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
3314
                               this->VSSolutionFile);
3315
    }
3316
#endif
3317
0
    return ret;
3318
0
  }
3319
0
  ret = this->Generate();
3320
0
  if (ret) {
3321
0
    cmSystemTools::Message("CMake Generate step failed.  "
3322
0
                           "Build files cannot be regenerated correctly.");
3323
0
    return ret;
3324
0
  }
3325
0
  std::string message = cmStrCat("Build files have been written to: ",
3326
0
                                 this->GetHomeOutputDirectory());
3327
0
  this->UpdateProgress(message, -1);
3328
0
  return ret;
3329
0
}
3330
3331
int cmake::Generate()
3332
0
{
3333
0
  if (!this->GlobalGenerator) {
3334
0
    return -1;
3335
0
  }
3336
3337
0
  auto startTime = std::chrono::steady_clock::now();
3338
0
#if !defined(CMAKE_BOOTSTRAP)
3339
0
  auto profilingRAII = this->CreateProfilingEntry("project", "generate");
3340
0
  auto doGenerate = [this]() -> int {
3341
0
    if (!this->GlobalGenerator->Compute()) {
3342
0
      this->FileAPI->WriteReplies(cmFileAPI::IndexFor::FailedCompute);
3343
0
      return -1;
3344
0
    }
3345
0
    this->GlobalGenerator->Generate();
3346
0
    if (this->Instrumentation->HasQuery()) {
3347
0
      this->Instrumentation->WriteCMakeContent(this->GlobalGenerator);
3348
0
    }
3349
0
    return 0;
3350
0
  };
3351
3352
0
  int ret = this->Instrumentation->InstrumentCommand(
3353
0
    "generate", this->cmdArgs,
3354
0
    [doGenerate]() -> cmInstrumentation::CommandResult {
3355
0
      return { doGenerate(), cm::nullopt, cm::nullopt, cm::nullopt };
3356
0
    });
3357
0
  if (ret != 0) {
3358
0
    return ret;
3359
0
  }
3360
#else
3361
  if (!this->GlobalGenerator->Compute()) {
3362
    return -1;
3363
  }
3364
  this->GlobalGenerator->Generate();
3365
#endif
3366
  // Do not keep the parse trees alive after generation, e.g. while
3367
  // cmake-gui waits for the next configure.
3368
0
  this->GeneratorExpressionParseCache->Clear();
3369
0
  auto endTime = std::chrono::steady_clock::now();
3370
0
  {
3371
0
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(endTime -
3372
0
                                                                    startTime);
3373
0
    std::string msg;
3374
0
    msg.resize(128);
3375
    // NOLINTNEXTLINE(readability-container-data-pointer)
3376
0
    msg.resize(snprintf(&msg[0], msg.size(), "Generating done (%.1fs)",
3377
0
                        static_cast<double>(ms.count()) * 1e-3));
3378
0
    this->UpdateProgress(msg, -1);
3379
0
  }
3380
0
  if (!this->GraphVizFile.empty()) {
3381
0
    std::cout << "Generate graphviz: " << this->GraphVizFile << '\n';
3382
0
    this->GenerateGraphViz(this->GraphVizFile);
3383
0
  }
3384
0
  this->RunCheckForUnusedVariables();
3385
0
  if (cmSystemTools::GetErrorOccurredFlag()) {
3386
0
#if !defined(CMAKE_BOOTSTRAP)
3387
0
    this->FileAPI->WriteReplies(cmFileAPI::IndexFor::FailedGenerate);
3388
0
#endif
3389
0
    return -1;
3390
0
  }
3391
  // Save the cache again after a successful Generate so that any internal
3392
  // variables created during Generate are saved. (Specifically target GUIDs
3393
  // for the Visual Studio and Xcode generators.)
3394
0
  this->SaveCache(this->GetHomeOutputDirectory());
3395
3396
0
#if !defined(CMAKE_BOOTSTRAP)
3397
0
  this->GlobalGenerator->WriteInstallJson();
3398
0
  this->FileAPI->WriteReplies(cmFileAPI::IndexFor::Success);
3399
0
  this->Instrumentation->CollectTimingData(
3400
0
    cmInstrumentationQuery::Hook::PostGenerate);
3401
0
#endif
3402
3403
0
  return 0;
3404
0
}
3405
3406
void cmake::AddCacheEntry(std::string const& key, cmValue value,
3407
                          cmValue helpString, int type)
3408
3
{
3409
3
  this->State->AddCacheEntry(key, value, helpString,
3410
3
                             static_cast<cmStateEnums::CacheEntryType>(type));
3411
3
  this->UnwatchUnusedCli(key);
3412
3
}
3413
3414
bool cmake::DoWriteGlobVerifyTarget() const
3415
0
{
3416
0
  return this->State->DoWriteGlobVerifyTarget();
3417
0
}
3418
3419
std::string const& cmake::GetGlobVerifyScript() const
3420
0
{
3421
0
  return this->State->GetGlobVerifyScript();
3422
0
}
3423
3424
std::string const& cmake::GetGlobVerifyStamp() const
3425
0
{
3426
0
  return this->State->GetGlobVerifyStamp();
3427
0
}
3428
3429
void cmake::AddGlobCacheEntry(cmGlobCacheEntry const& entry,
3430
                              std::string const& variable,
3431
                              cmListFileBacktrace const& backtrace)
3432
0
{
3433
0
  this->State->AddGlobCacheEntry(entry, variable, backtrace,
3434
0
                                 this->Messenger.get());
3435
0
}
3436
3437
std::vector<cmGlobCacheEntry> cmake::GetGlobCacheEntries() const
3438
0
{
3439
0
  return this->State->GetGlobCacheEntries();
3440
0
}
3441
3442
std::vector<std::string> cmake::GetAllExtensions() const
3443
725
{
3444
725
  std::vector<std::string> allExt = this->CLikeSourceFileExtensions.ordered;
3445
725
  allExt.insert(allExt.end(), this->HeaderFileExtensions.ordered.begin(),
3446
725
                this->HeaderFileExtensions.ordered.end());
3447
  // cuda extensions are also in SourceFileExtensions so we ignore it here
3448
725
  allExt.insert(allExt.end(), this->FortranFileExtensions.ordered.begin(),
3449
725
                this->FortranFileExtensions.ordered.end());
3450
725
  allExt.insert(allExt.end(), this->HipFileExtensions.ordered.begin(),
3451
725
                this->HipFileExtensions.ordered.end());
3452
725
  allExt.insert(allExt.end(), this->ISPCFileExtensions.ordered.begin(),
3453
725
                this->ISPCFileExtensions.ordered.end());
3454
725
  return allExt;
3455
725
}
3456
3457
std::string cmake::StripExtension(std::string const& file) const
3458
125k
{
3459
125k
  auto dotpos = file.rfind('.');
3460
125k
  if (dotpos != std::string::npos) {
3461
#if defined(_WIN32) || defined(__APPLE__)
3462
    auto ext = cmSystemTools::LowerCase(file.substr(dotpos + 1));
3463
#else
3464
58.3k
    auto ext = cm::string_view(file).substr(dotpos + 1);
3465
58.3k
#endif
3466
58.3k
    if (this->IsAKnownExtension(ext)) {
3467
44.3k
      return file.substr(0, dotpos);
3468
44.3k
    }
3469
58.3k
  }
3470
80.6k
  return file;
3471
125k
}
3472
3473
cmValue cmake::GetCacheDefinition(std::string const& name) const
3474
0
{
3475
0
  return this->State->GetInitializedCacheValue(name);
3476
0
}
3477
3478
void cmake::AddScriptingCommands() const
3479
19.9k
{
3480
19.9k
  GetScriptingCommands(this->GetState());
3481
19.9k
}
3482
3483
void cmake::AddProjectCommands() const
3484
19.8k
{
3485
19.8k
  GetProjectCommands(this->GetState());
3486
19.8k
}
3487
3488
void cmake::AddDefaultGenerators()
3489
19.9k
{
3490
#if defined(_WIN32) && !defined(__CYGWIN__)
3491
#  if !defined(CMAKE_BOOT_MINGW)
3492
  this->Generators.push_back(
3493
    cmGlobalVisualStudioVersionedGenerator::NewFactory18());
3494
  this->Generators.push_back(
3495
    cmGlobalVisualStudioVersionedGenerator::NewFactory17());
3496
  this->Generators.push_back(
3497
    cmGlobalVisualStudioVersionedGenerator::NewFactory16());
3498
  this->Generators.push_back(
3499
    cmGlobalVisualStudioVersionedGenerator::NewFactory15());
3500
  this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory());
3501
  this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory());
3502
  this->Generators.push_back(cmGlobalJOMMakefileGenerator::NewFactory());
3503
#  endif
3504
  this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory());
3505
  this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
3506
#endif
3507
19.9k
#if !defined(CMAKE_BOOTSTRAP)
3508
19.9k
#  if (defined(__linux__) && !defined(__ANDROID__)) || defined(_WIN32)
3509
19.9k
  this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
3510
19.9k
#  endif
3511
19.9k
  this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
3512
19.9k
  this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
3513
19.9k
  this->Generators.push_back(cmGlobalNinjaMultiGenerator::NewFactory());
3514
19.9k
  this->Generators.push_back(cmGlobalFastbuildGenerator::NewFactory());
3515
#elif defined(CMAKE_BOOTSTRAP_NINJA)
3516
  this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
3517
#elif defined(CMAKE_BOOTSTRAP_MAKEFILES)
3518
  this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
3519
#endif
3520
19.9k
#if defined(CMAKE_USE_WMAKE)
3521
19.9k
  this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory());
3522
19.9k
#endif
3523
#ifdef CMAKE_USE_XCODE
3524
  this->Generators.push_back(cmGlobalXCodeGenerator::NewFactory());
3525
#endif
3526
19.9k
}
3527
3528
bool cmake::ParseCacheEntry(std::string const& entry, std::string& var,
3529
                            std::string& value,
3530
                            cmStateEnums::CacheEntryType& type)
3531
0
{
3532
0
  return cmState::ParseCacheEntry(entry, var, value, type);
3533
0
}
3534
3535
int cmake::LoadCache()
3536
0
{
3537
  // could we not read the cache
3538
0
  if (!this->LoadCache(this->GetHomeOutputDirectory())) {
3539
    // if it does exist, but isn't readable then warn the user
3540
0
    std::string cacheFile =
3541
0
      cmStrCat(this->GetHomeOutputDirectory(), "/CMakeCache.txt");
3542
0
    if (cmSystemTools::FileExists(cacheFile)) {
3543
0
      cmSystemTools::Error(
3544
0
        "There is a CMakeCache.txt file for the current binary tree but "
3545
0
        "cmake does not have permission to read it. Please check the "
3546
0
        "permissions of the directory you are trying to run CMake on.");
3547
0
      return -1;
3548
0
    }
3549
0
  }
3550
3551
  // setup CMAKE_ROOT and CMAKE_COMMAND
3552
0
  if (!this->AddCMakePaths()) {
3553
0
    return -3;
3554
0
  }
3555
0
  return 0;
3556
0
}
3557
3558
bool cmake::LoadCache(std::string const& path)
3559
0
{
3560
0
  std::set<std::string> emptySet;
3561
0
  return this->LoadCache(path, true, emptySet, emptySet);
3562
0
}
3563
3564
bool cmake::LoadCache(std::string const& path, bool internal,
3565
                      std::set<std::string>& excludes,
3566
                      std::set<std::string>& includes)
3567
0
{
3568
0
  bool result = this->State->LoadCache(path, internal, excludes, includes);
3569
0
  static auto const entries = { "CMAKE_CACHE_MAJOR_VERSION",
3570
0
                                "CMAKE_CACHE_MINOR_VERSION" };
3571
0
  for (auto const& entry : entries) {
3572
0
    this->UnwatchUnusedCli(entry);
3573
0
  }
3574
0
  return result;
3575
0
}
3576
3577
bool cmake::SaveCache(std::string const& path)
3578
0
{
3579
0
  bool result = this->State->SaveCache(path, this->GetMessenger());
3580
0
  static auto const entries = { "CMAKE_CACHE_MAJOR_VERSION",
3581
0
                                "CMAKE_CACHE_MINOR_VERSION",
3582
0
                                "CMAKE_CACHE_PATCH_VERSION",
3583
0
                                "CMAKE_CACHEFILE_DIR" };
3584
0
  for (auto const& entry : entries) {
3585
0
    this->UnwatchUnusedCli(entry);
3586
0
  }
3587
0
  return result;
3588
0
}
3589
3590
bool cmake::DeleteCache(std::string const& path)
3591
0
{
3592
0
  return this->State->DeleteCache(path);
3593
0
}
3594
3595
void cmake::SetProgressCallback(ProgressCallbackType f)
3596
0
{
3597
0
  this->ProgressCallback = std::move(f);
3598
0
}
3599
3600
void cmake::UpdateProgress(std::string const& msg, float prog)
3601
5.92k
{
3602
5.92k
  if (this->ProgressCallback && !this->GetIsInTryCompile()) {
3603
0
    this->ProgressCallback(msg, prog);
3604
0
  }
3605
5.92k
}
3606
3607
bool cmake::GetIsInTryCompile() const
3608
0
{
3609
0
  return this->State->GetIsTryCompile() == cmState::TryCompile::Yes;
3610
0
}
3611
3612
void cmake::AppendGlobalGeneratorsDocumentation(
3613
  std::vector<cmDocumentationEntry>& v)
3614
0
{
3615
0
  auto const defaultGenerator = this->EvaluateDefaultGlobalGenerator();
3616
0
  auto const defaultName = defaultGenerator->GetName();
3617
0
  auto foundDefaultOne = false;
3618
3619
0
  for (auto const& g : this->Generators) {
3620
0
    v.emplace_back(g->GetDocumentation());
3621
0
    if (!foundDefaultOne && cmHasPrefix(v.back().Name, defaultName)) {
3622
0
      v.back().CustomNamePrefix = '*';
3623
0
      foundDefaultOne = true;
3624
0
    }
3625
0
  }
3626
0
}
3627
3628
void cmake::AppendExtraGeneratorsDocumentation(
3629
  std::vector<cmDocumentationEntry>& v)
3630
0
{
3631
0
  for (cmExternalMakefileProjectGeneratorFactory* eg : this->ExtraGenerators) {
3632
0
    std::string const doc = eg->GetDocumentation();
3633
0
    std::string const name = eg->GetName();
3634
3635
    // Aliases:
3636
0
    for (std::string const& a : eg->Aliases) {
3637
0
      v.emplace_back(cmDocumentationEntry{ a, doc });
3638
0
    }
3639
3640
    // Full names:
3641
0
    for (std::string const& g : eg->GetSupportedGlobalGenerators()) {
3642
0
      v.emplace_back(cmDocumentationEntry{
3643
0
        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name),
3644
0
        doc });
3645
0
    }
3646
0
  }
3647
0
}
3648
3649
std::vector<cmDocumentationEntry> cmake::GetGeneratorsDocumentation()
3650
0
{
3651
0
  std::vector<cmDocumentationEntry> v;
3652
0
  this->AppendGlobalGeneratorsDocumentation(v);
3653
0
  this->AppendExtraGeneratorsDocumentation(v);
3654
0
  return v;
3655
0
}
3656
3657
void cmake::PrintGeneratorList()
3658
0
{
3659
0
#ifndef CMAKE_BOOTSTRAP
3660
0
  cmDocumentation doc;
3661
0
  auto generators = this->GetGeneratorsDocumentation();
3662
0
  doc.AppendSection("Generators", generators);
3663
0
  std::cerr << '\n';
3664
0
  doc.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr);
3665
0
#endif
3666
0
}
3667
3668
int cmake::CheckBuildSystem()
3669
0
{
3670
  // We do not need to rerun CMake.  Check dependency integrity.
3671
0
  bool const verbose = isCMakeVerbose();
3672
3673
  // This method will check the integrity of the build system if the
3674
  // option was given on the command line.  It reads the given file to
3675
  // determine whether CMake should rerun.
3676
3677
  // If no file is provided for the check, we have to rerun.
3678
0
  if (this->CheckBuildSystemArgument.empty()) {
3679
0
    if (verbose) {
3680
0
      cmSystemTools::Stdout("Re-run cmake no build system arguments\n");
3681
0
    }
3682
0
    return 1;
3683
0
  }
3684
3685
  // If the file provided does not exist, we have to rerun.
3686
0
  if (!cmSystemTools::FileExists(this->CheckBuildSystemArgument)) {
3687
0
    if (verbose) {
3688
0
      std::string msg = cmStrCat(
3689
0
        "Re-run cmake missing file: ", this->CheckBuildSystemArgument, '\n');
3690
0
      cmSystemTools::Stdout(msg);
3691
0
    }
3692
0
    return 1;
3693
0
  }
3694
3695
  // Read the rerun check file and use it to decide whether to do the
3696
  // global generate.
3697
  // Actually, all we need is the `set` command.
3698
0
  cmake cm(cmState::Role::Script);
3699
0
  cm.GetCurrentSnapshot().SetDefaultDefinitions();
3700
0
  cmGlobalGenerator gg(&cm);
3701
0
  cmMakefile mf(&gg, cm.GetCurrentSnapshot());
3702
0
  if (!mf.ReadListFile(this->CheckBuildSystemArgument) ||
3703
0
      cmSystemTools::GetErrorOccurredFlag()) {
3704
0
    if (verbose) {
3705
0
      std::string msg = cmStrCat(
3706
0
        "Re-run cmake error reading : ", this->CheckBuildSystemArgument, '\n');
3707
0
      cmSystemTools::Stdout(msg);
3708
0
    }
3709
    // There was an error reading the file.  Just rerun.
3710
0
    return 1;
3711
0
  }
3712
3713
0
  if (this->ClearBuildSystem) {
3714
    // Get the generator used for this build system.
3715
0
    std::string genName = mf.GetSafeDefinition("CMAKE_DEPENDS_GENERATOR");
3716
0
    if (!cmNonempty(genName)) {
3717
0
      genName = "Unix Makefiles";
3718
0
    }
3719
3720
    // Create the generator and use it to clear the dependencies.
3721
0
    std::unique_ptr<cmGlobalGenerator> ggd =
3722
0
      this->CreateGlobalGenerator(genName);
3723
0
    if (ggd) {
3724
0
      cm.GetCurrentSnapshot().SetDefaultDefinitions();
3725
0
      cmMakefile mfd(ggd.get(), cm.GetCurrentSnapshot());
3726
0
      auto lgd = ggd->CreateLocalGenerator(&mfd);
3727
0
      lgd->ClearDependencies(&mfd, verbose);
3728
0
    }
3729
0
  }
3730
3731
  // If any byproduct of makefile generation is missing we must re-run.
3732
0
  cmList products{ mf.GetDefinition("CMAKE_MAKEFILE_PRODUCTS") };
3733
0
  for (auto const& p : products) {
3734
0
    if (!cmSystemTools::PathExists(p)) {
3735
0
      if (verbose) {
3736
0
        cmSystemTools::Stdout(
3737
0
          cmStrCat("Re-run cmake, missing byproduct: ", p, '\n'));
3738
0
      }
3739
0
      return 1;
3740
0
    }
3741
0
  }
3742
3743
  // Get the set of dependencies and outputs.
3744
0
  cmList depends{ mf.GetDefinition("CMAKE_MAKEFILE_DEPENDS") };
3745
0
  cmList outputs;
3746
0
  if (!depends.empty()) {
3747
0
    outputs.assign(mf.GetDefinition("CMAKE_MAKEFILE_OUTPUTS"));
3748
0
  }
3749
0
  if (depends.empty() || outputs.empty()) {
3750
    // Not enough information was provided to do the test.  Just rerun.
3751
0
    if (verbose) {
3752
0
      cmSystemTools::Stdout("Re-run cmake no CMAKE_MAKEFILE_DEPENDS "
3753
0
                            "or CMAKE_MAKEFILE_OUTPUTS :\n");
3754
0
    }
3755
0
    return 1;
3756
0
  }
3757
3758
  // Find the newest dependency.
3759
0
  auto dep = depends.begin();
3760
0
  std::string dep_newest = *dep++;
3761
0
  for (; dep != depends.end(); ++dep) {
3762
0
    int result = 0;
3763
0
    if (this->FileTimeCache->Compare(dep_newest, *dep, &result)) {
3764
0
      if (result < 0) {
3765
0
        dep_newest = *dep;
3766
0
      }
3767
0
    } else {
3768
0
      if (verbose) {
3769
0
        cmSystemTools::Stdout(
3770
0
          "Re-run cmake: build system dependency is missing\n");
3771
0
      }
3772
0
      return 1;
3773
0
    }
3774
0
  }
3775
3776
  // Find the oldest output.
3777
0
  auto out = outputs.begin();
3778
0
  std::string out_oldest = *out++;
3779
0
  for (; out != outputs.end(); ++out) {
3780
0
    int result = 0;
3781
0
    if (this->FileTimeCache->Compare(out_oldest, *out, &result)) {
3782
0
      if (result > 0) {
3783
0
        out_oldest = *out;
3784
0
      }
3785
0
    } else {
3786
0
      if (verbose) {
3787
0
        cmSystemTools::Stdout(
3788
0
          "Re-run cmake: build system output is missing\n");
3789
0
      }
3790
0
      return 1;
3791
0
    }
3792
0
  }
3793
3794
  // If any output is older than any dependency then rerun.
3795
0
  {
3796
0
    int result = 0;
3797
0
    if (!this->FileTimeCache->Compare(out_oldest, dep_newest, &result) ||
3798
0
        result < 0) {
3799
0
      if (verbose) {
3800
0
        std::string msg = cmStrCat("Re-run cmake file: ", out_oldest,
3801
0
                                   " older than: ", dep_newest, '\n');
3802
0
        cmSystemTools::Stdout(msg);
3803
0
      }
3804
0
      return 1;
3805
0
    }
3806
0
  }
3807
3808
  // No need to rerun.
3809
0
  return 0;
3810
0
}
3811
3812
void cmake::TruncateOutputLog(char const* fname)
3813
0
{
3814
0
  std::string fullPath = cmStrCat(this->GetHomeOutputDirectory(), '/', fname);
3815
0
  struct stat st;
3816
0
  if (::stat(fullPath.c_str(), &st)) {
3817
0
    return;
3818
0
  }
3819
0
  if (!this->State->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) {
3820
0
    cmSystemTools::RemoveFile(fullPath);
3821
0
    return;
3822
0
  }
3823
0
  off_t fsize = st.st_size;
3824
0
  off_t const maxFileSize = 50 * 1024;
3825
0
  if (fsize < maxFileSize) {
3826
    // TODO: truncate file
3827
0
    return;
3828
0
  }
3829
0
}
3830
3831
void cmake::MarkCliAsUsed(std::string const& variable)
3832
0
{
3833
0
  this->UsedCliVariables[variable] = true;
3834
0
}
3835
3836
void cmake::GenerateGraphViz(std::string const& fileName) const
3837
0
{
3838
0
#ifndef CMAKE_BOOTSTRAP
3839
0
  cmGraphVizWriter gvWriter(fileName, this->GetGlobalGenerator());
3840
3841
0
  std::string settingsFile =
3842
0
    cmStrCat(this->GetHomeOutputDirectory(), "/CMakeGraphVizOptions.cmake");
3843
0
  std::string fallbackSettingsFile =
3844
0
    cmStrCat(this->GetHomeDirectory(), "/CMakeGraphVizOptions.cmake");
3845
3846
0
  gvWriter.ReadSettings(settingsFile, fallbackSettingsFile);
3847
3848
0
  gvWriter.Write();
3849
3850
0
#endif
3851
0
}
3852
3853
void cmake::SetProperty(std::string const& prop, cmValue value)
3854
11.8k
{
3855
11.8k
  this->State->SetGlobalProperty(prop, value);
3856
11.8k
}
3857
3858
void cmake::AppendProperty(std::string const& prop, std::string const& value,
3859
                           bool asString)
3860
0
{
3861
0
  this->State->AppendGlobalProperty(prop, value, asString);
3862
0
}
3863
3864
cmValue cmake::GetProperty(std::string const& prop)
3865
0
{
3866
0
  return this->State->GetGlobalProperty(prop);
3867
0
}
3868
3869
bool cmake::GetPropertyAsBool(std::string const& prop)
3870
0
{
3871
0
  return this->State->GetGlobalPropertyAsBool(prop);
3872
0
}
3873
3874
cmInstalledFile* cmake::GetOrCreateInstalledFile(cmMakefile* mf,
3875
                                                 std::string const& name)
3876
0
{
3877
0
  auto i = this->InstalledFiles.find(name);
3878
3879
0
  if (i != this->InstalledFiles.end()) {
3880
0
    cmInstalledFile& file = i->second;
3881
0
    return &file;
3882
0
  }
3883
0
  cmInstalledFile& file = this->InstalledFiles[name];
3884
0
  file.SetName(mf, name);
3885
0
  return &file;
3886
0
}
3887
3888
cmInstalledFile const* cmake::GetInstalledFile(std::string const& name) const
3889
0
{
3890
0
  auto i = this->InstalledFiles.find(name);
3891
3892
0
  if (i != this->InstalledFiles.end()) {
3893
0
    cmInstalledFile const& file = i->second;
3894
0
    return &file;
3895
0
  }
3896
0
  return nullptr;
3897
0
}
3898
3899
int cmake::GetSystemInformation(std::vector<std::string>& args)
3900
0
{
3901
  // so create the directory
3902
0
  std::string resultFile;
3903
0
  std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
3904
0
  std::string destPath = cwd + "/__cmake_systeminformation";
3905
0
  cmSystemTools::RemoveADirectory(destPath);
3906
0
  if (!cmSystemTools::MakeDirectory(destPath)) {
3907
0
    std::cerr << "Error: --system-information must be run from a "
3908
0
                 "writable directory!\n";
3909
0
    return 1;
3910
0
  }
3911
3912
  // process the arguments
3913
0
  bool writeToStdout = true;
3914
0
  for (unsigned int i = 1; i < args.size(); ++i) {
3915
0
    std::string const& arg = args[i];
3916
0
    if (cmHasLiteralPrefix(arg, "-G")) {
3917
0
      std::string value = arg.substr(2);
3918
0
      if (value.empty()) {
3919
0
        ++i;
3920
0
        if (i >= args.size()) {
3921
0
          cmSystemTools::Error("No generator specified for -G");
3922
0
          this->PrintGeneratorList();
3923
0
          return -1;
3924
0
        }
3925
0
        value = args[i];
3926
0
      }
3927
0
      auto gen = this->CreateGlobalGenerator(value);
3928
0
      if (!gen) {
3929
0
        cmSystemTools::Error("Could not create named generator " + value);
3930
0
        this->PrintGeneratorList();
3931
0
      } else {
3932
0
        this->SetGlobalGenerator(std::move(gen));
3933
0
      }
3934
0
    }
3935
    // no option assume it is the output file
3936
0
    else {
3937
0
      if (!cmSystemTools::FileIsFullPath(arg)) {
3938
0
        resultFile = cmStrCat(cwd, '/');
3939
0
      }
3940
0
      resultFile += arg;
3941
0
      writeToStdout = false;
3942
0
    }
3943
0
  }
3944
3945
  // we have to find the module directory, so we can copy the files
3946
0
  this->AddCMakePaths();
3947
0
  std::string modulesPath =
3948
0
    cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules");
3949
0
  std::string inFile = cmStrCat(modulesPath, "/SystemInformation.cmake");
3950
0
  std::string outFile = cmStrCat(destPath, "/CMakeLists.txt");
3951
3952
  // Copy file
3953
0
  if (!cmsys::SystemTools::CopyFileAlways(inFile, outFile)) {
3954
0
    std::cerr << "Error copying file \"" << inFile << "\" to \"" << outFile
3955
0
              << "\".\n";
3956
0
    return 1;
3957
0
  }
3958
3959
  // do we write to a file or to stdout?
3960
0
  if (resultFile.empty()) {
3961
0
    resultFile = cmStrCat(cwd, "/__cmake_systeminformation/results.txt");
3962
0
  }
3963
3964
0
  {
3965
    // now run cmake on the CMakeLists file
3966
0
    cmWorkingDirectory workdir(destPath);
3967
0
    if (workdir.Failed()) {
3968
      // We created the directory and we were able to copy the CMakeLists.txt
3969
      // file to it, so we wouldn't expect to get here unless the default
3970
      // permissions are questionable or some other process has deleted the
3971
      // directory
3972
0
      std::cerr << workdir.GetError() << '\n';
3973
0
      return 1;
3974
0
    }
3975
0
    std::vector<std::string> args2;
3976
0
    args2.reserve(3);
3977
0
    args2.emplace_back(args[0]);
3978
0
    args2.emplace_back(destPath);
3979
0
    args2.emplace_back("-DRESULT_FILE=" + resultFile);
3980
0
    int res = this->Run(args2, false);
3981
3982
0
    if (res != 0) {
3983
0
      std::cerr << "Error: --system-information failed on internal CMake!\n";
3984
0
      return res;
3985
0
    }
3986
0
  }
3987
3988
  // echo results to stdout if needed
3989
0
  if (writeToStdout) {
3990
0
    FILE* fin = cmsys::SystemTools::Fopen(resultFile, "r");
3991
0
    if (fin) {
3992
0
      int const bufferSize = 4096;
3993
0
      char buffer[bufferSize];
3994
0
      size_t n;
3995
0
      while ((n = fread(buffer, 1, bufferSize, fin)) > 0) {
3996
0
        for (char* c = buffer; c < buffer + n; ++c) {
3997
0
          putc(*c, stdout);
3998
0
        }
3999
0
        fflush(stdout);
4000
0
      }
4001
0
      fclose(fin);
4002
0
    }
4003
0
  }
4004
4005
  // clean up the directory
4006
0
  cmSystemTools::RemoveADirectory(destPath);
4007
0
  return 0;
4008
0
}
4009
4010
void cmake::IssueMessage(MessageType t, std::string const& text,
4011
                         cmListFileBacktrace const& backtrace) const
4012
37.2k
{
4013
37.2k
  this->Messenger->IssueMessage(t, text, backtrace);
4014
37.2k
}
4015
4016
void cmake::IssueDiagnostic(cmDiagnosticCategory category,
4017
                            std::string const& text,
4018
                            cmStateSnapshot const& state,
4019
                            cmDiagnosticContext const& context) const
4020
0
{
4021
0
  this->Messenger->IssueDiagnostic(category, text, state, context);
4022
0
}
4023
4024
std::vector<std::string> cmake::GetDebugConfigs()
4025
8.58k
{
4026
8.58k
  cmList configs;
4027
8.58k
  if (cmValue config_list =
4028
8.58k
        this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) {
4029
    // Expand the specified list and convert to upper-case.
4030
0
    configs.assign(*config_list);
4031
0
    configs.transform(cmList::TransformAction::TOUPPER);
4032
0
  }
4033
  // If no configurations were specified, use a default list.
4034
8.58k
  if (configs.empty()) {
4035
8.58k
    configs.emplace_back("DEBUG");
4036
8.58k
  }
4037
8.58k
  return std::move(configs.data());
4038
8.58k
}
4039
4040
int cmake::Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
4041
                 std::vector<std::string> nativeOptions,
4042
                 cmBuildOptions& buildOptions,
4043
                 cmCMakePresetsArgs const& presetsArgs,
4044
                 std::vector<std::string> const& args)
4045
0
{
4046
0
  buildArgs.timeout = cmDuration::zero();
4047
4048
0
#if !defined(CMAKE_BOOTSTRAP)
4049
0
  if (presetsArgs.HasPresetsArg()) {
4050
    // If the binary directory was specified, use it to find
4051
    // the source directory so we can locate the presets file.
4052
0
    if (!buildArgs.binaryDir.empty() &&
4053
0
        this->SetDirectoriesFromFile(buildArgs.binaryDir)) {
4054
      // HomeDirectory is now the source directory (found in CMakeCache.txt)
4055
0
    } else {
4056
      // Otherwise we assume this command was called from the source directory.
4057
0
      this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
4058
0
      this->SetHomeOutputDirectory(
4059
0
        cmSystemTools::GetLogicalWorkingDirectory());
4060
0
    }
4061
0
    cmCMakePresetsGraph settingsFile;
4062
0
    auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory(),
4063
0
                                                  presetsArgs.PresetsFile);
4064
0
    if (result != true) {
4065
0
      cmSystemTools::Error(
4066
0
        cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
4067
0
                 ":\n", settingsFile.parseState.GetErrorMessage()));
4068
0
      return 1;
4069
0
    }
4070
4071
0
    if (presetsArgs.ListPresetsMode) {
4072
0
      auto configureUsabilityCheck =
4073
0
        this->CreateConfigurePresetUsabilityCheck();
4074
0
      settingsFile.PrintBuildPresetList(*presetsArgs.ListPresetsMode,
4075
0
                                        configureUsabilityCheck);
4076
0
      return 0;
4077
0
    }
4078
4079
0
    auto resolveResult = settingsFile.ResolvePreset(presetsArgs.PresetName,
4080
0
                                                    settingsFile.BuildPresets);
4081
0
    auto resolveError =
4082
0
      cmCMakePresetsGraph::FormatPresetError<cmCMakePresetsGraph::BuildPreset>(
4083
0
        resolveResult.StatusCode, resolveResult.ErrorPresetName,
4084
0
        this->GetHomeDirectory());
4085
0
    if (resolveError) {
4086
0
      cmSystemTools::Error(*resolveError);
4087
0
      settingsFile.PrintBuildPresetList();
4088
0
      return 1;
4089
0
    }
4090
0
    auto const* expandedPreset = resolveResult.Preset;
4091
4092
0
    auto configurePresetPair =
4093
0
      settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
4094
0
    if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
4095
0
      cmSystemTools::Error(cmStrCat("No such configure preset in ",
4096
0
                                    this->GetHomeDirectory(), ": \"",
4097
0
                                    expandedPreset->ConfigurePreset, '"'));
4098
0
      this->PrintPresetList(settingsFile);
4099
0
      return 1;
4100
0
    }
4101
4102
0
    if (configurePresetPair->second.Unexpanded.Hidden) {
4103
0
      cmSystemTools::Error(cmStrCat("Cannot use hidden configure preset in ",
4104
0
                                    this->GetHomeDirectory(), ": \"",
4105
0
                                    expandedPreset->ConfigurePreset, '"'));
4106
0
      this->PrintPresetList(settingsFile);
4107
0
      return 1;
4108
0
    }
4109
4110
0
    auto const& expandedConfigurePreset = configurePresetPair->second.Expanded;
4111
0
    if (!expandedConfigurePreset) {
4112
0
      cmSystemTools::Error(cmStrCat("Could not evaluate configure preset \"",
4113
0
                                    expandedPreset->ConfigurePreset,
4114
0
                                    "\": Invalid macro expansion"));
4115
0
      return 1;
4116
0
    }
4117
4118
0
    if (buildArgs.binaryDir.empty() &&
4119
0
        !expandedConfigurePreset->BinaryDir.empty()) {
4120
0
      buildArgs.binaryDir = expandedConfigurePreset->BinaryDir;
4121
0
    }
4122
4123
0
    this->UnprocessedPresetEnvironment = expandedPreset->Environment;
4124
0
    this->ProcessPresetEnvironment();
4125
4126
0
    if ((buildArgs.jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL ||
4127
0
         buildArgs.jobs == cmake::NO_BUILD_PARALLEL_LEVEL) &&
4128
0
        expandedPreset->Jobs) {
4129
0
      if (*expandedPreset->Jobs > static_cast<unsigned int>(INT_MAX)) {
4130
0
        cmSystemTools::Error(
4131
0
          "The build preset \"jobs\" value is too large.\n");
4132
0
        return 1;
4133
0
      }
4134
0
      buildArgs.jobs = *expandedPreset->Jobs;
4135
0
    }
4136
4137
0
    if (targets.empty()) {
4138
0
      targets.insert(targets.begin(), expandedPreset->Targets.begin(),
4139
0
                     expandedPreset->Targets.end());
4140
0
    }
4141
4142
0
    if (buildArgs.config.empty()) {
4143
0
      buildArgs.config = expandedPreset->Configuration;
4144
0
    }
4145
4146
0
    if (!buildOptions.Clean && expandedPreset->CleanFirst) {
4147
0
      buildOptions.Clean = *expandedPreset->CleanFirst;
4148
0
    }
4149
4150
0
    if (buildOptions.ResolveMode == PackageResolveMode::Default &&
4151
0
        expandedPreset->ResolvePackageReferences) {
4152
0
      buildOptions.ResolveMode = *expandedPreset->ResolvePackageReferences;
4153
0
    }
4154
4155
0
    if (!buildArgs.verbose && expandedPreset->Verbose) {
4156
0
      buildArgs.verbose = *expandedPreset->Verbose;
4157
0
    }
4158
4159
0
    if (nativeOptions.empty()) {
4160
0
      nativeOptions.insert(nativeOptions.begin(),
4161
0
                           expandedPreset->NativeToolOptions.begin(),
4162
0
                           expandedPreset->NativeToolOptions.end());
4163
0
    }
4164
0
  }
4165
0
#endif
4166
4167
0
  if (!cmSystemTools::FileIsDirectory(buildArgs.binaryDir)) {
4168
0
    std::cerr << "Error: " << buildArgs.binaryDir << " is not a directory\n";
4169
0
    return 1;
4170
0
  }
4171
4172
0
  std::string cachePath = FindCacheFile(buildArgs.binaryDir);
4173
0
  if (!this->LoadCache(cachePath)) {
4174
0
    std::cerr
4175
0
      << "Error: not a CMake build directory (missing CMakeCache.txt)\n";
4176
0
    return 1;
4177
0
  }
4178
0
  cmValue cachedGenerator = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
4179
0
  if (!cachedGenerator) {
4180
0
    std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
4181
0
    return 1;
4182
0
  }
4183
0
  auto gen = this->CreateGlobalGenerator(*cachedGenerator);
4184
0
  if (!gen) {
4185
0
    std::cerr << "Error: could not create CMAKE_GENERATOR \""
4186
0
              << *cachedGenerator << "\"\n";
4187
0
    return 1;
4188
0
  }
4189
0
  this->SetGlobalGenerator(std::move(gen));
4190
0
  cmValue cachedGeneratorInstance =
4191
0
    this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE");
4192
0
  if (cachedGeneratorInstance) {
4193
0
    cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
4194
0
    if (!this->GlobalGenerator->SetGeneratorInstance(*cachedGeneratorInstance,
4195
0
                                                     &mf)) {
4196
0
      return 1;
4197
0
    }
4198
0
  }
4199
0
  cmValue cachedGeneratorPlatform =
4200
0
    this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
4201
0
  if (cachedGeneratorPlatform) {
4202
0
    cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
4203
0
    if (!this->GlobalGenerator->SetGeneratorPlatform(*cachedGeneratorPlatform,
4204
0
                                                     &mf)) {
4205
0
      return 1;
4206
0
    }
4207
0
  }
4208
0
  cmValue cachedGeneratorToolset =
4209
0
    this->State->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
4210
0
  if (cachedGeneratorToolset) {
4211
0
    cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
4212
0
    if (!this->GlobalGenerator->SetGeneratorToolset(*cachedGeneratorToolset,
4213
0
                                                    true, &mf)) {
4214
0
      return 1;
4215
0
    }
4216
0
  }
4217
0
  cmValue cachedProjectName =
4218
0
    this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
4219
0
  if (!cachedProjectName) {
4220
0
    std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
4221
0
    return 1;
4222
0
  }
4223
0
  buildArgs.projectName = *cachedProjectName;
4224
4225
0
  if (this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE").IsOn()) {
4226
0
    buildArgs.verbose = true;
4227
0
  }
4228
4229
#ifdef CMAKE_HAVE_VS_GENERATORS
4230
  // For VS generators, explicitly check if regeneration is necessary before
4231
  // actually starting the build. If not done separately from the build
4232
  // itself, there is the risk of building an out-of-date solution file due
4233
  // to limitations of the underlying build system.
4234
  std::string const stampList =
4235
    cmStrCat(cachePath, "/CMakeFiles/",
4236
             cmGlobalVisualStudioVersionedGenerator::GetGenerateStampList());
4237
4238
  // Note that the stampList file only exists for VS generators.
4239
  if (cmSystemTools::FileExists(stampList) &&
4240
      !cmakeCheckStampList(stampList)) {
4241
    // Upgrade cmake role from --build to reconfigure the project.
4242
    this->State->SetRoleToProjectForCMakeBuildVsReconfigure();
4243
    this->AddScriptingCommands();
4244
    this->AddProjectCommands();
4245
4246
    // Correctly initialize the home (=source) and home output (=binary)
4247
    // directories, which is required for running the generation step.
4248
    this->SetDirectoriesFromFile(cachePath);
4249
4250
    int ret = this->Configure();
4251
    if (ret) {
4252
      cmSystemTools::Message("CMake Configure step failed.  "
4253
                             "Build files cannot be regenerated correctly.");
4254
      return ret;
4255
    }
4256
    ret = this->Generate();
4257
    if (ret) {
4258
      cmSystemTools::Message("CMake Generate step failed.  "
4259
                             "Build files cannot be regenerated correctly.");
4260
      return ret;
4261
    }
4262
    std::string message = cmStrCat("Build files have been written to: ",
4263
                                   this->GetHomeOutputDirectory());
4264
    this->UpdateProgress(message, -1);
4265
  }
4266
#endif
4267
4268
0
  if (!this->GlobalGenerator->ReadCacheEntriesForBuild(*this->State)) {
4269
0
    return 1;
4270
0
  }
4271
4272
0
#if !defined(CMAKE_BOOTSTRAP)
4273
0
  cmInstrumentation instrumentation(buildArgs.binaryDir);
4274
0
  if (instrumentation.HasErrors()) {
4275
0
    return 1;
4276
0
  }
4277
0
  instrumentation.CollectTimingData(
4278
0
    cmInstrumentationQuery::Hook::PreCMakeBuild);
4279
0
#endif
4280
4281
0
  this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, buildArgs.jobs);
4282
0
  std::stringstream ostr;
4283
  // `cmGlobalGenerator::Build` logs metadata about what directory and commands
4284
  // are being executed to the `output` parameter. If CMake is verbose, print
4285
  // this out.
4286
0
  std::ostream& verbose_ostr = buildArgs.verbose ? std::cout : ostr;
4287
0
  auto doBuild = [this, targets, &verbose_ostr, buildOptions, buildArgs,
4288
0
                  nativeOptions]() -> int {
4289
0
    return this->GlobalGenerator->Build(
4290
0
      buildArgs, targets, verbose_ostr, "", buildArgs.config, buildOptions,
4291
0
      buildArgs.timeout, cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
4292
0
  };
4293
4294
0
#if !defined(CMAKE_BOOTSTRAP)
4295
  // Block the instrumentation build daemon from spawning during this build.
4296
  // This lock will be released when the process exits at the end of the build.
4297
0
  instrumentation.LockBuildDaemon();
4298
  // Run the build under an interrupt handler so that a user interrupt (e.g.
4299
  // Ctrl+C) still writes the overall `cmakeBuild` snippet before we exit.
4300
0
  cmInstrumentationInterrupt::InterruptOutcome buildOutcome =
4301
0
    cmInstrumentationInterrupt::HandleInterrupt(
4302
0
      instrumentation.HasQuery(),
4303
0
      [&instrumentation, &args, &doBuild]() -> int {
4304
0
        return instrumentation.InstrumentCommand(
4305
0
          "cmakeBuild", args,
4306
0
          [&doBuild]() -> cmInstrumentation::CommandResult {
4307
0
            return { doBuild(), cm::nullopt, cm::nullopt, cm::nullopt };
4308
0
          });
4309
0
      });
4310
0
  int buildresult = buildOutcome.ExitCode;
4311
0
  if (buildOutcome.Interrupted) {
4312
    // The build was interrupted and its snippet has been written.  Skip the
4313
    // post-build indexing hook (which would run callbacks and delete data).
4314
    // For a real OS interrupt, re-raise so the exit status reflects it; for a
4315
    // test-injected interrupt, exit cleanly.  The next indexing run will
4316
    // reclaim the snippet written above.
4317
0
    if (buildOutcome.ShouldRaise) {
4318
0
      cmInstrumentationInterrupt::RaiseInterrupt(buildOutcome.Signal);
4319
0
    }
4320
0
    return buildresult;
4321
0
  }
4322
0
  instrumentation.CollectTimingData(
4323
0
    cmInstrumentationQuery::Hook::PostCMakeBuild);
4324
#else
4325
  int buildresult = doBuild();
4326
#endif
4327
4328
0
  return buildresult;
4329
0
}
4330
4331
bool cmake::Open(std::string const& dir, DryRun dryRun)
4332
0
{
4333
0
  if (!cmSystemTools::FileIsDirectory(dir)) {
4334
0
    if (dryRun == DryRun::No) {
4335
0
      std::cerr << "Error: " << dir << " is not a directory\n";
4336
0
    }
4337
0
    return false;
4338
0
  }
4339
4340
0
  std::string cachePath = FindCacheFile(dir);
4341
0
  if (!this->LoadCache(cachePath)) {
4342
0
    std::cerr
4343
0
      << "Error: not a CMake build directory (missing CMakeCache.txt)\n";
4344
0
    return false;
4345
0
  }
4346
0
  cmValue genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
4347
0
  if (!genName) {
4348
0
    std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
4349
0
    return false;
4350
0
  }
4351
0
  cmValue extraGenName =
4352
0
    this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
4353
0
  std::string fullName =
4354
0
    cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
4355
0
      *genName, extraGenName ? *extraGenName : "");
4356
4357
0
  std::unique_ptr<cmGlobalGenerator> gen =
4358
0
    this->CreateGlobalGenerator(fullName);
4359
0
  if (!gen) {
4360
0
    std::cerr << "Error: could not create CMAKE_GENERATOR \"" << fullName
4361
0
              << "\"\n";
4362
0
    return false;
4363
0
  }
4364
4365
0
  cmValue cachedProjectName =
4366
0
    this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
4367
0
  if (!cachedProjectName) {
4368
0
    std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
4369
0
    return false;
4370
0
  }
4371
4372
0
  return gen->Open(dir, *cachedProjectName, dryRun == DryRun::Yes);
4373
0
}
4374
4375
#if !defined(CMAKE_BOOTSTRAP)
4376
namespace {
4377
std::string WorkflowStepLabel(cm::static_string_view type,
4378
                              std::string const& name)
4379
0
{
4380
0
  return cmStrCat("of type \"", type, "\" named \"", name, '"');
4381
0
}
4382
}
4383
4384
template <typename T>
4385
T const* cmake::FindPresetForWorkflow(
4386
  cm::static_string_view type,
4387
  std::map<std::string, cmCMakePresetsGraph::PresetPair<T>> const& presets,
4388
  cmCMakePresetsGraph::WorkflowPreset::WorkflowStep const& step)
4389
0
{
4390
0
  std::string const stepLabel = WorkflowStepLabel(type, step.PresetName);
4391
0
  auto it = presets.find(step.PresetName);
4392
0
  if (it == presets.end()) {
4393
0
    cmSystemTools::Error(cmStrCat("No such preset for workflow step ",
4394
0
                                  stepLabel, " in ",
4395
0
                                  this->GetHomeDirectory()));
4396
0
    return nullptr;
4397
0
  }
4398
4399
0
  if (it->second.Unexpanded.Hidden) {
4400
0
    cmSystemTools::Error(
4401
0
      cmStrCat("Cannot use hidden preset for workflow step ", stepLabel,
4402
0
               " in ", this->GetHomeDirectory()));
4403
0
    return nullptr;
4404
0
  }
4405
4406
0
  if (!it->second.Expanded) {
4407
0
    cmSystemTools::Error(cmStrCat("Could not evaluate workflow step ",
4408
0
                                  stepLabel, ": Invalid macro expansion"));
4409
0
    return nullptr;
4410
0
  }
4411
4412
0
  if (!it->second.Expanded->ConditionResult) {
4413
0
    cmSystemTools::Error(
4414
0
      cmStrCat("Cannot use disabled preset for workflow step ", stepLabel,
4415
0
               " in ", this->GetHomeDirectory()));
4416
0
    return nullptr;
4417
0
  }
4418
4419
0
  return &*it->second.Expanded;
4420
0
}
Unexecuted instantiation: cmCMakePresetsGraph::ConfigurePreset const* cmake::FindPresetForWorkflow<cmCMakePresetsGraph::ConfigurePreset>(cm::static_string_view, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::ConfigurePreset>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::ConfigurePreset> > > > const&, cmCMakePresetsGraph::WorkflowPreset::WorkflowStep const&)
Unexecuted instantiation: cmCMakePresetsGraph::BuildPreset const* cmake::FindPresetForWorkflow<cmCMakePresetsGraph::BuildPreset>(cm::static_string_view, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::BuildPreset>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::BuildPreset> > > > const&, cmCMakePresetsGraph::WorkflowPreset::WorkflowStep const&)
Unexecuted instantiation: cmCMakePresetsGraph::TestPreset const* cmake::FindPresetForWorkflow<cmCMakePresetsGraph::TestPreset>(cm::static_string_view, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::TestPreset>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::TestPreset> > > > const&, cmCMakePresetsGraph::WorkflowPreset::WorkflowStep const&)
Unexecuted instantiation: cmCMakePresetsGraph::PackagePreset const* cmake::FindPresetForWorkflow<cmCMakePresetsGraph::PackagePreset>(cm::static_string_view, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::PackagePreset>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, cmCMakePresetsGraph::PresetPair<cmCMakePresetsGraph::PackagePreset> > > > const&, cmCMakePresetsGraph::WorkflowPreset::WorkflowStep const&)
4421
4422
namespace {
4423
4424
std::function<cmUVProcessChain::Status()> buildWorkflowStep(
4425
  std::vector<std::string> const& args)
4426
0
{
4427
0
  cmUVProcessChainBuilder builder;
4428
0
  builder.AddCommand(args)
4429
0
    .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout)
4430
0
    .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr);
4431
0
  return [builder]() -> cmUVProcessChain::Status {
4432
0
    auto chain = builder.Start();
4433
0
    chain.Wait();
4434
0
    return chain.GetStatus(0);
4435
0
  };
4436
0
}
4437
4438
}
4439
#endif
4440
4441
int cmake::Workflow(cmCMakePresetsWorkflowArgs const& args)
4442
0
{
4443
0
  int exitStatus = 0;
4444
0
#ifndef CMAKE_BOOTSTRAP
4445
0
  this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
4446
0
  this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
4447
4448
0
  cmCMakePresetsGraph settingsFile;
4449
0
  auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory(),
4450
0
                                                args.PresetsFile);
4451
0
  if (result != true) {
4452
0
    cmSystemTools::Error(cmStrCat("Could not read presets from ",
4453
0
                                  this->GetHomeDirectory(), ":\n",
4454
0
                                  settingsFile.parseState.GetErrorMessage()));
4455
0
    return 1;
4456
0
  }
4457
4458
0
  if (args.ListPresetsMode) {
4459
0
    auto configureUsabilityCheck = this->CreateConfigurePresetUsabilityCheck();
4460
0
    settingsFile.PrintWorkflowPresetList(*args.ListPresetsMode,
4461
0
                                         configureUsabilityCheck);
4462
0
    return 0;
4463
0
  }
4464
4465
0
  auto presetPair = settingsFile.WorkflowPresets.find(args.PresetName);
4466
0
  if (presetPair == settingsFile.WorkflowPresets.end()) {
4467
0
    cmSystemTools::Error(cmStrCat("No such workflow preset in ",
4468
0
                                  this->GetHomeDirectory(), ": \"",
4469
0
                                  args.PresetName, '"'));
4470
0
    settingsFile.PrintWorkflowPresetList();
4471
0
    return 1;
4472
0
  }
4473
4474
0
  if (presetPair->second.Unexpanded.Hidden) {
4475
0
    cmSystemTools::Error(cmStrCat("Cannot use hidden workflow preset in ",
4476
0
                                  this->GetHomeDirectory(), ": \"",
4477
0
                                  args.PresetName, '"'));
4478
0
    settingsFile.PrintWorkflowPresetList();
4479
0
    return 1;
4480
0
  }
4481
4482
0
  auto const& expandedPreset = presetPair->second.Expanded;
4483
0
  if (!expandedPreset) {
4484
0
    cmSystemTools::Error(cmStrCat("Could not evaluate workflow preset \"",
4485
0
                                  args.PresetName,
4486
0
                                  "\": Invalid macro expansion"));
4487
0
    settingsFile.PrintWorkflowPresetList();
4488
0
    return 1;
4489
0
  }
4490
4491
0
  if (!expandedPreset->ConditionResult) {
4492
0
    cmSystemTools::Error(cmStrCat("Cannot use disabled workflow preset in ",
4493
0
                                  this->GetHomeDirectory(), ": \"",
4494
0
                                  args.PresetName, '"'));
4495
0
    settingsFile.PrintWorkflowPresetList();
4496
0
    return 1;
4497
0
  }
4498
4499
0
  struct CalculatedStep
4500
0
  {
4501
0
    int StepNumber;
4502
0
    cm::static_string_view Type;
4503
0
    std::string Name;
4504
0
    std::function<cmUVProcessChain::Status()> Action;
4505
4506
0
    CalculatedStep(int stepNumber, cm::static_string_view type,
4507
0
                   std::string name,
4508
0
                   std::function<cmUVProcessChain::Status()> action)
4509
0
      : StepNumber(stepNumber)
4510
0
      , Type(type)
4511
0
      , Name(std::move(name))
4512
0
      , Action(std::move(action))
4513
0
    {
4514
0
    }
4515
0
  };
4516
4517
0
  auto buildPresetCommand = [&args](std::vector<std::string> cmd,
4518
0
                                    std::string const& presetName) {
4519
0
    cmd.insert(cmd.end(), { "--preset", presetName });
4520
0
    if (!args.PresetsFile.empty()) {
4521
0
      cmd.insert(cmd.end(), { "--presets-file", args.PresetsFile });
4522
0
    }
4523
0
    return cmd;
4524
0
  };
4525
4526
0
  std::vector<CalculatedStep> steps;
4527
0
  steps.reserve(expandedPreset->Steps.size());
4528
0
  int stepNumber = 1;
4529
0
  cmCMakePresetsGraph::ConfigurePreset const* configurePreset = {};
4530
0
  for (auto const& step : expandedPreset->Steps) {
4531
0
    switch (step.PresetType) {
4532
0
      case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::
4533
0
        Configure: {
4534
0
        configurePreset = this->FindPresetForWorkflow(
4535
0
          "configure"_s, settingsFile.ConfigurePresets, step);
4536
0
        if (!configurePreset) {
4537
0
          return 1;
4538
0
        }
4539
0
        std::vector<std::string> configureCmdArgs = buildPresetCommand(
4540
0
          { cmSystemTools::GetCMakeCommand() }, step.PresetName);
4541
0
        if (args.Fresh) {
4542
0
          configureCmdArgs.emplace_back("--fresh");
4543
0
        }
4544
0
        steps.emplace_back(stepNumber, "configure"_s, step.PresetName,
4545
0
                           buildWorkflowStep(configureCmdArgs));
4546
0
      } break;
4547
0
      case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Build: {
4548
0
        auto const* buildPreset = this->FindPresetForWorkflow(
4549
0
          "build"_s, settingsFile.BuildPresets, step);
4550
0
        if (!buildPreset) {
4551
0
          return 1;
4552
0
        }
4553
0
        std::vector<std::string> buildCmdArgs = buildPresetCommand(
4554
0
          { cmSystemTools::GetCMakeCommand(), "--build" }, step.PresetName);
4555
0
        steps.emplace_back(stepNumber, "build"_s, step.PresetName,
4556
0
                           buildWorkflowStep(buildCmdArgs));
4557
0
      } break;
4558
0
      case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Test: {
4559
0
        auto const* testPreset = this->FindPresetForWorkflow(
4560
0
          "test"_s, settingsFile.TestPresets, step);
4561
0
        if (!testPreset) {
4562
0
          return 1;
4563
0
        }
4564
0
        std::vector<std::string> testCmdArgs = buildPresetCommand(
4565
0
          { cmSystemTools::GetCTestCommand() }, step.PresetName);
4566
0
        steps.emplace_back(stepNumber, "test"_s, step.PresetName,
4567
0
                           buildWorkflowStep(testCmdArgs));
4568
0
      } break;
4569
0
      case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Package: {
4570
0
        auto const* packagePreset = this->FindPresetForWorkflow(
4571
0
          "package"_s, settingsFile.PackagePresets, step);
4572
0
        if (!packagePreset) {
4573
0
          return 1;
4574
0
        }
4575
0
        std::vector<std::string> packageCmdArgs = buildPresetCommand(
4576
0
          { cmSystemTools::GetCPackCommand() }, step.PresetName);
4577
0
        steps.emplace_back(stepNumber, "package"_s, step.PresetName,
4578
0
                           buildWorkflowStep(packageCmdArgs));
4579
0
      } break;
4580
0
    }
4581
0
    stepNumber++;
4582
0
  }
4583
4584
0
  bool first = true;
4585
0
  for (auto const& step : steps) {
4586
0
    if (!first) {
4587
0
      std::cout << "\n";
4588
0
    }
4589
0
    std::cout << "Executing workflow step " << step.StepNumber << " of "
4590
0
              << steps.size() << ": " << step.Type << " preset \"" << step.Name
4591
0
              << "\"\n\n"
4592
0
              << std::flush;
4593
0
    cmUVProcessChain::Status const status = step.Action();
4594
0
    if (status.ExitStatus != 0) {
4595
0
      cmSystemTools::Error(
4596
0
        cmStrCat("Workflow step ", WorkflowStepLabel(step.Type, step.Name),
4597
0
                 " failed with exit code ", status.ExitStatus));
4598
0
      exitStatus = static_cast<int>(status.ExitStatus);
4599
0
      break;
4600
0
    }
4601
0
    auto const codeReasonPair = status.GetException();
4602
0
    if (codeReasonPair.first != cmUVProcessChain::ExceptionCode::None) {
4603
0
      cmSystemTools::Error(
4604
0
        cmStrCat("Workflow step ", WorkflowStepLabel(step.Type, step.Name),
4605
0
                 " command ended abnormally: ", codeReasonPair.second));
4606
0
      exitStatus =
4607
0
        status.SpawnResult != 0 ? status.SpawnResult : status.TermSignal;
4608
0
      break;
4609
0
    }
4610
0
    first = false;
4611
0
  }
4612
0
  if (configurePreset) {
4613
0
    cmInstrumentation instrumentation(configurePreset->BinaryDir);
4614
0
    instrumentation.CollectTimingData(
4615
0
      cmInstrumentationQuery::Hook::PostCMakeWorkflow);
4616
0
  }
4617
0
#endif
4618
4619
0
  return exitStatus;
4620
0
}
4621
4622
void cmake::WatchUnusedCli(std::string const& var)
4623
0
{
4624
0
#ifndef CMAKE_BOOTSTRAP
4625
0
  this->VariableWatch->AddWatch(var, cmWarnUnusedCliWarning, this);
4626
0
  if (!cm::contains(this->UsedCliVariables, var)) {
4627
0
    this->UsedCliVariables[var] = false;
4628
0
  }
4629
0
#endif
4630
0
}
4631
4632
void cmake::UnwatchUnusedCli(std::string const& var)
4633
3
{
4634
3
#ifndef CMAKE_BOOTSTRAP
4635
3
  this->VariableWatch->RemoveWatch(var, cmWarnUnusedCliWarning);
4636
3
  this->UsedCliVariables.erase(var);
4637
3
#endif
4638
3
}
4639
4640
void cmake::RunCheckForUnusedVariables()
4641
0
{
4642
0
#ifndef CMAKE_BOOTSTRAP
4643
0
  cmDiagnosticAction const action =
4644
0
    this->CurrentSnapshot.GetDiagnostic(cmDiagnostics::CMD_UNUSED_CLI);
4645
0
  if (action != cmDiagnostics::Ignore) {
4646
0
    bool haveUnused = false;
4647
0
    std::string msg(
4648
0
      "Manually-specified variables were not used by the project:");
4649
0
    for (auto const& it : this->UsedCliVariables) {
4650
0
      if (!it.second) {
4651
0
        haveUnused = true;
4652
0
        msg = cmStrCat(std::move(msg), "\n  ", it.first);
4653
0
      }
4654
0
    }
4655
0
    if (haveUnused) {
4656
0
      this->IssueDiagnostic(cmDiagnostics::CMD_UNUSED_CLI, msg);
4657
0
    }
4658
0
  }
4659
0
#endif
4660
0
}
4661
4662
void cmake::AlterDiagnostic(DiagnosticAlterationMethod alteration,
4663
                            cmDiagnosticCategory category,
4664
                            cmDiagnosticAction desiredAction, bool recurse)
4665
0
{
4666
  // In Project mode, we need to defer applying any diagnostic changes until
4667
  // after reading the prior state from the cache. In all other modes, changes
4668
  // should be applied immediately.
4669
0
  if (this->State->GetRole() == cmState::Role::Project) {
4670
0
    this->DiagnosticAlterations.emplace_back( // clang-format: break
4671
0
      DiagnosticAlteration{ alteration, category, desiredAction, recurse });
4672
0
  } else {
4673
0
    (this->CurrentSnapshot.*alteration)(category, desiredAction, recurse);
4674
0
  }
4675
0
}
4676
4677
void cmake::SetDebugFindOutputPkgs(std::string const& args)
4678
0
{
4679
0
  this->DebugFindPkgs.emplace(args);
4680
0
}
4681
4682
void cmake::SetDebugFindOutputVars(std::string const& args)
4683
0
{
4684
0
  this->DebugFindVars.emplace(args);
4685
0
}
4686
4687
bool cmake::GetDebugFindOutput(std::string const& var) const
4688
0
{
4689
0
  return this->DebugFindVars.count(var);
4690
0
}
4691
4692
bool cmake::GetDebugFindPkgOutput(std::string const& pkg) const
4693
0
{
4694
0
  return this->DebugFindPkgs.count(pkg);
4695
0
}
4696
4697
void cmake::SetCMakeListName(std::string const& name)
4698
0
{
4699
0
  this->CMakeListName = name;
4700
0
}
4701
4702
std::string cmake::GetCMakeListFile(std::string const& dir) const
4703
11.8k
{
4704
11.8k
  assert(!dir.empty());
4705
11.8k
  cm::string_view const slash = dir.back() != '/' ? "/"_s : ""_s;
4706
11.8k
  std::string listFile;
4707
11.8k
  if (!this->CMakeListName.empty()) {
4708
0
    listFile = cmStrCat(dir, slash, this->CMakeListName);
4709
0
  }
4710
11.8k
  if (listFile.empty() || !cmSystemTools::FileExists(listFile, true)) {
4711
11.8k
    listFile = cmStrCat(dir, slash, "CMakeLists.txt");
4712
11.8k
  }
4713
11.8k
  return listFile;
4714
11.8k
}
4715
4716
#if !defined(CMAKE_BOOTSTRAP)
4717
cmMakefileProfilingData& cmake::GetProfilingOutput()
4718
0
{
4719
0
  return *(this->ProfilingOutput);
4720
0
}
4721
4722
bool cmake::IsProfilingEnabled() const
4723
576k
{
4724
576k
  return static_cast<bool>(this->ProfilingOutput);
4725
576k
}
4726
#endif