Coverage Report

Created: 2026-03-12 06:35

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