Coverage Report

Created: 2026-07-30 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGlobalGenerator.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 "cmGlobalGenerator.h"
4
5
#include <algorithm>
6
#include <cassert>
7
#include <cstdio>
8
#include <cstdlib>
9
#include <cstring>
10
#include <functional>
11
#include <initializer_list>
12
#include <iterator>
13
#include <sstream>
14
#include <utility>
15
16
#include <cm/memory>
17
#include <cm/optional>
18
#include <cmext/algorithm>
19
#include <cmext/string_view>
20
21
#include "cmsys/Directory.hxx"
22
#include "cmsys/FStream.hxx"
23
#include "cmsys/RegularExpression.hxx"
24
25
#include "cm_codecvt_Encoding.hxx"
26
27
#include "cmAlgorithms.h"
28
#include "cmArgumentParserTypes.h"
29
#include "cmBuildArgs.h"
30
#include "cmBuildSbomGenerator.h"
31
#include "cmCMakePath.h"
32
#include "cmCPackPropertiesGenerator.h"
33
#include "cmComputeTargetDepends.h"
34
#include "cmCryptoHash.h"
35
#include "cmCustomCommand.h"
36
#include "cmCustomCommandLines.h"
37
#include "cmCustomCommandTypes.h"
38
#include "cmDiagnostics.h"
39
#include "cmDuration.h"
40
#include "cmExperimental.h"
41
#include "cmExportBuildFileGenerator.h"
42
#include "cmExternalMakefileProjectGenerator.h"
43
#include "cmGeneratedFileStream.h"
44
#include "cmGeneratorExpression.h"
45
#include "cmGeneratorTarget.h"
46
#include "cmInstallDirs.h"
47
#include "cmInstallExportGenerator.h"
48
#include "cmInstallGenerator.h"
49
#include "cmInstallRuntimeDependencySet.h"
50
#include "cmInstallSbomGenerator.h"
51
#include "cmLinkLineComputer.h"
52
#include "cmList.h"
53
#include "cmListFileCache.h"
54
#include "cmLocalGenerator.h"
55
#include "cmMSVC60LinkLineComputer.h"
56
#include "cmMakefile.h"
57
#include "cmMessageType.h"
58
#include "cmOutputConverter.h"
59
#include "cmPolicies.h"
60
#include "cmRange.h"
61
#include "cmSbomArguments.h"
62
#include "cmSourceFile.h"
63
#include "cmState.h"
64
#include "cmStateDirectory.h"
65
#include "cmStateTypes.h"
66
#include "cmStringAlgorithms.h"
67
#include "cmSystemTools.h"
68
#include "cmTargetExport.h"
69
#include "cmValue.h"
70
#include "cmVersion.h"
71
#include "cmWorkingDirectory.h"
72
#include "cmXcFramework.h"
73
#include "cmake.h"
74
75
#if !defined(CMAKE_BOOTSTRAP)
76
#  include <cm3p/json/value.h>
77
#  include <cm3p/json/writer.h>
78
79
#  include "cmQtAutoGenGlobalInitializer.h"
80
#endif
81
82
std::string const kCMAKE_PLATFORM_INFO_INITIALIZED =
83
  "CMAKE_PLATFORM_INFO_INITIALIZED";
84
85
class cmInstalledFile;
86
87
namespace detail {
88
std::string GeneratedMakeCommand::QuotedPrintable() const
89
0
{
90
0
  std::string output;
91
0
  char const* sep = "";
92
0
  int flags = 0;
93
0
#if !defined(_WIN32)
94
0
  flags |= cmOutputConverter::Shell_Flag_IsUnix;
95
0
#endif
96
0
  for (auto const& arg : this->PrimaryCommand) {
97
0
    output = cmStrCat(std::move(output), sep,
98
0
                      cmOutputConverter::EscapeForShell(arg, flags));
99
0
    sep = " ";
100
0
  }
101
0
  return output;
102
0
}
103
}
104
105
bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1,
106
                                                  cmTarget const* t2) const
107
0
{
108
0
  int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
109
0
  if (nameResult == 0) {
110
0
    return strcmp(t1->GetMakefile()->GetCurrentBinaryDirectory().c_str(),
111
0
                  t2->GetMakefile()->GetCurrentBinaryDirectory().c_str()) < 0;
112
0
  }
113
0
  return nameResult < 0;
114
0
}
115
116
cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
117
1
  : CMakeInstance(cm)
118
1
{
119
  // By default the .SYMBOLIC dependency is not needed on symbolic rules.
120
1
  this->NeedSymbolicMark = false;
121
122
  // by default use the native paths
123
1
  this->ForceUnixPaths = false;
124
125
  // By default do not try to support color.
126
1
  this->ToolSupportsColor = false;
127
128
  // By default do not use link scripts.
129
1
  this->UseLinkScript = false;
130
131
  // Whether an install target is needed.
132
1
  this->InstallTargetEnabled = false;
133
134
  // how long to let try compiles run
135
1
  this->TryCompileTimeout = cmDuration::zero();
136
137
1
  this->CurrentConfigureMakefile = nullptr;
138
1
  this->TryCompileOuterMakefile = nullptr;
139
140
1
  this->FirstTimeProgress = 0.0f;
141
142
1
  cm->GetState()->SetIsGeneratorMultiConfig(false);
143
1
  cm->GetState()->SetMinGWMake(false);
144
1
  cm->GetState()->SetMSYSShell(false);
145
1
  cm->GetState()->SetNMake(false);
146
1
  cm->GetState()->SetWatcomWMake(false);
147
1
  cm->GetState()->SetWindowsShell(false);
148
1
  cm->GetState()->SetWindowsVSIDE(false);
149
150
1
  cm->GetState()->SetFastbuildMake(false);
151
1
#if !defined(CMAKE_BOOTSTRAP)
152
1
  Json::StreamWriterBuilder wbuilder;
153
1
  wbuilder["indentation"] = "\t";
154
1
  this->JsonWriter =
155
1
    std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter());
156
1
#endif
157
1
}
158
159
cmGlobalGenerator::~cmGlobalGenerator()
160
1
{
161
1
  this->ClearGeneratorMembers();
162
1
}
163
codecvt_Encoding cmGlobalGenerator::GetMakefileEncoding() const
164
0
{
165
0
  return codecvt_Encoding::None;
166
0
}
167
168
#if !defined(CMAKE_BOOTSTRAP)
169
Json::Value cmGlobalGenerator::GetJson() const
170
0
{
171
0
  Json::Value generator = Json::objectValue;
172
0
  generator["name"] = this->GetName();
173
0
  generator["multiConfig"] = this->IsMultiConfig();
174
0
  return generator;
175
0
}
176
#endif
177
178
bool cmGlobalGenerator::SetGeneratorInstance(std::string const& i,
179
                                             cmMakefile* mf)
180
0
{
181
0
  if (i.empty()) {
182
0
    return true;
183
0
  }
184
185
0
  std::ostringstream e;
186
  /* clang-format off */
187
0
  e <<
188
0
    "Generator\n"
189
0
    "  " << this->GetName() << "\n"
190
0
    "does not support instance specification, but instance\n"
191
0
    "  " << i << "\n"
192
0
    "was specified.";
193
  /* clang-format on */
194
0
  mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
195
0
  return false;
196
0
}
197
198
bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p,
199
                                             cmMakefile* mf)
200
0
{
201
0
  if (p.empty()) {
202
0
    return true;
203
0
  }
204
205
0
  std::ostringstream e;
206
  /* clang-format off */
207
0
  e <<
208
0
    "Generator\n"
209
0
    "  " << this->GetName() << "\n"
210
0
    "does not support platform specification, but platform\n"
211
0
    "  " << p << "\n"
212
0
    "was specified.";
213
  /* clang-format on */
214
0
  mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
215
0
  return false;
216
0
}
217
218
bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool,
219
                                            cmMakefile* mf)
220
0
{
221
0
  if (ts.empty()) {
222
0
    return true;
223
0
  }
224
0
  std::ostringstream e;
225
  /* clang-format off */
226
0
  e <<
227
0
    "Generator\n"
228
0
    "  " << this->GetName() << "\n"
229
0
    "does not support toolset specification, but toolset\n"
230
0
    "  " << ts << "\n"
231
0
    "was specified.";
232
  /* clang-format on */
233
0
  mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
234
0
  return false;
235
0
}
236
237
std::string cmGlobalGenerator::SelectMakeProgram(
238
  std::string const& inMakeProgram, std::string const& makeDefault) const
239
0
{
240
0
  std::string makeProgram = inMakeProgram;
241
0
  if (cmIsOff(makeProgram)) {
242
0
    cmValue makeProgramCSTR =
243
0
      this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
244
0
    if (makeProgramCSTR.IsOff()) {
245
0
      makeProgram = makeDefault;
246
0
    } else {
247
0
      makeProgram = *makeProgramCSTR;
248
0
    }
249
0
    if (cmIsOff(makeProgram) && !makeProgram.empty()) {
250
0
      makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND";
251
0
    }
252
0
  }
253
0
  return makeProgram;
254
0
}
255
256
void cmGlobalGenerator::ResolveLanguageCompiler(std::string const& lang,
257
                                                cmMakefile* mf,
258
                                                bool optional) const
259
0
{
260
0
  std::string langComp = cmStrCat("CMAKE_", lang, "_COMPILER");
261
262
0
  if (!mf->GetDefinition(langComp)) {
263
0
    if (!optional) {
264
0
      cmSystemTools::Error(
265
0
        cmStrCat(langComp, " not set, after EnableLanguage"));
266
0
    }
267
0
    return;
268
0
  }
269
0
  std::string const& name = mf->GetRequiredDefinition(langComp);
270
0
  std::string path;
271
0
  if (!cmSystemTools::FileIsFullPath(name)) {
272
0
    path = cmSystemTools::FindProgram(name);
273
0
  } else {
274
0
    path = name;
275
0
  }
276
0
  if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) {
277
0
    return;
278
0
  }
279
0
  cmValue cname =
280
0
    this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp);
281
282
  // Split compiler from arguments
283
0
  cmList cnameArgList;
284
0
  if (cname && !cname->empty()) {
285
0
    cnameArgList.assign(*cname);
286
0
    cname = cmValue(cnameArgList.front());
287
0
  }
288
289
0
  if (cname && !optional) {
290
0
    cmCMakePath cachedPath;
291
0
    if (!cmSystemTools::FileIsFullPath(*cname)) {
292
0
      cachedPath = cmSystemTools::FindProgram(*cname);
293
0
    } else {
294
0
      cachedPath = *cname;
295
0
    }
296
0
    cmCMakePath foundPath = path;
297
0
    if (foundPath.Normal() != cachedPath.Normal()) {
298
0
      this->GetCMakeInstance()->GetState()->AddDeleteCacheChangeVar(langComp,
299
0
                                                                    *cname);
300
0
    }
301
0
  }
302
0
}
303
304
void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
305
0
{
306
0
  this->BuildExportSets[gen->GetMainExportFileName()] = gen;
307
0
}
308
309
cmExportFileGenerator::ExportInfo cmGlobalGenerator::FindBuildExportInfo(
310
  cmGeneratorTarget const* target) const
311
0
{
312
0
  cmExportFileGenerator::ExportInfo info;
313
0
  for (auto const& exp : this->BuildExportSets) {
314
0
    if (auto rec = exp.second->FindRecordForTarget(target)) {
315
0
      info.Files.push_back(exp.first);
316
0
      info.Sets.insert(rec->Name.empty() ? exp.first : rec->Name);
317
0
      info.Namespaces.insert(rec->Namespace);
318
0
    }
319
0
  }
320
0
  return info;
321
0
}
322
323
cmExportFileGenerator::ExportInfo cmGlobalGenerator::FindInstallExportInfo(
324
  cmGeneratorTarget const* target) const
325
0
{
326
0
  cmExportFileGenerator::ExportInfo info;
327
0
  auto const& name = target->GetName();
328
0
  for (auto const& exp : this->ExportSets) {
329
0
    auto const& exportSet = exp.second;
330
0
    auto const& targets = exportSet.GetTargetExports();
331
0
    bool const contains =
332
0
      std::any_of(targets.begin(), targets.end(),
333
0
                  [&name](std::unique_ptr<cmTargetExport> const& te) {
334
0
                    return te->TargetName == name;
335
0
                  });
336
0
    if (!contains) {
337
0
      continue;
338
0
    }
339
0
    auto const* installs = exportSet.GetInstallations();
340
0
    if (!installs || installs->empty()) {
341
0
      continue;
342
0
    }
343
0
    info.Sets.insert(exp.first);
344
0
    for (auto const* install : *installs) {
345
0
      info.Files.push_back(install->GetDestinationFile());
346
0
      info.Namespaces.insert(install->GetNamespace());
347
0
    }
348
0
  }
349
0
  return info;
350
0
}
351
352
#ifndef CMAKE_BOOTSTRAP
353
cmSbomBuilder::SbomInfo cmGlobalGenerator::FindBuildSbomInfo(
354
  cmGeneratorTarget const* target) const
355
0
{
356
0
  cmSbomBuilder::SbomInfo info;
357
0
  for (cmBuildSbomGenerator const* g : this->BuildSbomGenerators) {
358
0
    if (g->CoversTarget(target)) {
359
0
      info.Packages.push_back(g->GetPackageName());
360
0
    }
361
0
  }
362
0
  std::sort(info.Packages.begin(), info.Packages.end());
363
0
  return info;
364
0
}
365
366
cmSbomBuilder::SbomInfo cmGlobalGenerator::FindInstallSbomInfo(
367
  cmGeneratorTarget const* target) const
368
0
{
369
0
  cmSbomBuilder::SbomInfo info;
370
0
  for (cmInstallSbomGenerator const* g : this->InstallSbomGenerators) {
371
0
    if (g->CoversTarget(target)) {
372
0
      info.Packages.push_back(g->GetPackageName());
373
0
    }
374
0
  }
375
0
  std::sort(info.Packages.begin(), info.Packages.end());
376
0
  return info;
377
0
}
378
#endif
379
380
void cmGlobalGenerator::AddBuildExportExportSet(
381
  cmExportBuildFileGenerator* gen)
382
0
{
383
0
  this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
384
0
  this->AddBuildExportSet(gen);
385
0
}
386
387
void cmGlobalGenerator::AddBuildSbomGenerator(cmBuildSbomGenerator* gen)
388
0
{
389
0
  this->BuildSbomGenerators.push_back(gen);
390
0
}
391
392
void cmGlobalGenerator::AddInstallSbomGenerator(
393
  cmInstallSbomGenerator const* gen)
394
0
{
395
0
  this->InstallSbomGenerators.push_back(gen);
396
0
}
397
398
void cmGlobalGenerator::ForceLinkerLanguages()
399
0
{
400
0
}
401
402
bool cmGlobalGenerator::CheckTargetsForMissingSources() const
403
0
{
404
0
  bool failed = false;
405
0
  for (auto const& localGen : this->LocalGenerators) {
406
0
    for (auto const& target : localGen->GetGeneratorTargets()) {
407
0
      if (!target->CanCompileSources() ||
408
0
          target->GetProperty("ghs_integrity_app").IsOn()) {
409
0
        continue;
410
0
      }
411
412
0
      if (target->GetAllConfigSources().empty()) {
413
0
        std::ostringstream e;
414
0
        e << "No SOURCES given to target: " << target->GetName();
415
0
        this->GetCMakeInstance()->IssueMessage(
416
0
          MessageType::FATAL_ERROR, e.str(), target->GetBacktrace());
417
0
        failed = true;
418
0
      }
419
0
    }
420
0
  }
421
0
  return failed;
422
0
}
423
424
void cmGlobalGenerator::CheckTargetLinkLibraries() const
425
0
{
426
0
  for (auto const& generator : this->LocalGenerators) {
427
0
    for (auto const& gt : generator->GetGeneratorTargets()) {
428
0
      gt->CheckLinkLibraries();
429
0
    }
430
0
    for (auto const& gt : generator->GetOwnedImportedGeneratorTargets()) {
431
0
      gt->CheckLinkLibraries();
432
0
    }
433
0
  }
434
0
}
435
436
bool cmGlobalGenerator::CheckTargetsForType() const
437
0
{
438
0
  if (!this->GetLanguageEnabled("Swift")) {
439
0
    return false;
440
0
  }
441
0
  bool failed = false;
442
0
  for (auto const& generator : this->LocalGenerators) {
443
0
    for (auto const& target : generator->GetGeneratorTargets()) {
444
0
      std::string systemName =
445
0
        target->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
446
0
      if (systemName.find("Windows") == std::string::npos) {
447
0
        continue;
448
0
      }
449
450
0
      if (target->GetType() == cm::TargetType::EXECUTABLE) {
451
0
        std::vector<std::string> const& configs =
452
0
          target->Makefile->GetGeneratorConfigs(
453
0
            cmMakefile::IncludeEmptyConfig);
454
0
        for (std::string const& config : configs) {
455
0
          if (target->IsWin32Executable(config) &&
456
0
              target->GetLinkerLanguage(config) == "Swift") {
457
0
            this->GetCMakeInstance()->IssueMessage(
458
0
              MessageType::FATAL_ERROR,
459
0
              "WIN32_EXECUTABLE property is not supported on Swift "
460
0
              "executables",
461
0
              target->GetBacktrace());
462
0
            failed = true;
463
0
          }
464
0
        }
465
0
      }
466
0
    }
467
0
  }
468
0
  return failed;
469
0
}
470
471
void cmGlobalGenerator::MarkTargetsForPchReuse() const
472
0
{
473
0
  for (auto const& generator : this->LocalGenerators) {
474
0
    for (auto const& target : generator->GetGeneratorTargets()) {
475
0
      if (auto* reuseTarget = target->GetPchReuseTarget()) {
476
0
        reuseTarget->MarkAsPchReused();
477
0
      }
478
0
    }
479
0
  }
480
0
}
481
482
bool cmGlobalGenerator::IsExportedTargetsFile(
483
  std::string const& filename) const
484
0
{
485
0
  auto const it = this->BuildExportSets.find(filename);
486
0
  if (it == this->BuildExportSets.end()) {
487
0
    return false;
488
0
  }
489
0
  return !cm::contains(this->BuildExportExportSets, filename);
490
0
}
491
492
bool cmGlobalGenerator::IsBuildSbomFile(std::string const& filepath) const
493
0
{
494
0
  return std::any_of(this->BuildSbomGenerators.begin(),
495
0
                     this->BuildSbomGenerators.end(),
496
0
                     [&filepath](cmBuildSbomGenerator const* g) {
497
0
                       return g->GetOutputFile() == filepath;
498
0
                     });
499
0
}
500
501
bool cmGlobalGenerator::IsInstallSbomFile(std::string const& filepath) const
502
0
{
503
0
  return std::any_of(this->InstallSbomGenerators.begin(),
504
0
                     this->InstallSbomGenerators.end(),
505
0
                     [&filepath](cmInstallSbomGenerator const* g) {
506
0
                       return g->GetInstallFile() == filepath;
507
0
                     });
508
0
}
509
510
// Find the make program for the generator, required for try compiles
511
bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
512
0
{
513
0
  if (this->FindMakeProgramFile.empty()) {
514
0
    cmSystemTools::Error(
515
0
      "Generator implementation error, "
516
0
      "all generators must specify this->FindMakeProgramFile");
517
0
    return false;
518
0
  }
519
0
  if (mf->GetDefinition("CMAKE_MAKE_PROGRAM").IsOff()) {
520
0
    std::string setMakeProgram = mf->GetModulesFile(this->FindMakeProgramFile);
521
0
    if (!setMakeProgram.empty()) {
522
0
      mf->ReadListFile(setMakeProgram);
523
0
    }
524
0
  }
525
0
  if (mf->GetDefinition("CMAKE_MAKE_PROGRAM").IsOff()) {
526
0
    std::ostringstream err;
527
0
    err << "CMake was unable to find a build program corresponding to \""
528
0
        << this->GetName()
529
0
        << "\".  CMAKE_MAKE_PROGRAM is not set.  You "
530
0
           "probably need to select a different build tool.";
531
0
    cmSystemTools::Error(err.str());
532
0
    cmSystemTools::SetFatalErrorOccurred();
533
0
    return false;
534
0
  }
535
0
  std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
536
  // if there are spaces in the make program use short path
537
  // but do not short path the actual program name, as
538
  // this can cause trouble with VSExpress
539
0
  if (makeProgram.find(' ') != std::string::npos) {
540
0
    std::string dir;
541
0
    std::string file;
542
0
    cmSystemTools::SplitProgramPath(makeProgram, dir, file);
543
0
    std::string saveFile = file;
544
0
    cmSystemTools::GetShortPath(makeProgram, makeProgram);
545
0
    cmSystemTools::SplitProgramPath(makeProgram, dir, file);
546
0
    makeProgram = cmStrCat(dir, '/', saveFile);
547
0
    mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram, "make program",
548
0
                           cmStateEnums::FILEPATH);
549
0
  }
550
0
  return true;
551
0
}
552
553
bool cmGlobalGenerator::CheckLanguages(
554
  std::vector<std::string> const& /* languages */, cmMakefile* /* mf */) const
555
0
{
556
0
  return true;
557
0
}
558
559
// enable the given language
560
//
561
// The following files are loaded in this order:
562
//
563
// First figure out what OS we are running on:
564
//
565
// CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake
566
//   CMakeDetermineSystem.cmake - figure out os info and create
567
//                                CMakeSystem.cmake IF CMAKE_SYSTEM
568
//                                not set
569
//   CMakeSystem.cmake - configured file created by
570
//                       CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED
571
572
// CMakeSystemSpecificInitialize.cmake
573
//   - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake
574
575
// Next try and enable all languages found in the languages vector
576
//
577
// FOREACH LANG in languages
578
//   CMake(LANG)Compiler.cmake - configured file create by
579
//                               CMakeDetermine(LANG)Compiler.cmake
580
//     CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and
581
//                                          creates CMake(LANG)Compiler.cmake
582
//     CMake(LANG)Compiler.cmake - configured file created by
583
//                                 CMakeDetermine(LANG)Compiler.cmake
584
//
585
// CMakeSystemSpecificInformation.cmake
586
//   - includes Platform/${CMAKE_SYSTEM_NAME}.cmake
587
//     may use compiler stuff
588
589
// FOREACH LANG in languages
590
//   CMake(LANG)Information.cmake
591
//     - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake
592
//   CMakeTest(LANG)Compiler.cmake
593
//     - Make sure the compiler works with a try compile if
594
//       CMakeDetermine(LANG) was loaded
595
//
596
//   CMake(LANG)LinkerInformation.cmake
597
//     - loads Platform/Linker/${CMAKE_SYSTEM_NAME}-${LINKER}.cmake
598
//
599
// Now load a few files that can override values set in any of the above
600
// (PROJECTNAME)Compatibility.cmake
601
//   - load any backwards compatibility stuff for current project
602
// ${CMAKE_USER_MAKE_RULES_OVERRIDE}
603
//   - allow users a chance to override system variables
604
//
605
//
606
607
void cmGlobalGenerator::EnableLanguage(
608
  std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
609
0
{
610
0
  if (!this->IsMultiConfig() &&
611
0
      !this->GetCMakeInstance()->GetIsInTryCompile()) {
612
0
    std::string envBuildType;
613
0
    if (!mf->GetDefinition("CMAKE_BUILD_TYPE") &&
614
0
        cmSystemTools::GetEnv("CMAKE_BUILD_TYPE", envBuildType)) {
615
0
      mf->AddCacheDefinition(
616
0
        "CMAKE_BUILD_TYPE", envBuildType,
617
0
        "Choose the type of build.  Options include: empty, "
618
0
        "Debug, Release, RelWithDebInfo, MinSizeRel.",
619
0
        cmStateEnums::STRING);
620
0
    }
621
0
  }
622
623
0
  if (languages.empty()) {
624
0
    cmSystemTools::Error("EnableLanguage must have a lang specified!");
625
0
    cmSystemTools::SetFatalErrorOccurred();
626
0
    return;
627
0
  }
628
629
0
  std::set<std::string> cur_languages(languages.begin(), languages.end());
630
0
  for (std::string const& li : cur_languages) {
631
0
    if (!this->LanguagesInProgress.insert(li).second) {
632
0
      std::ostringstream e;
633
0
      e << "Language '" << li
634
0
        << "' is currently being enabled.  "
635
0
           "Recursive call not allowed.";
636
0
      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
637
0
      cmSystemTools::SetFatalErrorOccurred();
638
0
      return;
639
0
    }
640
0
  }
641
642
0
  if (this->TryCompileOuterMakefile) {
643
    // In a try-compile we can only enable languages provided by caller.
644
0
    for (std::string const& lang : languages) {
645
0
      if (lang == "NONE") {
646
0
        this->SetLanguageEnabled("NONE", mf);
647
0
      } else {
648
0
        if (!cm::contains(this->LanguagesReadyForTryCompile, lang)) {
649
0
          std::ostringstream e;
650
0
          e << "The test project needs language " << lang
651
0
            << " which is not enabled.";
652
0
          this->TryCompileOuterMakefile->IssueMessage(MessageType::FATAL_ERROR,
653
0
                                                      e.str());
654
0
          cmSystemTools::SetFatalErrorOccurred();
655
0
          return;
656
0
        }
657
0
      }
658
0
    }
659
0
  }
660
661
0
  bool fatalError = false;
662
663
0
  mf->AddDefinitionBool("RUN_CONFIGURE", true);
664
0
  std::string rootBin;
665
666
  // If the configuration files path has been set,
667
  // then we are in a try compile and need to copy the enable language
668
  // files from the parent cmake bin dir, into the try compile bin dir
669
0
  if (!this->ConfiguredFilesPath.empty()) {
670
0
    rootBin = this->ConfiguredFilesPath;
671
0
  } else {
672
0
    rootBin =
673
0
      cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
674
0
  }
675
0
  rootBin = cmStrCat(std::move(rootBin), '/', cmVersion::GetCMakeVersion());
676
677
  // set the dir for parent files so they can be used by modules
678
0
  mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin);
679
680
0
  if (!this->CMakeInstance->GetIsInTryCompile()) {
681
    // Keep a mark in the cache to indicate that we've initialized the
682
    // platform information directory.  If the platform information
683
    // directory exists but the mark is missing then CMakeCache.txt
684
    // has been removed or replaced without also removing the CMakeFiles/
685
    // directory.  In this case remove the platform information directory
686
    // so that it will be re-initialized and the relevant information
687
    // restored in the cache.
688
0
    if (cmSystemTools::FileIsDirectory(rootBin) &&
689
0
        !mf->IsOn(kCMAKE_PLATFORM_INFO_INITIALIZED)) {
690
0
      cmSystemTools::RemoveADirectory(rootBin);
691
0
    }
692
0
    this->GetCMakeInstance()->AddCacheEntry(
693
0
      kCMAKE_PLATFORM_INFO_INITIALIZED, "1",
694
0
      "Platform information initialized", cmStateEnums::INTERNAL);
695
0
  }
696
697
  // try and load the CMakeSystem.cmake if it is there
698
0
  std::string fpath = rootBin;
699
0
  bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
700
0
  if (readCMakeSystem) {
701
0
    fpath += "/CMakeSystem.cmake";
702
0
    if (cmSystemTools::FileExists(fpath)) {
703
0
      mf->ReadListFile(fpath);
704
      // If the toolchain file changes, the introspection results may become
705
      // invalid, and so the cache must be deleted. The CMAKE_TOOLCHAIN_FILE
706
      // value could be input the same way but be different in the cache due to
707
      // normalization and relative path searching, so the value is checked
708
      // against the original input to decide if the file path has changed.
709
0
      cmValue toolchainFile = mf->GetDefinition("CMAKE_TOOLCHAIN_FILE");
710
0
      cmValue inputToolchainFile =
711
0
        mf->GetDefinition("_CMAKE_INPUT_TOOLCHAIN_FILE");
712
0
      cmValue storedToolchainFile =
713
0
        mf->GetDefinition("_CMAKE_SYSTEM_TOOLCHAIN_FILE");
714
0
      if (toolchainFile && toolchainFile != inputToolchainFile &&
715
0
          toolchainFile != storedToolchainFile) {
716
0
        mf->GetState()->AddDeleteCacheChangeVar("CMAKE_TOOLCHAIN_FILE",
717
0
                                                *toolchainFile);
718
0
        for (std::string const& lang : cur_languages) {
719
0
          this->LanguagesInProgress.erase(lang);
720
0
        }
721
0
        cmSystemTools::SetFatalErrorOccurred();
722
0
        return;
723
0
      }
724
0
    }
725
0
  }
726
727
  //  Load the CMakeDetermineSystem.cmake file and find out
728
  // what platform we are running on
729
0
  if (!mf->GetDefinition("CMAKE_SYSTEM")) {
730
#if defined(_WIN32) && !defined(__CYGWIN__)
731
    cmSystemTools::WindowsVersion windowsVersion =
732
      cmSystemTools::GetWindowsVersion();
733
    auto windowsVersionString = cmStrCat(windowsVersion.dwMajorVersion, '.',
734
                                         windowsVersion.dwMinorVersion, '.',
735
                                         windowsVersion.dwBuildNumber);
736
    mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString);
737
#endif
738
    // Read the DetermineSystem file
739
0
    std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
740
0
    mf->ReadListFile(systemFile);
741
    // load the CMakeSystem.cmake from the binary directory
742
    // this file is configured by the CMakeDetermineSystem.cmake file
743
0
    fpath = cmStrCat(rootBin, "/CMakeSystem.cmake");
744
0
    mf->ReadListFile(fpath);
745
0
  }
746
747
0
  if (readCMakeSystem) {
748
    // Tell the generator about the instance, if any.
749
0
    std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
750
0
    if (!this->SetGeneratorInstance(instance, mf)) {
751
0
      cmSystemTools::SetFatalErrorOccurred();
752
0
      return;
753
0
    }
754
755
    // Tell the generator about the target system.
756
0
    std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
757
0
    if (!this->SetSystemName(system, mf)) {
758
0
      cmSystemTools::SetFatalErrorOccurred();
759
0
      return;
760
0
    }
761
762
    // Tell the generator about the platform, if any.
763
0
    std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM");
764
0
    if (!this->SetGeneratorPlatform(platform, mf)) {
765
0
      cmSystemTools::SetFatalErrorOccurred();
766
0
      return;
767
0
    }
768
769
    // Tell the generator about the toolset, if any.
770
0
    std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET");
771
0
    if (!this->SetGeneratorToolset(toolset, false, mf)) {
772
0
      cmSystemTools::SetFatalErrorOccurred();
773
0
      return;
774
0
    }
775
776
    // Find the native build tool for this generator.
777
0
    if (!this->FindMakeProgram(mf)) {
778
0
      return;
779
0
    }
780
781
    // One-time includes of user-provided project setup files
782
0
    mf->GetState()->SetInTopLevelIncludes(true);
783
0
    std::string includes =
784
0
      mf->GetSafeDefinition("CMAKE_PROJECT_TOP_LEVEL_INCLUDES");
785
0
    cmList includesList{ includes };
786
0
    for (std::string setupFile : includesList) {
787
      // Any relative path without a .cmake extension is checked for valid
788
      // cmake modules. This logic should be consistent with CMake's include()
789
      // command. Otherwise default to checking relative path w.r.t. source
790
      // directory
791
0
      if (!cmSystemTools::FileIsFullPath(setupFile) &&
792
0
          !cmHasLiteralSuffix(setupFile, ".cmake")) {
793
0
        std::string mfile = mf->GetModulesFile(cmStrCat(setupFile, ".cmake"));
794
0
        if (mfile.empty()) {
795
0
          cmSystemTools::Error(cmStrCat(
796
0
            "CMAKE_PROJECT_TOP_LEVEL_INCLUDES module:\n  ", setupFile));
797
0
          mf->GetState()->SetInTopLevelIncludes(false);
798
0
          return;
799
0
        }
800
0
        setupFile = mfile;
801
0
      }
802
0
      std::string absSetupFile = cmSystemTools::CollapseFullPath(
803
0
        setupFile, mf->GetCurrentSourceDirectory());
804
0
      if (!cmSystemTools::FileExists(absSetupFile)) {
805
0
        cmSystemTools::Error(
806
0
          cmStrCat("CMAKE_PROJECT_TOP_LEVEL_INCLUDES file does not exist: ",
807
0
                   setupFile));
808
0
        mf->GetState()->SetInTopLevelIncludes(false);
809
0
        return;
810
0
      }
811
0
      if (cmSystemTools::FileIsDirectory(absSetupFile)) {
812
0
        cmSystemTools::Error(
813
0
          cmStrCat("CMAKE_PROJECT_TOP_LEVEL_INCLUDES file is a directory: ",
814
0
                   setupFile));
815
0
        mf->GetState()->SetInTopLevelIncludes(false);
816
0
        return;
817
0
      }
818
0
      if (!mf->ReadListFile(absSetupFile)) {
819
0
        cmSystemTools::Error(
820
0
          cmStrCat("Failed reading CMAKE_PROJECT_TOP_LEVEL_INCLUDES file: ",
821
0
                   setupFile));
822
0
        mf->GetState()->SetInTopLevelIncludes(false);
823
0
        return;
824
0
      }
825
0
    }
826
0
  }
827
0
  mf->GetState()->SetInTopLevelIncludes(false);
828
829
  // Check that the languages are supported by the generator and its
830
  // native build tool found above.
831
0
  if (!this->CheckLanguages(languages, mf)) {
832
0
    return;
833
0
  }
834
835
  // **** Load the system specific initialization if not yet loaded
836
0
  if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) {
837
0
    fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake");
838
0
    if (!mf->ReadListFile(fpath)) {
839
0
      cmSystemTools::Error("Could not find cmake module file: "
840
0
                           "CMakeSystemSpecificInitialize.cmake");
841
0
    }
842
0
  }
843
844
0
  std::map<std::string, bool> needTestLanguage;
845
0
  std::map<std::string, bool> needSetLanguageEnabledMaps;
846
  // foreach language
847
  // load the CMakeDetermine(LANG)Compiler.cmake file to find
848
  // the compiler
849
850
0
  for (std::string const& lang : languages) {
851
0
    needSetLanguageEnabledMaps[lang] = false;
852
853
0
    if (lang == "Rust" &&
854
0
        !cmExperimental::HasSupportEnabled(*this->Makefiles[0].get(),
855
0
                                           cmExperimental::Feature::Rust)) {
856
0
      mf->IssueMessage(MessageType::FATAL_ERROR,
857
0
                       "Experimental Rust support is not enabled.");
858
0
      cmSystemTools::SetFatalErrorOccurred();
859
0
      return;
860
0
    }
861
862
0
    if (lang == "NONE") {
863
0
      this->SetLanguageEnabled("NONE", mf);
864
0
      continue;
865
0
    }
866
    // Compiler information may have already been detected and saved.
867
    // Load it if we have not enabled the language anywhere yet, or
868
    // if we have not loaded compiler information in this directory.
869
0
    if (!this->GetLanguageEnabled(lang) ||
870
0
        !mf->GetDefinition(cmStrCat("CMAKE_", lang, "_COMPILER_LOADED"))) {
871
0
      fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
872
873
      // If the existing build tree was already configured with this
874
      // version of CMake then try to load the configured file first
875
      // to avoid duplicate compiler tests.
876
0
      if (cmSystemTools::FileExists(fpath)) {
877
0
        if (!mf->ReadListFile(fpath)) {
878
0
          cmSystemTools::Error(
879
0
            cmStrCat("Could not find cmake module file: ", fpath));
880
0
        }
881
        // if this file was found then the language was already determined
882
        // to be working
883
0
        needTestLanguage[lang] = false;
884
0
        this->SetLanguageEnabledFlag(lang, mf);
885
0
        needSetLanguageEnabledMaps[lang] = true;
886
        // this can only be called after loading CMake(LANG)Compiler.cmake
887
0
      }
888
0
    }
889
890
0
    if (!this->GetLanguageEnabled(lang)) {
891
0
      if (this->CMakeInstance->GetIsInTryCompile()) {
892
0
        cmSystemTools::Error("This should not have happened. "
893
0
                             "If you see this message, you are probably "
894
0
                             "using a broken CMakeLists.txt file or a "
895
0
                             "problematic release of CMake");
896
0
      }
897
      // if the CMake(LANG)Compiler.cmake file was not found then
898
      // load CMakeDetermine(LANG)Compiler.cmake
899
0
      std::string determineCompiler =
900
0
        cmStrCat("CMakeDetermine", lang, "Compiler.cmake");
901
0
      std::string determineFile = mf->GetModulesFile(determineCompiler);
902
0
      if (!mf->ReadListFile(determineFile)) {
903
0
        cmSystemTools::Error(
904
0
          cmStrCat("Could not find cmake module file: ", determineCompiler));
905
0
      }
906
0
      if (cmSystemTools::GetFatalErrorOccurred()) {
907
0
        return;
908
0
      }
909
0
      needTestLanguage[lang] = true;
910
      // Some generators like visual studio should not use the env variables
911
      // So the global generator can specify that in this variable
912
0
      if ((mf->GetPolicyStatus(cmPolicies::CMP0132) == cmPolicies::OLD ||
913
0
           mf->GetPolicyStatus(cmPolicies::CMP0132) == cmPolicies::WARN) &&
914
0
          !mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV")) {
915
        // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER
916
        // into the environment, in case user scripts want to run
917
        // configure, or sub cmakes
918
0
        std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
919
0
        std::string compilerEnv =
920
0
          cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
921
0
        std::string const& envVar = mf->GetRequiredDefinition(compilerEnv);
922
0
        std::string const& envVarValue =
923
0
          mf->GetRequiredDefinition(compilerName);
924
0
        std::string env = cmStrCat(envVar, '=', envVarValue);
925
0
        cmSystemTools::PutEnv(env);
926
0
      }
927
928
      // if determineLanguage was called then load the file it
929
      // configures CMake(LANG)Compiler.cmake
930
0
      fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
931
0
      if (!mf->ReadListFile(fpath)) {
932
0
        cmSystemTools::Error(
933
0
          cmStrCat("Could not find cmake module file: ", fpath));
934
0
      }
935
0
      this->SetLanguageEnabledFlag(lang, mf);
936
0
      needSetLanguageEnabledMaps[lang] = true;
937
      // this can only be called after loading CMake(LANG)Compiler.cmake
938
      // the language must be enabled for try compile to work, but we do
939
      // not know if it is a working compiler yet so set the test language
940
      // flag
941
0
      needTestLanguage[lang] = true;
942
0
    } // end if(!this->GetLanguageEnabled(lang) )
943
0
  } // end loop over languages
944
945
  // **** Load the system specific information if not yet loaded
946
0
  if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED")) {
947
0
    fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
948
0
    if (!mf->ReadListFile(fpath)) {
949
0
      cmSystemTools::Error("Could not find cmake module file: "
950
0
                           "CMakeSystemSpecificInformation.cmake");
951
0
    }
952
0
  }
953
  // loop over languages again loading CMake(LANG)Information.cmake
954
  //
955
0
  for (std::string const& lang : languages) {
956
0
    if (lang == "NONE") {
957
0
      this->SetLanguageEnabled("NONE", mf);
958
0
      continue;
959
0
    }
960
961
    // Check that the compiler was found.
962
0
    std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
963
0
    std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
964
0
    std::ostringstream noCompiler;
965
0
    cmValue compilerFile = mf->GetDefinition(compilerName);
966
0
    if (!cmNonempty(compilerFile) || cmIsNOTFOUND(*compilerFile)) {
967
0
      noCompiler << "No " << compilerName << " could be found.\n";
968
0
    } else if ((lang != "RC") && (lang != "ASM_MARMASM") &&
969
0
               (lang != "ASM_MASM")) {
970
0
      if (!cmSystemTools::FileIsFullPath(*compilerFile)) {
971
        /* clang-format off */
972
0
        noCompiler <<
973
0
          "The " << compilerName << ":\n"
974
0
          "  " << *compilerFile << "\n"
975
0
          "is not a full path and was not found in the PATH."
976
#ifdef _WIN32
977
          "  Perhaps the extension is missing?"
978
#endif
979
0
          "\n"
980
0
          ;
981
        /* clang-format on */
982
0
      } else if (!cmSystemTools::FileExists(*compilerFile)) {
983
        /* clang-format off */
984
0
        noCompiler <<
985
0
          "The " << compilerName << ":\n"
986
0
          "  " << *compilerFile << "\n"
987
0
          "is not a full path to an existing compiler tool.\n"
988
0
          ;
989
        /* clang-format on */
990
0
      }
991
0
    }
992
0
    if (!noCompiler.str().empty()) {
993
      // Skip testing this language since the compiler is not found.
994
0
      needTestLanguage[lang] = false;
995
0
      if (!optional) {
996
        // The compiler was not found and it is not optional.  Remove
997
        // CMake(LANG)Compiler.cmake so we try again next time CMake runs.
998
0
        std::string compilerLangFile =
999
0
          cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
1000
0
        cmSystemTools::RemoveFile(compilerLangFile);
1001
0
        if (!this->CMakeInstance->GetIsInTryCompile()) {
1002
0
          this->PrintCompilerAdvice(noCompiler, lang,
1003
0
                                    mf->GetDefinition(compilerEnv));
1004
0
          mf->IssueMessage(MessageType::FATAL_ERROR, noCompiler.str());
1005
0
          fatalError = true;
1006
0
        }
1007
0
      }
1008
0
    }
1009
1010
0
    std::string langLoadedVar =
1011
0
      cmStrCat("CMAKE_", lang, "_INFORMATION_LOADED");
1012
0
    if (!mf->GetDefinition(langLoadedVar)) {
1013
0
      fpath = cmStrCat("CMake", lang, "Information.cmake");
1014
0
      std::string informationFile = mf->GetModulesFile(fpath);
1015
0
      if (informationFile.empty()) {
1016
0
        cmSystemTools::Error(
1017
0
          cmStrCat("Could not find cmake module file: ", fpath));
1018
0
      } else if (!mf->ReadListFile(informationFile)) {
1019
0
        cmSystemTools::Error(
1020
0
          cmStrCat("Could not process cmake module file: ", informationFile));
1021
0
      }
1022
0
    }
1023
0
    if (needSetLanguageEnabledMaps[lang]) {
1024
0
      this->SetLanguageEnabledMaps(lang, mf);
1025
0
    }
1026
1027
    // At this point we have enough info for a try compile.
1028
0
    this->LanguagesReadyForTryCompile.insert(lang);
1029
1030
    // Test the compiler for the language just setup
1031
    // (but only if a compiler has been actually found)
1032
    // If the language is untested then test it now with a try compile.
1033
0
    if (needTestLanguage[lang]) {
1034
0
      if (!this->CMakeInstance->GetIsInTryCompile()) {
1035
0
        std::string testLang = cmStrCat("CMakeTest", lang, "Compiler.cmake");
1036
0
        std::string ifpath = mf->GetModulesFile(testLang);
1037
0
        if (!mf->ReadListFile(ifpath)) {
1038
0
          cmSystemTools::Error(
1039
0
            cmStrCat("Could not find cmake module file: ", testLang));
1040
0
        }
1041
0
        std::string compilerWorks =
1042
0
          cmStrCat("CMAKE_", lang, "_COMPILER_WORKS");
1043
        // if the compiler did not work, then remove the
1044
        // CMake(LANG)Compiler.cmake file so that it will get tested the
1045
        // next time cmake is run
1046
0
        if (!mf->IsOn(compilerWorks)) {
1047
0
          std::string compilerLangFile =
1048
0
            cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
1049
0
          cmSystemTools::RemoveFile(compilerLangFile);
1050
0
        }
1051
0
      } // end if in try compile
1052
0
    } // end need test language
1053
1054
    // load linker configuration, if required
1055
0
    if (mf->IsOn(cmStrCat("CMAKE_", lang, "_COMPILER_WORKS")) &&
1056
0
        mf->IsOn(cmStrCat("CMAKE_", lang, "_USE_LINKER_INFORMATION"))) {
1057
0
      std::string langLinkerLoadedVar =
1058
0
        cmStrCat("CMAKE_", lang, "_LINKER_INFORMATION_LOADED");
1059
0
      if (!mf->GetDefinition(langLinkerLoadedVar)) {
1060
0
        fpath = cmStrCat("CMake", lang, "LinkerInformation.cmake");
1061
0
        std::string informationFile = mf->GetModulesFile(fpath);
1062
0
        if (informationFile.empty()) {
1063
0
          informationFile = mf->GetModulesFile(cmStrCat("Internal/", fpath));
1064
0
        }
1065
0
        if (informationFile.empty()) {
1066
0
          cmSystemTools::Error(
1067
0
            cmStrCat("Could not find cmake module file: ", fpath));
1068
0
        } else if (!mf->ReadListFile(informationFile)) {
1069
0
          cmSystemTools::Error(cmStrCat(
1070
0
            "Could not process cmake module file: ", informationFile));
1071
0
        }
1072
0
      }
1073
1074
0
      if (needTestLanguage[lang]) {
1075
0
        if (!this->CMakeInstance->GetIsInTryCompile()) {
1076
0
          std::string testLang =
1077
0
            cmStrCat("Internal/CMakeInspect", lang, "Linker.cmake");
1078
0
          std::string ifpath = mf->GetModulesFile(testLang);
1079
0
          if (!mf->ReadListFile(ifpath)) {
1080
0
            cmSystemTools::Error(
1081
0
              cmStrCat("Could not find cmake module file: ", testLang));
1082
0
          }
1083
0
        }
1084
0
      }
1085
0
    }
1086
1087
    // Translate compiler ids for compatibility.
1088
0
    this->CheckCompilerIdCompatibility(mf, lang);
1089
0
  } // end for each language
1090
1091
  // Now load files that can override any settings on the platform or for
1092
  // the project First load the project compatibility file if it is in
1093
  // cmake
1094
0
  std::string projectCompatibility =
1095
0
    cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/",
1096
0
             mf->GetSafeDefinition("PROJECT_NAME"), "Compatibility.cmake");
1097
0
  if (cmSystemTools::FileExists(projectCompatibility)) {
1098
0
    mf->ReadListFile(projectCompatibility);
1099
0
  }
1100
  // Inform any extra generator of the new language.
1101
0
  if (this->ExtraGenerator) {
1102
0
    this->ExtraGenerator->EnableLanguage(languages, mf, false);
1103
0
  }
1104
1105
0
  if (fatalError) {
1106
0
    cmSystemTools::SetFatalErrorOccurred();
1107
0
  }
1108
1109
0
  for (std::string const& lang : cur_languages) {
1110
0
    this->LanguagesInProgress.erase(lang);
1111
0
  }
1112
0
}
1113
1114
void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
1115
                                            std::string const& lang,
1116
                                            cmValue envVar) const
1117
0
{
1118
  // Subclasses override this method if they do not support this advice.
1119
0
  os << "Tell CMake where to find the compiler by setting ";
1120
0
  if (envVar) {
1121
0
    os << "either the environment variable \"" << *envVar << "\" or ";
1122
0
  }
1123
0
  os << "the CMake cache entry CMAKE_" << lang
1124
0
     << "_COMPILER "
1125
0
        "to the full path to the compiler, or to the compiler name "
1126
0
        "if it is in the PATH.";
1127
0
}
1128
1129
void cmGlobalGenerator::CheckCompilerIdCompatibility(
1130
  cmMakefile* mf, std::string const& lang) const
1131
0
{
1132
0
  std::string compilerIdVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID");
1133
0
  std::string const compilerId = mf->GetSafeDefinition(compilerIdVar);
1134
1135
0
  if (compilerId == "XLClang") {
1136
0
    switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
1137
0
      case cmPolicies::WARN:
1138
0
        if (!this->CMakeInstance->GetIsInTryCompile() &&
1139
0
            mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
1140
0
          mf->IssuePolicyWarning(
1141
0
            cmPolicies::CMP0089, {},
1142
0
            cmStrCat(
1143
0
              "Converting "_s, lang,
1144
0
              R"( compiler id "XLClang" to "XL" for compatibility.)"_s));
1145
0
        }
1146
0
        CM_FALLTHROUGH;
1147
0
      case cmPolicies::OLD:
1148
        // OLD behavior is to convert XLClang to XL.
1149
0
        mf->AddDefinition(compilerIdVar, "XL");
1150
0
        break;
1151
0
      case cmPolicies::NEW:
1152
        // NEW behavior is to keep AppleClang.
1153
0
        break;
1154
0
    }
1155
0
  }
1156
1157
0
  if (compilerId == "LCC") {
1158
0
    switch (mf->GetPolicyStatus(cmPolicies::CMP0129)) {
1159
0
      case cmPolicies::WARN:
1160
0
        if (!this->CMakeInstance->GetIsInTryCompile() &&
1161
0
            mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0129")) {
1162
0
          mf->IssuePolicyWarning(
1163
0
            cmPolicies::CMP0129, {},
1164
0
            cmStrCat("Converting "_s, lang,
1165
0
                     R"( compiler id "LCC" to "GNU" for compatibility.)"_s));
1166
0
        }
1167
0
        CM_FALLTHROUGH;
1168
0
      case cmPolicies::OLD:
1169
        // OLD behavior is to convert LCC to GNU.
1170
0
        mf->AddDefinition(compilerIdVar, "GNU");
1171
0
        if (lang == "C") {
1172
0
          mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1");
1173
0
        } else if (lang == "CXX") {
1174
0
          mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1");
1175
0
        } else if (lang == "Fortran") {
1176
0
          mf->AddDefinition("CMAKE_COMPILER_IS_GNUG77", "1");
1177
0
        }
1178
0
        {
1179
          // Fix compiler versions.
1180
0
          std::string version = cmStrCat("CMAKE_", lang, "_COMPILER_VERSION");
1181
0
          std::string emulated = cmStrCat("CMAKE_", lang, "_SIMULATE_VERSION");
1182
0
          std::string emulatedId = cmStrCat("CMAKE_", lang, "_SIMULATE_ID");
1183
0
          std::string const& actual = mf->GetRequiredDefinition(emulated);
1184
0
          mf->AddDefinition(version, actual);
1185
0
          mf->RemoveDefinition(emulatedId);
1186
0
          mf->RemoveDefinition(emulated);
1187
0
        }
1188
0
        break;
1189
0
      case cmPolicies::NEW:
1190
        // NEW behavior is to keep LCC.
1191
0
        break;
1192
0
    }
1193
0
  }
1194
0
}
1195
1196
std::string cmGlobalGenerator::GetLanguageOutputExtension(
1197
  cmSourceFile const& source) const
1198
0
{
1199
0
  std::string const& lang = source.GetLanguage();
1200
0
  if (!lang.empty()) {
1201
0
    if (lang == "Rust") {
1202
      // Rust source file can be compiled into different type of outputs. So
1203
      // we need to change the extension based on the Rust_EMIT property.
1204
0
      if (cmValue const rustEmit = source.GetRustEmitProperty()) {
1205
0
        return this->GetRustEmitOutputExtension(rustEmit);
1206
0
      }
1207
0
    }
1208
0
    return this->GetLanguageOutputExtension(lang);
1209
0
  }
1210
  // if no language is found then check to see if it is already an
1211
  // output extension for some language.  In that case it should be ignored
1212
  // and in this map, so it will not be compiled but will just be used.
1213
0
  std::string const& ext = source.GetExtension();
1214
0
  if (!ext.empty()) {
1215
0
    if (this->OutputExtensions.count(ext)) {
1216
0
      return ext;
1217
0
    }
1218
0
  }
1219
0
  return "";
1220
0
}
1221
1222
std::string cmGlobalGenerator::GetLanguageOutputExtension(
1223
  std::string const& lang) const
1224
0
{
1225
0
  auto const it = this->LanguageToOutputExtension.find(lang);
1226
0
  if (it != this->LanguageToOutputExtension.end()) {
1227
0
    return it->second;
1228
0
  }
1229
0
  return "";
1230
0
}
1231
1232
std::string cmGlobalGenerator::GetRustEmitOutputExtension(
1233
  std::string const& emitValue) const
1234
0
{
1235
0
  auto const it = this->RustEmitToOutputExtension.find(emitValue);
1236
0
  if (it != this->RustEmitToOutputExtension.end()) {
1237
0
    return it->second;
1238
0
  }
1239
0
  return "";
1240
0
}
1241
1242
cm::string_view cmGlobalGenerator::GetLanguageFromExtension(
1243
  cm::string_view ext) const
1244
0
{
1245
  // if there is an extension and it starts with . then move past the
1246
  // . because the extensions are not stored with a .  in the map
1247
0
  if (ext.empty()) {
1248
0
    return "";
1249
0
  }
1250
0
  if (ext.front() == '.') {
1251
0
    ext = ext.substr(1);
1252
0
  }
1253
0
#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
1254
0
  auto const it = this->ExtensionToLanguage.find(ext);
1255
#else
1256
  auto const it = this->ExtensionToLanguage.find(std::string(ext));
1257
#endif
1258
0
  if (it != this->ExtensionToLanguage.end()) {
1259
0
    return it->second;
1260
0
  }
1261
0
  return "";
1262
0
}
1263
1264
/* SetLanguageEnabled() is now split in two parts:
1265
at first the enabled-flag is set. This can then be used in EnabledLanguage()
1266
for checking whether the language is already enabled. After setting this
1267
flag still the values from the cmake variables have to be copied into the
1268
internal maps, this is done in SetLanguageEnabledMaps() which is called
1269
after the system- and compiler specific files have been loaded.
1270
1271
This split was done originally so that compiler-specific configuration
1272
files could change the object file extension
1273
(CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied
1274
to the C++ maps.
1275
*/
1276
void cmGlobalGenerator::SetLanguageEnabled(std::string const& l,
1277
                                           cmMakefile* mf)
1278
0
{
1279
0
  this->SetLanguageEnabledFlag(l, mf);
1280
0
  this->SetLanguageEnabledMaps(l, mf);
1281
0
}
1282
1283
void cmGlobalGenerator::SetLanguageEnabledFlag(std::string const& l,
1284
                                               cmMakefile* mf)
1285
0
{
1286
0
  this->CMakeInstance->GetState()->SetLanguageEnabled(l);
1287
1288
  // Fill the language-to-extension map with the current variable
1289
  // settings to make sure it is available for the try_compile()
1290
  // command source file signature.  In SetLanguageEnabledMaps this
1291
  // will be done again to account for any compiler- or
1292
  // platform-specific entries.
1293
0
  this->FillExtensionToLanguageMap(l, mf);
1294
0
}
1295
1296
void cmGlobalGenerator::SetLanguageEnabledMaps(std::string const& l,
1297
                                               cmMakefile* mf)
1298
0
{
1299
  // use LanguageToLinkerPreference to detect whether this functions has
1300
  // run before
1301
0
  if (cm::contains(this->LanguageToLinkerPreference, l)) {
1302
0
    return;
1303
0
  }
1304
1305
0
  std::string linkerPrefVar = cmStrCat("CMAKE_", l, "_LINKER_PREFERENCE");
1306
0
  cmValue linkerPref = mf->GetDefinition(linkerPrefVar);
1307
0
  int preference = 0;
1308
0
  if (cmNonempty(linkerPref)) {
1309
0
    if (sscanf(linkerPref->c_str(), "%d", &preference) != 1) {
1310
      // backward compatibility: before 2.6 LINKER_PREFERENCE
1311
      // was either "None" or "Preferred", and only the first character was
1312
      // tested. So if there is a custom language out there and it is
1313
      // "Preferred", set its preference high
1314
0
      if ((*linkerPref)[0] == 'P') {
1315
0
        preference = 100;
1316
0
      } else {
1317
0
        preference = 0;
1318
0
      }
1319
0
    }
1320
0
  }
1321
1322
0
  if (preference < 0) {
1323
0
    std::string msg =
1324
0
      cmStrCat(linkerPrefVar, " is negative, adjusting it to 0");
1325
0
    cmSystemTools::Message(msg, "Warning");
1326
0
    preference = 0;
1327
0
  }
1328
1329
0
  this->LanguageToLinkerPreference[l] = preference;
1330
1331
0
  std::string outputExtensionVar = cmStrCat("CMAKE_", l, "_OUTPUT_EXTENSION");
1332
0
  if (cmValue p = mf->GetDefinition(outputExtensionVar)) {
1333
0
    std::string outputExtension = *p;
1334
0
    this->LanguageToOutputExtension[l] = outputExtension;
1335
0
    this->OutputExtensions[outputExtension] = outputExtension;
1336
0
    if (cmHasPrefix(outputExtension, '.')) {
1337
0
      outputExtension = outputExtension.substr(1);
1338
0
      this->OutputExtensions[outputExtension] = outputExtension;
1339
0
    }
1340
0
  }
1341
1342
0
  if (l == "Rust") {
1343
0
    std::string const emitValues =
1344
0
      mf->GetSafeDefinition("CMAKE_Rust_EMIT_VALUES");
1345
0
    cmList emitList{ emitValues };
1346
0
    for (std::string const& v : emitList) {
1347
0
      std::string emitOutputExtension =
1348
0
        cmStrCat("CMAKE_Rust_EMIT_", v, "_OUTPUT_EXTENSION");
1349
0
      if (cmValue outputExtension = mf->GetDefinition(emitOutputExtension)) {
1350
0
        this->RustEmitToOutputExtension[v] = outputExtension;
1351
0
      }
1352
0
    }
1353
0
  }
1354
1355
  // The map was originally filled by SetLanguageEnabledFlag, but
1356
  // since then the compiler- and platform-specific files have been
1357
  // loaded which might have added more entries.
1358
0
  this->FillExtensionToLanguageMap(l, mf);
1359
1360
0
  std::string ignoreExtensionsVar =
1361
0
    cmStrCat("CMAKE_", l, "_IGNORE_EXTENSIONS");
1362
0
  std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar);
1363
0
  cmList extensionList{ ignoreExts };
1364
0
  for (std::string const& i : extensionList) {
1365
0
    this->IgnoreExtensions[i] = true;
1366
0
  }
1367
0
}
1368
1369
void cmGlobalGenerator::FillExtensionToLanguageMap(std::string const& l,
1370
                                                   cmMakefile* mf)
1371
0
{
1372
0
  std::string extensionsVar = cmStrCat("CMAKE_", l, "_SOURCE_FILE_EXTENSIONS");
1373
0
  std::string const& exts = mf->GetSafeDefinition(extensionsVar);
1374
0
  cmList extensionList{ exts };
1375
0
  for (std::string const& i : extensionList) {
1376
0
    this->ExtensionToLanguage[i] = l;
1377
0
  }
1378
0
}
1379
1380
cmValue cmGlobalGenerator::GetGlobalSetting(std::string const& name) const
1381
0
{
1382
0
  assert(!this->Makefiles.empty());
1383
0
  return this->Makefiles[0]->GetDefinition(name);
1384
0
}
1385
1386
bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const
1387
0
{
1388
0
  assert(!this->Makefiles.empty());
1389
0
  return this->Makefiles[0]->IsOn(name);
1390
0
}
1391
1392
std::string cmGlobalGenerator::GetSafeGlobalSetting(
1393
  std::string const& name) const
1394
0
{
1395
0
  assert(!this->Makefiles.empty());
1396
0
  return this->Makefiles[0]->GetDefinition(name);
1397
0
}
1398
1399
bool cmGlobalGenerator::IgnoreFile(cm::string_view ext) const
1400
0
{
1401
0
  if (!this->GetLanguageFromExtension(ext).empty()) {
1402
0
    return false;
1403
0
  }
1404
0
  return (this->IgnoreExtensions.count(std::string(ext)) > 0);
1405
0
}
1406
1407
bool cmGlobalGenerator::GetLanguageEnabled(std::string const& l) const
1408
0
{
1409
0
  return this->CMakeInstance->GetState()->GetLanguageEnabled(l);
1410
0
}
1411
1412
void cmGlobalGenerator::ClearEnabledLanguages()
1413
0
{
1414
0
  this->CMakeInstance->GetState()->ClearEnabledLanguages();
1415
0
}
1416
1417
void cmGlobalGenerator::CreateLocalGenerators()
1418
0
{
1419
0
  this->LocalGeneratorSearchIndex.clear();
1420
0
  this->LocalGenerators.clear();
1421
0
  this->LocalGenerators.reserve(this->Makefiles.size());
1422
0
  for (auto const& m : this->Makefiles) {
1423
0
    auto lg = this->CreateLocalGenerator(m.get());
1424
0
    this->IndexLocalGenerator(lg.get());
1425
0
    this->LocalGenerators.push_back(std::move(lg));
1426
0
  }
1427
0
}
1428
1429
void cmGlobalGenerator::Configure()
1430
0
{
1431
0
  this->FirstTimeProgress = 0.0f;
1432
0
  this->ClearGeneratorMembers();
1433
0
  this->NextDeferId = 0;
1434
1435
0
  cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
1436
1437
0
  snapshot.GetDirectory().SetCurrentSource(
1438
0
    this->CMakeInstance->GetHomeDirectory());
1439
0
  snapshot.GetDirectory().SetCurrentBinary(
1440
0
    this->CMakeInstance->GetHomeOutputDirectory());
1441
1442
0
  auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot);
1443
0
  auto* dirMf = dirMfu.get();
1444
0
  this->Makefiles.push_back(std::move(dirMfu));
1445
0
  dirMf->SetRecursionDepth(this->RecursionDepth);
1446
0
  this->IndexMakefile(dirMf);
1447
1448
0
  this->BinaryDirectories.insert(
1449
0
    this->CMakeInstance->GetHomeOutputDirectory());
1450
1451
0
  if (this->ExtraGenerator && !this->CMakeInstance->GetIsInTryCompile()) {
1452
0
    this->CMakeInstance->IssueMessage(
1453
0
      MessageType::WARNING,
1454
0
      cmStrCat("Support for \"Extra Generators\" like\n  ",
1455
0
               this->ExtraGenerator->GetName(),
1456
0
               "\nis deprecated and will be removed from a future version "
1457
0
               "of CMake.  IDEs may use the cmake-file-api(7) to view "
1458
0
               "CMake-generated project build trees."));
1459
0
  }
1460
1461
  // now do it
1462
0
  dirMf->Configure();
1463
0
  dirMf->EnforceDirectoryLevelRules();
1464
1465
  // Put a copy of each global target in every directory.
1466
0
  {
1467
0
    std::vector<GlobalTargetInfo> globalTargets;
1468
0
    this->CreateDefaultGlobalTargets(globalTargets);
1469
1470
0
    for (auto const& mf : this->Makefiles) {
1471
0
      for (GlobalTargetInfo const& globalTarget : globalTargets) {
1472
0
        this->CreateGlobalTarget(globalTarget, mf.get());
1473
0
      }
1474
0
    }
1475
0
  }
1476
1477
0
  this->ReserveGlobalTargetCodegen();
1478
1479
  // update the cache entry for the number of local generators, this is used
1480
  // for progress
1481
0
  this->GetCMakeInstance()->AddCacheEntry(
1482
0
    "CMAKE_NUMBER_OF_MAKEFILES", std::to_string(this->Makefiles.size()),
1483
0
    "number of local generators", cmStateEnums::INTERNAL);
1484
0
}
1485
1486
void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
1487
0
{
1488
0
  this->CreateLocalGenerators();
1489
  // Commit side effects only if we are actually generating
1490
0
  if (targetTypes == TargetTypes::AllTargets) {
1491
0
    this->CheckTargetProperties();
1492
0
  }
1493
0
  this->CreateGeneratorTargets(targetTypes);
1494
0
  if (targetTypes == TargetTypes::AllTargets) {
1495
0
    this->ComputeBuildFileGenerators();
1496
0
  }
1497
0
}
1498
1499
void cmGlobalGenerator::CreateImportedGenerationObjects(
1500
  cmMakefile* mf, std::vector<std::string> const& targets,
1501
  std::vector<cmGeneratorTarget const*>& exports)
1502
0
{
1503
0
  this->CreateGenerationObjects(ImportedOnly);
1504
0
  auto const mfit =
1505
0
    std::find_if(this->Makefiles.begin(), this->Makefiles.end(),
1506
0
                 [mf](std::unique_ptr<cmMakefile> const& item) {
1507
0
                   return item.get() == mf;
1508
0
                 });
1509
0
  auto& lg =
1510
0
    this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
1511
0
  for (std::string const& t : targets) {
1512
0
    cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t);
1513
0
    if (gt) {
1514
0
      exports.push_back(gt);
1515
0
    }
1516
0
  }
1517
0
}
1518
1519
cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
1520
  std::string const& filename) const
1521
0
{
1522
0
  auto const it = this->BuildExportSets.find(filename);
1523
0
  return it == this->BuildExportSets.end() ? nullptr : it->second;
1524
0
}
1525
1526
void cmGlobalGenerator::AddCMP0068WarnTarget(std::string const& target)
1527
0
{
1528
0
  this->CMP0068WarnTargets.insert(target);
1529
0
}
1530
1531
bool cmGlobalGenerator::ShouldWarnCMP0210(std::string const& lang)
1532
0
{
1533
0
  return this->WarnedCMP0210Languages.insert(lang).second;
1534
0
}
1535
1536
bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
1537
0
{
1538
  // If the property is not enabled then okay.
1539
0
  if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1540
0
        "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
1541
0
    return true;
1542
0
  }
1543
1544
  // This generator does not support duplicate custom targets.
1545
0
  std::ostringstream e;
1546
  // clang-format off
1547
0
  e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
1548
0
       "global property.  "
1549
0
       "The \"" << this->GetName() << "\" generator does not support "
1550
0
       "duplicate custom targets.  "
1551
0
       "Consider using a Makefiles generator or fix the project to not "
1552
0
       "use duplicate target names.";
1553
  // clang-format on
1554
0
  cmSystemTools::Error(e.str());
1555
0
  return false;
1556
0
}
1557
1558
void cmGlobalGenerator::ComputeBuildFileGenerators()
1559
0
{
1560
0
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1561
0
    cmLocalGenerator* lg = this->LocalGenerators[i].get();
1562
0
    for (auto const& g : this->Makefiles[i]->GetExportBuildFileGenerators()) {
1563
0
      g->Compute(lg);
1564
0
    }
1565
0
#ifndef CMAKE_BOOTSTRAP
1566
0
    for (auto const& g : this->Makefiles[i]->GetBuildSbomGenerators()) {
1567
0
      g->Compute(lg);
1568
0
    }
1569
0
#endif
1570
0
  }
1571
0
}
1572
1573
bool cmGlobalGenerator::UnsupportedVariableIsDefined(std::string const& name,
1574
                                                     bool supported) const
1575
0
{
1576
0
  if (!supported && this->Makefiles.front()->GetDefinition(name)) {
1577
0
    std::ostringstream e;
1578
    /* clang-format off */
1579
0
    e <<
1580
0
      "Generator\n"
1581
0
      "  " << this->GetName() << "\n"
1582
0
      "does not support variable\n"
1583
0
      "  " << name << "\n"
1584
0
      "but it has been specified."
1585
0
      ;
1586
    /* clang-format on */
1587
0
    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
1588
0
    return true;
1589
0
  }
1590
1591
0
  return false;
1592
0
}
1593
1594
bool cmGlobalGenerator::Compute()
1595
0
{
1596
  // Make sure unsupported variables are not used.
1597
0
  if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE",
1598
0
                                         this->SupportsDefaultBuildType())) {
1599
0
    return false;
1600
0
  }
1601
0
  if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS",
1602
0
                                         this->SupportsCrossConfigs())) {
1603
0
    return false;
1604
0
  }
1605
0
  if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS",
1606
0
                                         this->SupportsDefaultConfigs())) {
1607
0
    return false;
1608
0
  }
1609
0
  if (!this->InspectConfigTypeVariables()) {
1610
0
    return false;
1611
0
  }
1612
1613
0
  if (cmValue v = this->CMakeInstance->GetCacheDefinition(
1614
0
        "CMAKE_INTERMEDIATE_DIR_STRATEGY")) {
1615
0
    this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_INTERMEDIATE_DIR_STRATEGY");
1616
0
    if (*v == "FULL") {
1617
0
      this->IntDirStrategy = IntermediateDirStrategy::Full;
1618
0
    } else if (*v == "SHORT") {
1619
0
      this->IntDirStrategy = IntermediateDirStrategy::Short;
1620
0
    } else {
1621
0
      this->GetCMakeInstance()->IssueMessage(
1622
0
        MessageType::FATAL_ERROR,
1623
0
        cmStrCat("Unsupported intermediate directory strategy '", *v, '\''));
1624
0
      return false;
1625
0
    }
1626
0
  }
1627
0
  if (cmValue v = this->CMakeInstance->GetCacheDefinition(
1628
0
        "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY")) {
1629
0
    this->GetCMakeInstance()->MarkCliAsUsed(
1630
0
      "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY");
1631
0
    if (*v == "FULL") {
1632
0
      this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Full;
1633
0
    } else if (*v == "SHORT") {
1634
0
      this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Short;
1635
0
    } else {
1636
0
      this->GetCMakeInstance()->IssueMessage(
1637
0
        MessageType::FATAL_ERROR,
1638
0
        cmStrCat("Unsupported autogen intermediate directory strategy '", *v,
1639
0
                 '\''));
1640
0
      return false;
1641
0
    }
1642
0
  }
1643
1644
  // Some generators track files replaced during the Generate.
1645
  // Start with an empty vector:
1646
0
  this->FilesReplacedDuringGenerate.clear();
1647
1648
  // clear targets to issue warning CMP0068 for
1649
0
  this->CMP0068WarnTargets.clear();
1650
1651
  // Check whether this generator is allowed to run.
1652
0
  if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
1653
0
    return false;
1654
0
  }
1655
0
  this->FinalizeTargetConfiguration();
1656
1657
0
  if (!this->AddBuildDatabaseTargets()) {
1658
0
    return false;
1659
0
  }
1660
1661
0
  this->CreateGenerationObjects();
1662
1663
  // at this point this->LocalGenerators has been filled,
1664
  // so create the map from project name to vector of local generators
1665
0
  this->FillProjectMap();
1666
1667
0
  this->CreateFileGenerateOutputs();
1668
1669
  // Iterate through all targets and add verification targets for header sets
1670
0
  if (!this->AddHeaderSetVerification()) {
1671
0
    return false;
1672
0
  }
1673
1674
0
#ifndef CMAKE_BOOTSTRAP
1675
0
  this->QtAutoGen =
1676
0
    cm::make_unique<cmQtAutoGenGlobalInitializer>(this->LocalGenerators);
1677
0
  if (!this->QtAutoGen->InitializeCustomTargets()) {
1678
0
    return false;
1679
0
  }
1680
0
#endif
1681
1682
  // Perform up-front computation in order to handle errors (such as unknown
1683
  // features) at this point. While processing the compile features we also
1684
  // calculate and cache the language standard required by the compile
1685
  // features.
1686
  //
1687
  // Synthetic targets performed this inside of
1688
  // `cmLocalGenerator::DiscoverSyntheticTargets`
1689
0
  for (auto const& localGen : this->LocalGenerators) {
1690
0
    if (!localGen->ComputeTargetCompileFeatures()) {
1691
0
      return false;
1692
0
    }
1693
0
  }
1694
1695
  // We now have all targets set up. Add the `@cmake_cxx_std` target as a link
1696
  // dependency to all targets which need it.
1697
  //
1698
  // Synthetic targets performed this inside of
1699
  // `cmLocalGenerator::DiscoverSyntheticTargets`
1700
0
  if (!this->ApplyCXXStdTarget()) {
1701
0
    return false;
1702
0
  }
1703
1704
  // Iterate through all targets and set up C++20 module targets.
1705
  // Create target templates for each imported target with C++20 modules.
1706
  // INTERFACE library with BMI-generating rules and a collation step?
1707
  // Maybe INTERFACE libraries with modules files should just do BMI-only?
1708
  // Make `add_dependencies(imported_target
1709
  // $<$<TARGET_NAME_IF_EXISTS:uses_imported>:synth1>
1710
  // $<$<TARGET_NAME_IF_EXISTS:other_uses_imported>:synth2>)`
1711
  //
1712
  // Note that synthetic target creation performs the above marked
1713
  // steps on the created targets.
1714
0
  if (!this->DiscoverSyntheticTargets()) {
1715
0
    return false;
1716
0
  }
1717
1718
  // Perform after-generator-target generator actions. These involve collecting
1719
  // information gathered during the construction of generator targets.
1720
0
  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
1721
0
    this->Makefiles[i]->GenerateAfterGeneratorTargets(
1722
0
      *this->LocalGenerators[i]);
1723
0
  }
1724
1725
  // Add generator specific helper commands
1726
0
  for (auto const& localGen : this->LocalGenerators) {
1727
0
    localGen->AddHelperCommands();
1728
0
  }
1729
1730
0
  this->MarkTargetsForPchReuse();
1731
1732
  // Add automatically generated sources (e.g. unity build).
1733
  // Add unity sources after computing compile features.  Unity sources do
1734
  // not change the set of languages or features, but we need to know them
1735
  // to filter out sources that are scanned for C++ module dependencies.
1736
0
  if (!this->AddAutomaticSources()) {
1737
0
    return false;
1738
0
  }
1739
1740
0
#ifndef CMAKE_BOOTSTRAP
1741
0
  bool isTryCompile = this->GetGlobalSetting("IN_TRY_COMPILE").IsOn();
1742
0
  bool sbomEnabled = cmExperimental::HasSupportEnabled(
1743
0
    *this->Makefiles[0], cmExperimental::Feature::GenerateSbom);
1744
1745
  // Automatically generate one SBOM per export set not already tied to an
1746
  // explicit install(SBOM) call.
1747
0
  cmValue sbomFormat = this->GetGlobalSetting("CMAKE_INSTALL_SBOM_FORMATS");
1748
0
  if (sbomFormat.IsSet() && sbomEnabled && !isTryCompile) {
1749
0
    std::string projectName = this->LocalGenerators[0]->GetProjectName();
1750
0
    for (auto& exportSet : this->ExportSets) {
1751
0
      bool isCovered =
1752
0
        std::any_of(this->InstallSbomGenerators.cbegin(),
1753
0
                    this->InstallSbomGenerators.cend(),
1754
0
                    [&exportSet](cmInstallSbomGenerator const* g) {
1755
0
                      return g->CoversExportSet(&exportSet.second);
1756
0
                    });
1757
0
      if (isCovered) {
1758
0
        continue;
1759
0
      }
1760
1761
0
      cmSbomArguments args;
1762
0
      args.ProjectName = projectName;
1763
0
      args.PackageName = exportSet.first;
1764
0
      std::string dest = args.GetDefaultDestination(
1765
0
        cm::InstallDirs::GetLibraryDirectory(this->Makefiles[0].get()));
1766
1767
0
      auto installGen = cm::make_unique<cmInstallSbomGenerator>(
1768
0
        std::vector<cmExportSet*>{ &exportSet.second }, dest, "",
1769
0
        std::vector<std::string>(), "",
1770
0
        cmInstallGenerator::SelectMessageLevel(this->Makefiles[0].get()),
1771
0
        false, std::move(args),
1772
0
        cmInstallGenerator::CaptureContext(this->Makefiles[0].get()));
1773
1774
0
      cmInstallSbomGenerator const* rawPtr = installGen.get();
1775
0
      this->Makefiles[0]->AddInstallGenerator(std::move(installGen));
1776
0
      this->AddInstallSbomGenerator(rawPtr);
1777
0
    }
1778
0
  }
1779
0
#endif
1780
1781
0
  for (auto const& localGen : this->LocalGenerators) {
1782
0
    cmMakefile* mf = localGen->GetMakefile();
1783
0
    for (auto const& g : mf->GetInstallGenerators()) {
1784
0
      if (!g->Compute(localGen.get())) {
1785
0
        return false;
1786
0
      }
1787
0
    }
1788
0
  }
1789
1790
0
  this->AddExtraIDETargets();
1791
1792
0
#ifndef CMAKE_BOOTSTRAP
1793
0
  for (auto const& localGen : this->LocalGenerators) {
1794
0
    localGen->ResolveSourceGroupGenex();
1795
0
  }
1796
0
#endif
1797
1798
  // Trace the dependencies, after that no custom commands should be added
1799
  // because their dependencies might not be handled correctly
1800
0
  for (auto const& localGen : this->LocalGenerators) {
1801
0
    localGen->TraceDependencies();
1802
0
  }
1803
1804
  // Make sure that all (non-imported) targets have source files added!
1805
0
  if (this->CheckTargetsForMissingSources()) {
1806
0
    return false;
1807
0
  }
1808
1809
0
  this->ForceLinkerLanguages();
1810
1811
  // Compute the manifest of main targets generated.
1812
0
  for (auto const& localGen : this->LocalGenerators) {
1813
0
    localGen->ComputeTargetManifest();
1814
0
  }
1815
1816
  // Compute the inter-target dependencies.
1817
0
  if (!this->ComputeTargetDepends()) {
1818
0
    return false;
1819
0
  }
1820
0
  this->ComputeTargetOrder();
1821
1822
0
  if (this->CheckTargetsForType()) {
1823
0
    return false;
1824
0
  }
1825
1826
0
  for (auto const& localGen : this->LocalGenerators) {
1827
0
    localGen->ComputeHomeRelativeOutputPath();
1828
0
  }
1829
1830
0
  return true;
1831
0
}
1832
1833
void cmGlobalGenerator::Generate()
1834
0
{
1835
  // Create a map from local generator to the complete set of targets
1836
  // it builds by default.
1837
0
  this->InitializeProgressMarks();
1838
1839
0
  this->ProcessEvaluationFiles();
1840
1841
0
  this->CMakeInstance->UpdateProgress("Generating", 0.1f);
1842
1843
0
#ifndef CMAKE_BOOTSTRAP
1844
0
  if (!this->QtAutoGen->SetupCustomTargets()) {
1845
0
    if (!cmSystemTools::GetErrorOccurredFlag()) {
1846
0
      this->GetCMakeInstance()->IssueMessage(
1847
0
        MessageType::FATAL_ERROR,
1848
0
        "Problem setting up custom targets for QtAutoGen");
1849
0
    }
1850
0
    return;
1851
0
  }
1852
0
#endif
1853
1854
  // Generate project files
1855
0
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1856
0
    this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
1857
0
    this->LocalGenerators[i]->Generate();
1858
0
    if (!this->LocalGenerators[i]->GetMakefile()->IsOn(
1859
0
          "CMAKE_SKIP_INSTALL_RULES")) {
1860
0
      this->LocalGenerators[i]->GenerateInstallRules();
1861
0
    }
1862
0
    this->LocalGenerators[i]->GenerateTestFiles();
1863
0
    this->CMakeInstance->UpdateProgress(
1864
0
      "Generating",
1865
0
      0.1f +
1866
0
        0.9f * (static_cast<float>(i) + 1.0f) /
1867
0
          static_cast<float>(this->LocalGenerators.size()));
1868
0
  }
1869
0
  this->SetCurrentMakefile(nullptr);
1870
1871
0
  if (!this->GenerateCPackPropertiesFile()) {
1872
0
    this->GetCMakeInstance()->IssueMessage(
1873
0
      MessageType::FATAL_ERROR, "Could not write CPack properties file.");
1874
0
  }
1875
1876
0
  for (auto& buildExpSet : this->BuildExportSets) {
1877
0
    if (!buildExpSet.second->GenerateImportFile()) {
1878
0
      if (!cmSystemTools::GetErrorOccurredFlag()) {
1879
0
        this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
1880
0
                                               "Could not write export file.");
1881
0
      }
1882
0
      return;
1883
0
    }
1884
0
  }
1885
0
#ifndef CMAKE_BOOTSTRAP
1886
1887
0
  for (auto& sbomGen : this->BuildSbomGenerators) {
1888
0
    for (std::string const& c : this->Makefiles[0]->GetGeneratorConfigs(
1889
0
           cmMakefile::IncludeEmptyConfig)) {
1890
0
      if (!sbomGen->GenerateForBuild(c)) {
1891
0
        if (!cmSystemTools::GetErrorOccurredFlag()) {
1892
0
          this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
1893
0
                                                 "Could not write SBOM file.");
1894
0
        }
1895
0
        return;
1896
0
      }
1897
0
    }
1898
0
  }
1899
0
#endif
1900
  // Update rule hashes.
1901
0
  this->CheckRuleHashes();
1902
1903
0
  this->WriteSummary();
1904
1905
0
  if (this->ExtraGenerator) {
1906
0
    this->ExtraGenerator->Generate();
1907
0
  }
1908
1909
  // Perform validation checks on memoized link structures.
1910
0
  this->CheckTargetLinkLibraries();
1911
1912
0
  if (!this->CMP0068WarnTargets.empty()) {
1913
0
    std::ostringstream w;
1914
    /* clang-format off */
1915
0
    w <<
1916
0
      cmPolicies::GetPolicyWarning(cmPolicies::CMP0068) << "\n"
1917
0
      "For compatibility with older versions of CMake, the install_name "
1918
0
      "fields for the following targets are still affected by RPATH "
1919
0
      "settings:\n"
1920
0
      ;
1921
    /* clang-format on */
1922
0
    for (std::string const& t : this->CMP0068WarnTargets) {
1923
0
      w << ' ' << t << '\n';
1924
0
    }
1925
0
    this->GetCMakeInstance()->IssueDiagnostic(cmDiagnostics::CMD_POLICY,
1926
0
                                              w.str());
1927
0
  }
1928
0
}
1929
1930
#if !defined(CMAKE_BOOTSTRAP)
1931
void cmGlobalGenerator::WriteJsonContent(std::string const& path,
1932
                                         Json::Value const& value) const
1933
0
{
1934
0
  cmsys::ofstream ftmp(path.c_str());
1935
0
  this->JsonWriter->write(value, &ftmp);
1936
0
  ftmp << '\n';
1937
0
  ftmp.close();
1938
0
}
1939
1940
void cmGlobalGenerator::WriteInstallJson() const
1941
0
{
1942
0
  Json::Value index(Json::objectValue);
1943
0
  index["InstallScripts"] = Json::arrayValue;
1944
0
  for (auto const& file : this->InstallScripts) {
1945
0
    index["InstallScripts"].append(file);
1946
0
  }
1947
0
  index["Parallel"] =
1948
0
    this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
1949
0
      "INSTALL_PARALLEL");
1950
0
  if (this->SupportsDefaultConfigs()) {
1951
0
    index["Configs"] = Json::arrayValue;
1952
0
    for (auto const& config : this->GetDefaultConfigs()) {
1953
0
      index["Configs"].append(config);
1954
0
    }
1955
0
  }
1956
0
  this->WriteJsonContent(
1957
0
    cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
1958
0
             "/CMakeFiles/InstallScripts.json"),
1959
0
    index);
1960
0
}
1961
#endif
1962
1963
bool cmGlobalGenerator::ComputeTargetDepends()
1964
0
{
1965
0
  cmComputeTargetDepends ctd(this);
1966
0
  if (!ctd.Compute()) {
1967
0
    return false;
1968
0
  }
1969
0
  for (cmGeneratorTarget const* target : ctd.GetTargets()) {
1970
0
    ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
1971
0
  }
1972
0
  return true;
1973
0
}
1974
1975
std::vector<cmGeneratorTarget*>
1976
cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const
1977
0
{
1978
0
  std::vector<cmGeneratorTarget*> gts;
1979
0
  cm::append(gts, lg->GetGeneratorTargets());
1980
0
  std::sort(gts.begin(), gts.end(),
1981
0
            [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
1982
0
              return this->TargetOrderIndexLess(l, r);
1983
0
            });
1984
0
  return gts;
1985
0
}
1986
1987
void cmGlobalGenerator::ComputeTargetOrder()
1988
0
{
1989
0
  size_t index = 0;
1990
0
  auto const& lgens = this->GetLocalGenerators();
1991
0
  for (auto const& lgen : lgens) {
1992
0
    auto const& targets = lgen->GetGeneratorTargets();
1993
0
    for (auto const& gt : targets) {
1994
0
      this->ComputeTargetOrder(gt.get(), index);
1995
0
    }
1996
0
  }
1997
0
  assert(index == this->TargetOrderIndex.size());
1998
0
}
1999
2000
void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
2001
                                           size_t& index)
2002
0
{
2003
0
  std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0);
2004
0
  auto insertion = this->TargetOrderIndex.insert(value);
2005
0
  if (!insertion.second) {
2006
0
    return;
2007
0
  }
2008
0
  auto entry = insertion.first;
2009
2010
0
  auto const& deps = this->GetTargetDirectDepends(gt);
2011
0
  for (auto const& d : deps) {
2012
0
    this->ComputeTargetOrder(d, index);
2013
0
  }
2014
2015
0
  entry->second = index++;
2016
0
}
2017
2018
bool cmGlobalGenerator::ApplyCXXStdTarget()
2019
0
{
2020
0
  for (auto const& gen : this->LocalGenerators) {
2021
2022
    // tgt->ApplyCXXStdTarget can create a target itself, so we need iterators
2023
    // which won't be invalidated by that target creation
2024
0
    auto const& genTgts = gen->GetGeneratorTargets();
2025
0
    std::vector<cmGeneratorTarget*> existingTgts;
2026
0
    existingTgts.reserve(genTgts.size());
2027
0
    for (auto const& tgt : genTgts) {
2028
0
      existingTgts.push_back(tgt.get());
2029
0
    }
2030
2031
0
    for (auto const& tgt : existingTgts) {
2032
0
      if (!tgt->ApplyCXXStdTarget()) {
2033
0
        return false;
2034
0
      }
2035
0
    }
2036
0
  }
2037
2038
0
  return true;
2039
0
}
2040
2041
bool cmGlobalGenerator::DiscoverSyntheticTargets()
2042
0
{
2043
0
  for (auto const& gen : this->LocalGenerators) {
2044
    // Because DiscoverSyntheticTargets() adds generator targets, we need to
2045
    // cache the existing list of generator targets before starting.
2046
0
    std::vector<cmGeneratorTarget*> genTargets;
2047
0
    genTargets.reserve(gen->GetGeneratorTargets().size());
2048
0
    for (auto const& tgt : gen->GetGeneratorTargets()) {
2049
0
      genTargets.push_back(tgt.get());
2050
0
    }
2051
2052
0
    for (auto* tgt : genTargets) {
2053
0
      std::vector<std::string> const& configs =
2054
0
        tgt->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2055
2056
0
      for (auto const& config : configs) {
2057
0
        if (!tgt->DiscoverSyntheticTargets(config)) {
2058
0
          return false;
2059
0
        }
2060
0
      }
2061
0
    }
2062
0
  }
2063
2064
0
  return true;
2065
0
}
2066
2067
bool cmGlobalGenerator::AddHeaderSetVerification()
2068
0
{
2069
0
  for (auto const& gen : this->LocalGenerators) {
2070
    // Because AddHeaderSetVerification() adds generator targets, we need to
2071
    // cache the existing list of generator targets before starting.
2072
0
    std::vector<cmGeneratorTarget*> genTargets;
2073
0
    genTargets.reserve(gen->GetGeneratorTargets().size());
2074
0
    for (auto const& tgt : gen->GetGeneratorTargets()) {
2075
0
      genTargets.push_back(tgt.get());
2076
0
    }
2077
2078
0
    for (auto* tgt : genTargets) {
2079
0
      if (!tgt->AddHeaderSetVerification()) {
2080
0
        return false;
2081
0
      }
2082
0
    }
2083
0
  }
2084
2085
0
  cmTarget* allVerifyInterfaceTarget =
2086
0
    this->Makefiles.front()->FindTargetToUse(
2087
0
      "all_verify_interface_header_sets", { cm::TargetDomain::NATIVE });
2088
0
  if (allVerifyInterfaceTarget) {
2089
0
    this->LocalGenerators.front()->AddGeneratorTarget(
2090
0
      cm::make_unique<cmGeneratorTarget>(allVerifyInterfaceTarget,
2091
0
                                         this->LocalGenerators.front().get()));
2092
0
  }
2093
0
  cmTarget* allVerifyPrivateTarget = this->Makefiles.front()->FindTargetToUse(
2094
0
    "all_verify_private_header_sets", { cm::TargetDomain::NATIVE });
2095
0
  if (allVerifyPrivateTarget) {
2096
0
    this->LocalGenerators.front()->AddGeneratorTarget(
2097
0
      cm::make_unique<cmGeneratorTarget>(allVerifyPrivateTarget,
2098
0
                                         this->LocalGenerators.front().get()));
2099
0
  }
2100
2101
0
  if (allVerifyInterfaceTarget || allVerifyPrivateTarget) {
2102
0
    cmTarget* allVerifyTarget =
2103
0
      this->GetMakefiles().front()->AddNewUtilityTarget(
2104
0
        "all_verify_header_sets", true);
2105
0
    this->LocalGenerators.front()->AddGeneratorTarget(
2106
0
      cm::make_unique<cmGeneratorTarget>(allVerifyTarget,
2107
0
                                         this->LocalGenerators.front().get()));
2108
0
    if (allVerifyInterfaceTarget) {
2109
0
      allVerifyTarget->AddUtility(allVerifyInterfaceTarget->GetName(), false);
2110
0
    }
2111
0
    if (allVerifyPrivateTarget) {
2112
0
      allVerifyTarget->AddUtility(allVerifyPrivateTarget->GetName(), false);
2113
0
    }
2114
0
  }
2115
2116
0
  return true;
2117
0
}
2118
2119
void cmGlobalGenerator::CreateFileGenerateOutputs()
2120
0
{
2121
0
  for (auto const& lg : this->LocalGenerators) {
2122
0
    lg->CreateEvaluationFileOutputs();
2123
0
  }
2124
0
}
2125
2126
bool cmGlobalGenerator::AddAutomaticSources()
2127
0
{
2128
0
  for (auto const& lg : this->LocalGenerators) {
2129
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
2130
0
      if (!gt->CanCompileSources()) {
2131
0
        continue;
2132
0
      }
2133
0
      lg->AddUnityBuild(gt.get());
2134
0
      lg->AddISPCDependencies(gt.get());
2135
      // Targets that reuse a PCH are handled below.
2136
0
      if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
2137
0
        lg->AddPchDependencies(gt.get());
2138
0
      }
2139
0
      lg->AddXCConfigSources(gt.get());
2140
0
    }
2141
0
  }
2142
0
  for (auto const& lg : this->LocalGenerators) {
2143
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
2144
0
      if (!gt->CanCompileSources()) {
2145
0
        continue;
2146
0
      }
2147
      // Handle targets that reuse a PCH from an above-handled target.
2148
0
      if (gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
2149
0
        lg->AddPchDependencies(gt.get());
2150
0
      }
2151
0
    }
2152
0
  }
2153
  // The above transformations may have changed the classification of sources,
2154
  // e.g., sources that go into unity builds become SourceKindUnityBatched.
2155
  // Clear the source list and classification cache (KindedSources) of all
2156
  // targets so that it will be recomputed correctly by the generators later
2157
  // now that the above transformations are done for all targets.
2158
  // Also clear the link interface cache to support $<TARGET_OBJECTS:objlib>
2159
  // in INTERFACE_LINK_LIBRARIES because the list of object files may have
2160
  // been changed by conversion to a unity build or addition of a PCH source.
2161
0
  for (auto const& lg : this->LocalGenerators) {
2162
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
2163
0
      gt->ClearSourcesCache();
2164
0
      gt->ClearLinkInterfaceCache();
2165
0
    }
2166
0
  }
2167
0
  return true;
2168
0
}
2169
2170
std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
2171
  cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
2172
0
{
2173
0
  return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir);
2174
0
}
2175
2176
std::unique_ptr<cmLinkLineComputer>
2177
cmGlobalGenerator::CreateMSVC60LinkLineComputer(
2178
  cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
2179
0
{
2180
0
  return std::unique_ptr<cmLinkLineComputer>(
2181
0
    cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
2182
0
}
2183
2184
void cmGlobalGenerator::FinalizeTargetConfiguration()
2185
0
{
2186
0
  std::vector<std::string> const langs =
2187
0
    this->CMakeInstance->GetState()->GetEnabledLanguages();
2188
2189
  // Construct per-target generator information.
2190
0
  for (auto const& mf : this->Makefiles) {
2191
0
    cmBTStringRange const compileDefinitions =
2192
0
      mf->GetCompileDefinitionsEntries();
2193
0
    for (auto& target : mf->GetTargets()) {
2194
0
      cmTarget* t = &target.second;
2195
0
      t->FinalizeTargetConfiguration(compileDefinitions);
2196
0
    }
2197
2198
    // The standard include directories for each language
2199
    // should be treated as system include directories.
2200
0
    std::set<std::string> standardIncludesSet;
2201
0
    for (std::string const& li : langs) {
2202
0
      std::string const standardIncludesVar =
2203
0
        cmStrCat("CMAKE_", li, "_STANDARD_INCLUDE_DIRECTORIES");
2204
0
      std::string const& standardIncludesStr =
2205
0
        mf->GetSafeDefinition(standardIncludesVar);
2206
0
      cmList standardIncludesList{ standardIncludesStr };
2207
0
      standardIncludesSet.insert(standardIncludesList.begin(),
2208
0
                                 standardIncludesList.end());
2209
0
    }
2210
0
    mf->AddSystemIncludeDirectories(standardIncludesSet);
2211
0
  }
2212
0
}
2213
2214
void cmGlobalGenerator::CreateGeneratorTargets(
2215
  TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
2216
  std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
2217
0
{
2218
0
  if (targetTypes == AllTargets) {
2219
0
    for (cmTarget* target : mf->GetOrderedTargets()) {
2220
0
      lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg));
2221
0
    }
2222
0
  }
2223
2224
0
  for (cmTarget* t : mf->GetImportedTargets()) {
2225
0
    lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
2226
0
  }
2227
0
}
2228
2229
void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes)
2230
0
{
2231
0
  std::map<cmTarget*, cmGeneratorTarget*> importedMap;
2232
0
  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
2233
0
    auto& mf = this->Makefiles[i];
2234
0
    for (auto const& ownedImpTgt : mf->GetOwnedImportedTargets()) {
2235
0
      cmLocalGenerator* lg = this->LocalGenerators[i].get();
2236
0
      auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
2237
0
      importedMap[ownedImpTgt.get()] = gt.get();
2238
0
      lg->AddOwnedImportedGeneratorTarget(std::move(gt));
2239
0
    }
2240
0
  }
2241
2242
  // Construct per-target generator information.
2243
0
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
2244
0
    this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(),
2245
0
                                 this->LocalGenerators[i].get(), importedMap);
2246
0
  }
2247
0
}
2248
2249
void cmGlobalGenerator::ComputeOutputOwnerIndex()
2250
0
{
2251
0
  this->OutputOwnerIndexComputed = true;
2252
0
  for (auto const& lg : this->LocalGenerators) {
2253
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
2254
0
      if (!gt->IsInBuildSystem()) {
2255
0
        continue;
2256
0
      }
2257
0
      for (cmGeneratorTarget::AllConfigSource const& acs :
2258
0
           gt->GetAllConfigSources(
2259
0
             cmGeneratorTarget::SourceKindCustomCommand)) {
2260
0
        cmCustomCommand const* cc = acs.Source->GetCustomCommand();
2261
0
        if (!cc) {
2262
0
          continue;
2263
0
        }
2264
0
        for (std::string const& out : cc->GetOutputs()) {
2265
0
          this->OutputOwnerIndex[cmSystemTools::CollapseFullPath(out)]
2266
0
            .push_back(gt.get());
2267
0
        }
2268
0
      }
2269
0
    }
2270
0
  }
2271
0
}
2272
2273
cmGeneratorTarget* cmGlobalGenerator::FindOutputOwningTarget(
2274
  std::string const& output)
2275
0
{
2276
0
  if (!this->OutputOwnerIndexComputed) {
2277
0
    this->ComputeOutputOwnerIndex();
2278
0
  }
2279
0
  auto it =
2280
0
    this->OutputOwnerIndex.find(cmSystemTools::CollapseFullPath(output));
2281
0
  if (it != this->OutputOwnerIndex.end() && it->second.size() == 1) {
2282
0
    return it->second.front();
2283
0
  }
2284
0
  return nullptr;
2285
0
}
2286
2287
void cmGlobalGenerator::ClearGeneratorMembers()
2288
1
{
2289
1
  this->BuildExportSets.clear();
2290
2291
1
  this->OutputOwnerIndex.clear();
2292
1
  this->OutputOwnerIndexComputed = false;
2293
2294
1
  this->Makefiles.clear();
2295
2296
1
  this->LocalGenerators.clear();
2297
2298
1
  this->AliasTargets.clear();
2299
1
  this->ExportSets.clear();
2300
1
  this->InstallComponents.clear();
2301
1
  this->TargetDependencies.clear();
2302
1
  this->TargetSearchIndex.clear();
2303
1
  this->GeneratorTargetSearchIndex.clear();
2304
1
  this->MakefileSearchIndex.clear();
2305
1
  this->LocalGeneratorSearchIndex.clear();
2306
1
  this->TargetOrderIndex.clear();
2307
1
  this->ProjectMap.clear();
2308
1
  this->RuleHashes.clear();
2309
1
  this->DirectoryContentMap.clear();
2310
1
  this->XcFrameworkPListContentMap.clear();
2311
1
  this->BinaryDirectories.clear();
2312
1
  this->GeneratedFiles.clear();
2313
1
  this->RuntimeDependencySets.clear();
2314
1
  this->RuntimeDependencySetsByName.clear();
2315
1
  this->WarnedExperimental.clear();
2316
1
  this->WarnedCMP0210Languages.clear();
2317
1
}
2318
2319
bool cmGlobalGenerator::SupportsShortObjectNames() const
2320
0
{
2321
0
  return false;
2322
0
}
2323
2324
bool cmGlobalGenerator::UseShortObjectNames(
2325
  cmStateEnums::IntermediateDirKind kind) const
2326
0
{
2327
0
  IntermediateDirStrategy strategy = IntermediateDirStrategy::Full;
2328
0
  switch (kind) {
2329
0
    case cmStateEnums::IntermediateDirKind::ObjectFiles:
2330
0
      strategy = this->IntDirStrategy;
2331
0
      break;
2332
0
    case cmStateEnums::IntermediateDirKind::QtAutogenMetadata:
2333
0
      strategy = this->QtAutogenIntDirStrategy;
2334
0
      break;
2335
0
    default:
2336
0
      assert(false);
2337
0
      break;
2338
0
  }
2339
0
  return this->SupportsShortObjectNames() &&
2340
0
    strategy == IntermediateDirStrategy::Short;
2341
0
}
2342
2343
std::string cmGlobalGenerator::GetShortBinaryOutputDir() const
2344
0
{
2345
0
  return ".o";
2346
0
}
2347
2348
std::string cmGlobalGenerator::ComputeTargetShortName(
2349
  std::string const& bindir, std::string const& targetName) const
2350
0
{
2351
0
  auto const& rcwbd =
2352
0
    this->LocalGenerators[0]->MaybeRelativeToTopBinDir(bindir);
2353
0
  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
2354
0
  constexpr size_t HASH_TRUNCATION = 4;
2355
0
  auto dirHash = hasher.HashString(rcwbd).substr(0, HASH_TRUNCATION);
2356
0
  auto tgtHash = hasher.HashString(targetName).substr(0, HASH_TRUNCATION);
2357
0
  return cmStrCat(tgtHash, dirHash);
2358
0
}
2359
2360
cmGlobalGenerator::TargetDirectoryRegistration&
2361
cmGlobalGenerator::RegisterTargetDirectory(cmGeneratorTarget const* tgt,
2362
                                           std::string const& targetDir) const
2363
0
{
2364
0
  if (!tgt->IsNormal() || tgt->GetType() == cm::TargetType::GLOBAL_TARGET ||
2365
0
      tgt->Target->IsForTryCompile()) {
2366
0
    static TargetDirectoryRegistration utilityRegistration(nullptr, true);
2367
0
    return utilityRegistration;
2368
0
  }
2369
2370
  // Get the registration instance for the target.
2371
0
#if __cplusplus >= 201703L
2372
0
  auto registration = this->TargetDirectoryRegistrations.try_emplace(tgt);
2373
#else
2374
  auto registration = this->TargetDirectoryRegistrations.insert(
2375
    std::make_pair(tgt, TargetDirectoryRegistration()));
2376
#endif
2377
  // If it was just inserted, search for a `CollidesWith` possibility.
2378
0
  if (registration.second) {
2379
0
    auto& otherTargets = this->TargetDirectories[targetDir];
2380
0
    if (!otherTargets.empty()) {
2381
0
      registration.first->second.CollidesWith = *otherTargets.begin();
2382
0
    }
2383
0
    otherTargets.insert(tgt);
2384
0
  }
2385
2386
0
  return registration.first->second;
2387
0
}
2388
2389
void cmGlobalGenerator::ComputeTargetObjectDirectory(
2390
  cmGeneratorTarget* /*unused*/) const
2391
0
{
2392
0
}
2393
2394
void cmGlobalGenerator::CheckTargetProperties()
2395
0
{
2396
  // check for link libraries and include directories containing "NOTFOUND"
2397
  // and for infinite loops
2398
0
  std::map<std::string, std::string> notFoundMap;
2399
0
  cmState* state = this->GetCMakeInstance()->GetState();
2400
0
  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
2401
0
    this->Makefiles[i]->Generate(*this->LocalGenerators[i]);
2402
0
    for (auto const& target : this->Makefiles[i]->GetTargets()) {
2403
0
      if (target.second.GetType() == cm::TargetType::INTERFACE_LIBRARY) {
2404
0
        continue;
2405
0
      }
2406
0
      for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
2407
0
        if (lib.first.size() > 9 && cmIsNOTFOUND(lib.first)) {
2408
0
          std::string varName = lib.first.substr(0, lib.first.size() - 9);
2409
0
          if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
2410
0
            varName += " (ADVANCED)";
2411
0
          }
2412
0
          std::string text =
2413
0
            cmStrCat(notFoundMap[varName], "\n    linked by target \"",
2414
0
                     target.second.GetName(), "\" in directory ",
2415
0
                     this->Makefiles[i]->GetCurrentSourceDirectory());
2416
0
          notFoundMap[varName] = text;
2417
0
        }
2418
0
      }
2419
0
      cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
2420
0
      if (!incDirProp) {
2421
0
        continue;
2422
0
      }
2423
2424
0
      std::string incDirs = cmGeneratorExpression::Preprocess(
2425
0
        *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
2426
2427
0
      cmList incs(incDirs);
2428
2429
0
      for (std::string const& incDir : incs) {
2430
0
        if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) {
2431
0
          std::string varName = incDir.substr(0, incDir.size() - 9);
2432
0
          if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
2433
0
            varName += " (ADVANCED)";
2434
0
          }
2435
0
          std::string text =
2436
0
            cmStrCat(notFoundMap[varName],
2437
0
                     "\n   used as include directory in directory ",
2438
0
                     this->Makefiles[i]->GetCurrentSourceDirectory());
2439
0
          notFoundMap[varName] = text;
2440
0
        }
2441
0
      }
2442
0
    }
2443
0
  }
2444
2445
0
  if (!notFoundMap.empty()) {
2446
0
    std::string notFoundVars;
2447
0
    for (auto const& notFound : notFoundMap) {
2448
0
      notFoundVars = cmStrCat(std::move(notFoundVars), notFound.first,
2449
0
                              notFound.second, '\n');
2450
0
    }
2451
0
    cmSystemTools::Error(
2452
0
      cmStrCat("The following variables are used in this project, "
2453
0
               "but they are set to NOTFOUND.\n"
2454
0
               "Please set them or make sure they are set and "
2455
0
               "tested correctly in the CMake files:\n",
2456
0
               notFoundVars));
2457
0
  }
2458
0
}
2459
2460
int cmGlobalGenerator::TryCompile(int jobs, std::string const& bindir,
2461
                                  std::string const& projectName,
2462
                                  std::string const& target, bool fast,
2463
                                  std::string& output, cmMakefile* mf)
2464
0
{
2465
0
  cmBuildArgs buildArgs;
2466
0
  buildArgs.jobs = jobs;
2467
0
  buildArgs.binaryDir = bindir;
2468
0
  buildArgs.projectName = projectName;
2469
0
  buildArgs.verbose = true;
2470
2471
  // if this is not set, then this is a first time configure
2472
  // and there is a good chance that the try compile stuff will
2473
  // take the bulk of the time, so try and guess some progress
2474
  // by getting closer and closer to 100 without actually getting there.
2475
0
  if (!this->CMakeInstance->GetState()->GetInitializedCacheValue(
2476
0
        "CMAKE_NUMBER_OF_MAKEFILES")) {
2477
    // If CMAKE_NUMBER_OF_MAKEFILES is not set
2478
    // we are in the first time progress and we have no
2479
    // idea how long it will be.  So, just move 1/10th of the way
2480
    // there each time, and don't go over 95%
2481
0
    this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2482
0
    if (this->FirstTimeProgress > 0.95f) {
2483
0
      this->FirstTimeProgress = 0.95f;
2484
0
    }
2485
0
    this->CMakeInstance->UpdateProgress("Configuring",
2486
0
                                        this->FirstTimeProgress);
2487
0
  }
2488
2489
0
  std::vector<std::string> newTarget = {};
2490
0
  if (!target.empty()) {
2491
0
    newTarget = { target };
2492
0
  }
2493
0
  std::string config =
2494
0
    mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
2495
0
  cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
2496
2497
0
  std::stringstream ostr;
2498
0
  auto ret = this->Build(buildArgs, newTarget, ostr, "", config,
2499
0
                         defaultBuildOptions, this->TryCompileTimeout,
2500
0
                         cmSystemTools::OUTPUT_NONE, {}, BuildTryCompile::Yes);
2501
0
  output = ostr.str();
2502
0
  return ret;
2503
0
}
2504
2505
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
2506
cmGlobalGenerator::GenerateBuildCommand(
2507
  std::string const& /*unused*/, std::string const& /*unused*/,
2508
  std::string const& /*unused*/, std::vector<std::string> const& /*unused*/,
2509
  std::string const& /*unused*/, int /*unused*/, bool /*unused*/,
2510
  cmBuildOptions /*unused*/, std::vector<std::string> const& /*unused*/,
2511
  BuildTryCompile /*unused*/)
2512
0
{
2513
0
  GeneratedMakeCommand makeCommand;
2514
0
  makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
2515
0
  return { std::move(makeCommand) };
2516
0
}
2517
2518
void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
2519
                                                int /*jobs*/) const
2520
0
{
2521
  // Subclasses override this method if they e.g want to give a warning that
2522
  // they do not support certain build command line options
2523
0
}
2524
2525
int cmGlobalGenerator::Build(cmBuildArgs const& buildArgs,
2526
                             std::vector<std::string> const& targets,
2527
                             std::ostream& ostr,
2528
                             std::string const& makeCommandCSTR,
2529
                             std::string const& config,
2530
                             cmBuildOptions buildOptions, cmDuration timeout,
2531
                             cmSystemTools::OutputOption outputMode,
2532
                             std::vector<std::string> const& nativeOptions,
2533
                             BuildTryCompile isInTryCompile)
2534
0
{
2535
0
  bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
2536
2537
  /**
2538
   * Run an executable command and put the stdout in output.
2539
   */
2540
0
  cmWorkingDirectory workdir(buildArgs.binaryDir);
2541
0
  ostr << "Change Dir: '" << buildArgs.binaryDir << '\'' << std::endl;
2542
0
  if (workdir.Failed()) {
2543
0
    cmSystemTools::SetRunCommandHideConsole(hideconsole);
2544
0
    std::string const& err = workdir.GetError();
2545
0
    cmSystemTools::Error(err);
2546
0
    ostr << err << std::endl;
2547
0
    return 1;
2548
0
  }
2549
0
  std::string realConfig = config;
2550
0
  if (realConfig.empty()) {
2551
0
    realConfig = this->GetDefaultBuildConfig();
2552
0
  }
2553
2554
0
  int retVal = 0;
2555
0
  cmSystemTools::SetRunCommandHideConsole(true);
2556
2557
  // Capture build command output when outputMode == OUTPUT_NONE.
2558
0
  std::string outputBuf;
2559
2560
0
  std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(
2561
0
    makeCommandCSTR, buildArgs.projectName, buildArgs.binaryDir, targets,
2562
0
    realConfig, buildArgs.jobs, buildArgs.verbose, buildOptions, nativeOptions,
2563
0
    isInTryCompile);
2564
2565
  // should we do a clean first?
2566
0
  if (buildOptions.Clean) {
2567
0
    std::vector<GeneratedMakeCommand> cleanCommand =
2568
0
      this->GenerateBuildCommand(makeCommandCSTR, buildArgs.projectName,
2569
0
                                 buildArgs.binaryDir, { "clean" }, realConfig,
2570
0
                                 buildArgs.jobs, buildArgs.verbose,
2571
0
                                 buildOptions);
2572
0
    ostr << "\nRun Clean Command: " << cleanCommand.front().QuotedPrintable()
2573
0
         << std::endl;
2574
0
    if (cleanCommand.size() != 1) {
2575
0
      this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
2576
0
                                             "The generator did not produce "
2577
0
                                             "exactly one command for the "
2578
0
                                             "'clean' target");
2579
0
      return 1;
2580
0
    }
2581
0
    if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
2582
0
                                         &outputBuf, &outputBuf, &retVal,
2583
0
                                         nullptr, outputMode, timeout)) {
2584
0
      cmSystemTools::SetRunCommandHideConsole(hideconsole);
2585
0
      cmSystemTools::Error("Generator: execution of make clean failed.");
2586
0
      ostr << outputBuf << "\nGenerator: execution of make clean failed."
2587
0
           << std::endl;
2588
2589
0
      return 1;
2590
0
    }
2591
0
    ostr << outputBuf;
2592
0
  }
2593
2594
  // now build
2595
0
  std::string makeCommandStr;
2596
0
  std::string outputMakeCommandStr;
2597
0
  bool isWatcomWMake = this->CMakeInstance->GetState()->UseWatcomWMake();
2598
0
  bool needBuildOutput = isWatcomWMake;
2599
0
  std::string buildOutput;
2600
0
  ostr << "\nRun Build Command(s): ";
2601
2602
0
  retVal = 0;
2603
0
  for (auto command = makeCommand.begin();
2604
0
       command != makeCommand.end() && retVal == 0; ++command) {
2605
0
    makeCommandStr = command->Printable();
2606
0
    outputMakeCommandStr = command->QuotedPrintable();
2607
0
    if ((command + 1) != makeCommand.end()) {
2608
0
      makeCommandStr += " && ";
2609
0
      outputMakeCommandStr += " && ";
2610
0
    }
2611
2612
0
    ostr << outputMakeCommandStr << std::endl;
2613
0
    if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, &outputBuf,
2614
0
                                         &outputBuf, &retVal, nullptr,
2615
0
                                         outputMode, timeout)) {
2616
0
      cmSystemTools::SetRunCommandHideConsole(hideconsole);
2617
0
      cmSystemTools::Error(
2618
0
        cmStrCat("Generator: build tool execution failed, command was: ",
2619
0
                 makeCommandStr));
2620
0
      ostr << outputBuf
2621
0
           << "\nGenerator: build tool execution failed, command was: "
2622
0
           << outputMakeCommandStr << std::endl;
2623
2624
0
      return 1;
2625
0
    }
2626
0
    ostr << outputBuf << std::flush;
2627
0
    if (needBuildOutput) {
2628
0
      buildOutput += outputBuf;
2629
0
    }
2630
0
  }
2631
0
  ostr << std::endl;
2632
0
  cmSystemTools::SetRunCommandHideConsole(hideconsole);
2633
2634
  // The OpenWatcom tools do not return an error code when a link
2635
  // library is not found!
2636
0
  if (isWatcomWMake && retVal == 0 &&
2637
0
      buildOutput.find("W1008: cannot open") != std::string::npos) {
2638
0
    retVal = 1;
2639
0
  }
2640
2641
0
  return retVal;
2642
0
}
2643
2644
bool cmGlobalGenerator::Open(std::string const& bindir,
2645
                             std::string const& projectName, bool dryRun)
2646
0
{
2647
0
  if (this->ExtraGenerator) {
2648
0
    return this->ExtraGenerator->Open(bindir, projectName, dryRun);
2649
0
  }
2650
2651
0
  return false;
2652
0
}
2653
2654
std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
2655
  std::string const& target, std::string const& config,
2656
  std::string const& parallel, std::string const& native, bool ignoreErrors)
2657
0
{
2658
0
  std::string makeCommand = cmSystemTools::GetCMakeCommand();
2659
0
  makeCommand =
2660
0
    cmStrCat(cmSystemTools::ConvertToOutputPath(makeCommand), " --build .");
2661
0
  if (!config.empty()) {
2662
0
    makeCommand = cmStrCat(makeCommand, " --config \"", config, '"');
2663
0
  }
2664
0
  if (!parallel.empty()) {
2665
0
    makeCommand = cmStrCat(makeCommand, " --parallel \"", parallel, '"');
2666
0
  }
2667
0
  if (!target.empty()) {
2668
0
    makeCommand = cmStrCat(makeCommand, " --target \"", target, '"');
2669
0
  }
2670
0
  char const* sep = " -- ";
2671
0
  if (ignoreErrors) {
2672
0
    char const* iflag = this->GetBuildIgnoreErrorsFlag();
2673
0
    if (iflag && *iflag) {
2674
0
      makeCommand = cmStrCat(makeCommand, sep, iflag);
2675
0
      sep = " ";
2676
0
    }
2677
0
  }
2678
0
  if (!native.empty()) {
2679
0
    makeCommand = cmStrCat(makeCommand, sep, native);
2680
0
  }
2681
0
  return makeCommand;
2682
0
}
2683
2684
void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
2685
0
{
2686
0
  this->IndexMakefile(mf.get());
2687
0
  this->Makefiles.push_back(std::move(mf));
2688
2689
  // update progress
2690
  // estimate how many lg there will be
2691
0
  cmValue numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
2692
0
    "CMAKE_NUMBER_OF_MAKEFILES");
2693
2694
0
  if (!numGenC) {
2695
    // If CMAKE_NUMBER_OF_MAKEFILES is not set
2696
    // we are in the first time progress and we have no
2697
    // idea how long it will be.  So, just move half way
2698
    // there each time, and don't go over 95%
2699
0
    this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2700
0
    if (this->FirstTimeProgress > 0.95f) {
2701
0
      this->FirstTimeProgress = 0.95f;
2702
0
    }
2703
0
    this->CMakeInstance->UpdateProgress("Configuring",
2704
0
                                        this->FirstTimeProgress);
2705
0
    return;
2706
0
  }
2707
2708
0
  int numGen = atoi(numGenC->c_str());
2709
0
  float prog =
2710
0
    static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen);
2711
0
  if (prog > 1.0f) {
2712
0
    prog = 1.0f;
2713
0
  }
2714
0
  this->CMakeInstance->UpdateProgress("Configuring", prog);
2715
0
}
2716
2717
void cmGlobalGenerator::AddInstallComponent(std::string const& component)
2718
0
{
2719
0
  if (!component.empty()) {
2720
0
    this->InstallComponents.insert(component);
2721
0
  }
2722
0
}
2723
2724
void cmGlobalGenerator::MarkAsGeneratedFile(std::string const& filepath)
2725
0
{
2726
0
  this->GeneratedFiles.insert(filepath);
2727
0
}
2728
2729
bool cmGlobalGenerator::IsGeneratedFile(std::string const& filepath)
2730
0
{
2731
0
  return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end();
2732
0
}
2733
2734
void cmGlobalGenerator::EnableInstallTarget()
2735
0
{
2736
0
  this->InstallTargetEnabled = true;
2737
0
}
2738
2739
std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator(
2740
  cmMakefile* mf)
2741
0
{
2742
0
  return cm::make_unique<cmLocalGenerator>(this, mf);
2743
0
}
2744
2745
void cmGlobalGenerator::SetupTryCompile(cmGlobalGenerator* gen, cmMakefile* mf)
2746
0
{
2747
0
  this->SetConfiguredFilesPath(gen);
2748
0
  this->TryCompileOuterMakefile = mf;
2749
0
  cmValue make =
2750
0
    gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
2751
0
  this->GetCMakeInstance()->AddCacheEntry(
2752
0
    "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH);
2753
0
  this->LanguagesReadyForTryCompile = gen->LanguagesReadyForTryCompile;
2754
0
}
2755
2756
void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
2757
0
{
2758
0
  if (!gen->ConfiguredFilesPath.empty()) {
2759
0
    this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
2760
0
  } else {
2761
0
    this->ConfiguredFilesPath =
2762
0
      cmStrCat(gen->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
2763
0
  }
2764
0
}
2765
2766
bool cmGlobalGenerator::IsExcluded(cmStateSnapshot const& rootSnp,
2767
                                   cmStateSnapshot const& snp_) const
2768
0
{
2769
0
  cmStateSnapshot snp = snp_;
2770
0
  while (snp.IsValid()) {
2771
0
    if (snp == rootSnp) {
2772
      // No directory excludes itself.
2773
0
      return false;
2774
0
    }
2775
2776
0
    if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
2777
      // This directory is excluded from its parent.
2778
0
      return true;
2779
0
    }
2780
0
    snp = snp.GetBuildsystemDirectoryParent();
2781
0
  }
2782
0
  return false;
2783
0
}
2784
2785
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator const* root,
2786
                                   cmLocalGenerator const* gen) const
2787
0
{
2788
0
  assert(gen);
2789
2790
0
  cmStateSnapshot rootSnp = root->GetStateSnapshot();
2791
0
  cmStateSnapshot snp = gen->GetStateSnapshot();
2792
2793
0
  return this->IsExcluded(rootSnp, snp);
2794
0
}
2795
2796
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator const* root,
2797
                                   cmGeneratorTarget const* target) const
2798
0
{
2799
0
  if (!target->IsInBuildSystem()) {
2800
0
    return true;
2801
0
  }
2802
0
  cmMakefile* mf = root->GetMakefile();
2803
0
  std::string const EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
2804
0
  if (cmValue exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
2805
    // Expand the property value per configuration.
2806
0
    unsigned int trueCount = 0;
2807
0
    unsigned int falseCount = 0;
2808
0
    std::vector<std::string> const& configs =
2809
0
      mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2810
0
    for (std::string const& config : configs) {
2811
0
      cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
2812
0
      if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
2813
0
        ++trueCount;
2814
0
      } else {
2815
0
        ++falseCount;
2816
0
      }
2817
0
    }
2818
2819
    // Check whether the genex expansion of the property agrees in all
2820
    // configurations.
2821
0
    if (trueCount > 0 && falseCount > 0) {
2822
0
      std::ostringstream e;
2823
0
      e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName()
2824
0
        << "\" varies by configuration. This is not supported by the \""
2825
0
        << root->GetGlobalGenerator()->GetName() << "\" generator.";
2826
0
      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
2827
0
    }
2828
0
    return trueCount;
2829
0
  }
2830
  // This target is included in its directory.  Check whether the
2831
  // directory is excluded.
2832
0
  return this->IsExcluded(root, target->GetLocalGenerator());
2833
0
}
2834
2835
void cmGlobalGenerator::GetEnabledLanguages(
2836
  std::vector<std::string>& lang) const
2837
0
{
2838
0
  lang = this->CMakeInstance->GetState()->GetEnabledLanguages();
2839
0
}
2840
2841
int cmGlobalGenerator::GetLinkerPreference(std::string const& lang) const
2842
0
{
2843
0
  auto const it = this->LanguageToLinkerPreference.find(lang);
2844
0
  if (it != this->LanguageToLinkerPreference.end()) {
2845
0
    return it->second;
2846
0
  }
2847
0
  return 0;
2848
0
}
2849
2850
void cmGlobalGenerator::FillProjectMap()
2851
0
{
2852
0
  this->ProjectMap.clear(); // make sure we start with a clean map
2853
0
  for (auto const& localGen : this->LocalGenerators) {
2854
    // for each local generator add all projects
2855
0
    cmStateSnapshot snp = localGen->GetStateSnapshot();
2856
0
    std::string name;
2857
0
    do {
2858
0
      std::string snpProjName = snp.GetProjectName();
2859
0
      if (name != snpProjName) {
2860
0
        name = snpProjName;
2861
0
        this->ProjectMap[name].push_back(localGen.get());
2862
0
      }
2863
0
      snp = snp.GetBuildsystemDirectoryParent();
2864
0
    } while (snp.IsValid());
2865
0
  }
2866
0
}
2867
2868
cmMakefile* cmGlobalGenerator::FindMakefile(std::string const& start_dir) const
2869
0
{
2870
0
  auto const it = this->MakefileSearchIndex.find(start_dir);
2871
0
  if (it != this->MakefileSearchIndex.end()) {
2872
0
    return it->second;
2873
0
  }
2874
0
  return nullptr;
2875
0
}
2876
2877
cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
2878
  cmDirectoryId const& id) const
2879
0
{
2880
0
  auto const it = this->LocalGeneratorSearchIndex.find(id.String);
2881
0
  if (it != this->LocalGeneratorSearchIndex.end()) {
2882
0
    return it->second;
2883
0
  }
2884
0
  return nullptr;
2885
0
}
2886
2887
void cmGlobalGenerator::AddAlias(std::string const& name,
2888
                                 std::string const& tgtName)
2889
0
{
2890
0
  this->AliasTargets[name] = tgtName;
2891
0
}
2892
2893
bool cmGlobalGenerator::IsAlias(std::string const& name) const
2894
0
{
2895
0
  return cm::contains(this->AliasTargets, name);
2896
0
}
2897
2898
void cmGlobalGenerator::IndexTarget(cmTarget* t)
2899
0
{
2900
0
  if (!t->IsImported() || t->IsImportedGloballyVisible()) {
2901
0
    this->TargetSearchIndex[t->GetName()] = t;
2902
0
  }
2903
0
}
2904
2905
void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
2906
0
{
2907
0
  if (!gt->IsImported() || gt->IsImportedGloballyVisible()) {
2908
0
    this->GeneratorTargetSearchIndex[gt->GetName()] = gt;
2909
0
  }
2910
0
}
2911
2912
static char const hexDigits[] = "0123456789abcdef";
2913
2914
std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
2915
  cmGeneratorTarget const* gt)
2916
0
{
2917
  // Use the pointer value to uniquely identify the target instance.
2918
  // Use a ":" prefix to avoid conflict with project-defined targets.
2919
  // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
2920
  // other special characters.
2921
0
  constexpr size_t sizeof_ptr =
2922
0
    sizeof(gt); // NOLINT(bugprone-sizeof-expression)
2923
0
  char buf[1 + sizeof_ptr * 2];
2924
0
  char* b = buf;
2925
0
  *b++ = ':';
2926
0
  for (size_t i = 0; i < sizeof_ptr; ++i) {
2927
0
    unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
2928
0
    *b++ = hexDigits[(c & 0xf0) >> 4];
2929
0
    *b++ = hexDigits[(c & 0x0f)];
2930
0
  }
2931
0
  std::string id(buf, sizeof(buf));
2932
  // We internally index pointers to non-const generator targets
2933
  // but our callers only have pointers to const generator targets.
2934
  // They will give up non-const privileges when looking up anyway.
2935
0
  this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt);
2936
0
  return id;
2937
0
}
2938
2939
void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
2940
0
{
2941
  // We index by both source and binary directory.  add_subdirectory
2942
  // supports multiple build directories sharing the same source directory.
2943
  // The source directory index will reference only the first time it is used.
2944
0
  this->MakefileSearchIndex.insert(
2945
0
    MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf));
2946
0
  this->MakefileSearchIndex.insert(
2947
0
    MakefileMap::value_type(mf->GetCurrentBinaryDirectory(), mf));
2948
0
}
2949
2950
void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
2951
0
{
2952
0
  cmDirectoryId id = lg->GetMakefile()->GetDirectoryId();
2953
0
  this->LocalGeneratorSearchIndex[id.String] = lg;
2954
0
}
2955
2956
cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name,
2957
                                            cm::TargetDomainSet domains) const
2958
0
{
2959
0
  bool const useForeign = domains.contains(cm::TargetDomain::FOREIGN);
2960
0
  bool const useNative = domains.contains(cm::TargetDomain::NATIVE);
2961
2962
0
  auto const it = this->TargetSearchIndex.find(name);
2963
0
  if (it != this->TargetSearchIndex.end()) {
2964
0
    if (it->second->IsForeign() ? useForeign : useNative) {
2965
0
      return it->second;
2966
0
    }
2967
0
  }
2968
0
  return nullptr;
2969
0
}
2970
2971
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
2972
  std::string const& name) const
2973
0
{
2974
0
  auto const it = this->GeneratorTargetSearchIndex.find(name);
2975
0
  if (it != this->GeneratorTargetSearchIndex.end()) {
2976
0
    return it->second;
2977
0
  }
2978
0
  return nullptr;
2979
0
}
2980
2981
cmTarget* cmGlobalGenerator::FindTarget(std::string const& name,
2982
                                        cm::TargetDomainSet domains) const
2983
0
{
2984
0
  if (domains.contains(cm::TargetDomain::ALIAS)) {
2985
0
    auto const ai = this->AliasTargets.find(name);
2986
0
    if (ai != this->AliasTargets.end()) {
2987
0
      return this->FindTargetImpl(ai->second, domains);
2988
0
    }
2989
0
  }
2990
0
  return this->FindTargetImpl(name, domains);
2991
0
}
2992
2993
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
2994
  std::string const& name) const
2995
0
{
2996
0
  auto const ai = this->AliasTargets.find(name);
2997
0
  if (ai != this->AliasTargets.end()) {
2998
0
    return this->FindGeneratorTargetImpl(ai->second);
2999
0
  }
3000
0
  return this->FindGeneratorTargetImpl(name);
3001
0
}
3002
3003
bool cmGlobalGenerator::NameResolvesToFramework(
3004
  std::string const& libname) const
3005
0
{
3006
0
  if (cmSystemTools::IsPathToFramework(libname)) {
3007
0
    return true;
3008
0
  }
3009
3010
0
  if (cmTarget* tgt = this->FindTarget(libname)) {
3011
0
    if (tgt->IsFrameworkOnApple()) {
3012
0
      return true;
3013
0
    }
3014
0
  }
3015
3016
0
  return false;
3017
0
}
3018
3019
std::vector<std::string> cmGlobalGenerator::GetTestBuildDependencyPaths(
3020
  std::string const& config,
3021
  cmTestGenerator::BuildDependencies const& deps) const
3022
0
{
3023
0
  std::set<std::string> uniqueDeps;
3024
0
  for (auto const& file : deps.Files) {
3025
0
    uniqueDeps.insert(file.Path);
3026
0
  }
3027
0
  for (cmGeneratorTarget* target : deps.Targets) {
3028
0
    if (target->GetType() == cm::TargetType::UTILITY ||
3029
0
        target->GetType() == cm::TargetType::GLOBAL_TARGET ||
3030
0
        target->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
3031
0
      continue;
3032
0
    }
3033
0
    if (target->GetType() == cm::TargetType::OBJECT_LIBRARY) {
3034
0
      std::vector<std::string> objects;
3035
0
      target->GetTargetObjectNames(config, objects);
3036
0
      for (auto const& object : objects) {
3037
0
        uniqueDeps.insert(
3038
0
          cmStrCat(target->GetObjectDirectory(config), object));
3039
0
      }
3040
0
      continue;
3041
0
    }
3042
0
    uniqueDeps.insert(target->GetFullPath(config));
3043
0
  }
3044
0
  return { uniqueDeps.begin(), uniqueDeps.end() };
3045
0
}
3046
3047
// If the file has no extension it's either a raw executable or might
3048
// be a direct reference to a binary within a framework (bad practice!).
3049
// This is where we change the path to point to the framework directory.
3050
// .tbd files also can be located in SDK frameworks (they are
3051
// placeholders for actual libraries shipped with the OS)
3052
cm::optional<cmGlobalGenerator::FrameworkDescriptor>
3053
cmGlobalGenerator::SplitFrameworkPath(std::string const& path,
3054
                                      FrameworkFormat format) const
3055
0
{
3056
  // Check for framework structure:
3057
  //    (/path/to/)?FwName.framework
3058
  // or (/path/to/)?FwName.framework/FwName(.tbd)?
3059
  // or (/path/to/)?FwName.framework/Versions/*/FwName(.tbd)?
3060
0
  static cmsys::RegularExpression frameworkPath(
3061
0
    "((.+)/)?([^/]+)\\.framework(/Versions/([^/]+))?(/(.+))?$");
3062
3063
0
  auto ext = cmSystemTools::GetFilenameLastExtensionView(path);
3064
0
  if ((ext.empty() || ext == ".tbd" || ext == ".framework") &&
3065
0
      frameworkPath.find(path)) {
3066
0
    auto name = frameworkPath.match(3);
3067
0
    auto libname =
3068
0
      cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(7));
3069
0
    if (format == FrameworkFormat::Strict && libname.empty()) {
3070
0
      return cm::nullopt;
3071
0
    }
3072
0
    if (!libname.empty() && !cmHasPrefix(libname, name)) {
3073
0
      return cm::nullopt;
3074
0
    }
3075
3076
0
    if (libname.empty() || name.size() == libname.size()) {
3077
0
      return FrameworkDescriptor{ frameworkPath.match(2),
3078
0
                                  frameworkPath.match(5), name };
3079
0
    }
3080
3081
0
    return FrameworkDescriptor{ frameworkPath.match(2), frameworkPath.match(5),
3082
0
                                name, libname.substr(name.size()) };
3083
0
  }
3084
3085
0
  if (format == FrameworkFormat::Extended) {
3086
    // path format can be more flexible: (/path/to/)?fwName(.framework)?
3087
0
    auto fwDir = cmSystemTools::GetParentDirectory(path);
3088
0
    auto name = ext == ".framework"
3089
0
      ? cmSystemTools::GetFilenameWithoutExtension(path)
3090
0
      : cmSystemTools::GetFilenameName(path);
3091
3092
0
    return FrameworkDescriptor{ fwDir, name };
3093
0
  }
3094
3095
0
  return cm::nullopt;
3096
0
}
3097
3098
namespace {
3099
void IssueReservedTargetNameError(cmake* cm, cmTarget* tgt,
3100
                                  std::string const& targetNameAsWritten,
3101
                                  std::string const& reason)
3102
0
{
3103
0
  cm->IssueMessage(MessageType::FATAL_ERROR,
3104
0
                   cmStrCat("The target name \"", targetNameAsWritten,
3105
0
                            "\" is reserved ", reason, '.'),
3106
0
                   tgt->GetBacktrace());
3107
0
}
3108
}
3109
3110
bool cmGlobalGenerator::CheckReservedTargetName(
3111
  std::string const& targetName, std::string const& reason) const
3112
0
{
3113
0
  cmTarget* tgt = this->FindTarget(targetName);
3114
0
  if (!tgt) {
3115
0
    return true;
3116
0
  }
3117
0
  IssueReservedTargetNameError(this->GetCMakeInstance(), tgt, targetName,
3118
0
                               reason);
3119
0
  return false;
3120
0
}
3121
3122
bool cmGlobalGenerator::CheckReservedTargetNamePrefix(
3123
  std::string const& targetPrefix, std::string const& reason) const
3124
0
{
3125
0
  bool ret = true;
3126
0
  for (auto const& tgtPair : this->TargetSearchIndex) {
3127
0
    if (cmHasPrefix(tgtPair.first, targetPrefix)) {
3128
0
      IssueReservedTargetNameError(this->GetCMakeInstance(), tgtPair.second,
3129
0
                                   tgtPair.first, reason);
3130
0
      ret = false;
3131
0
    }
3132
0
  }
3133
0
  return ret;
3134
0
}
3135
3136
void cmGlobalGenerator::CreateDefaultGlobalTargets(
3137
  std::vector<GlobalTargetInfo>& targets)
3138
0
{
3139
0
  this->AddGlobalTarget_Package(targets);
3140
0
  this->AddGlobalTarget_PackageSource(targets);
3141
0
  this->AddGlobalTarget_Test(targets);
3142
0
  this->AddGlobalTarget_EditCache(targets);
3143
0
  this->AddGlobalTarget_RebuildCache(targets);
3144
0
  this->AddGlobalTarget_Install(targets);
3145
0
}
3146
3147
void cmGlobalGenerator::AddGlobalTarget_Package(
3148
  std::vector<GlobalTargetInfo>& targets)
3149
0
{
3150
0
  auto& mf = this->Makefiles[0];
3151
0
  std::string configFile =
3152
0
    cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
3153
0
  if (!cmSystemTools::FileExists(configFile)) {
3154
0
    return;
3155
0
  }
3156
3157
0
  static auto const reservedTargets = { "package", "PACKAGE" };
3158
0
  for (auto const& target : reservedTargets) {
3159
0
    if (!this->CheckReservedTargetName(target,
3160
0
                                       "when CPack packaging is enabled")) {
3161
0
      return;
3162
0
    }
3163
0
  }
3164
3165
0
  char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
3166
0
  GlobalTargetInfo gti;
3167
0
  gti.Name = this->GetPackageTargetName();
3168
0
  gti.Message = "Run CPack packaging tool...";
3169
0
  gti.UsesTerminal = true;
3170
0
  gti.WorkingDir = mf->GetCurrentBinaryDirectory();
3171
0
  cmCustomCommandLine singleLine;
3172
0
  singleLine.emplace_back(cmSystemTools::GetCPackCommand());
3173
0
  if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
3174
0
    singleLine.emplace_back("-C");
3175
0
    singleLine.emplace_back(cmakeCfgIntDir);
3176
0
  }
3177
0
  singleLine.emplace_back("--config");
3178
0
  singleLine.emplace_back("./CPackConfig.cmake");
3179
0
  gti.CommandLines.emplace_back(std::move(singleLine));
3180
0
  if (this->GetPreinstallTargetName()) {
3181
0
    gti.Depends.emplace_back(this->GetPreinstallTargetName());
3182
0
  } else {
3183
0
    cmValue noPackageAll =
3184
0
      mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
3185
0
    if (noPackageAll.IsOff()) {
3186
0
      gti.Depends.emplace_back(this->GetAllTargetName());
3187
0
    }
3188
0
  }
3189
0
  targets.emplace_back(std::move(gti));
3190
0
}
3191
3192
void cmGlobalGenerator::AddGlobalTarget_PackageSource(
3193
  std::vector<GlobalTargetInfo>& targets)
3194
0
{
3195
0
  char const* packageSourceTargetName = this->GetPackageSourceTargetName();
3196
0
  if (!packageSourceTargetName) {
3197
0
    return;
3198
0
  }
3199
3200
0
  auto& mf = this->Makefiles[0];
3201
0
  std::string configFile =
3202
0
    cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
3203
0
  if (!cmSystemTools::FileExists(configFile)) {
3204
0
    return;
3205
0
  }
3206
3207
0
  static auto const reservedTargets = { "package_source" };
3208
0
  for (auto const& target : reservedTargets) {
3209
0
    if (!this->CheckReservedTargetName(
3210
0
          target, "when CPack source packaging is enabled")) {
3211
0
      return;
3212
0
    }
3213
0
  }
3214
3215
0
  GlobalTargetInfo gti;
3216
0
  gti.Name = packageSourceTargetName;
3217
0
  gti.Message = "Run CPack packaging tool for source...";
3218
0
  gti.WorkingDir = mf->GetCurrentBinaryDirectory();
3219
0
  gti.UsesTerminal = true;
3220
0
  cmCustomCommandLine singleLine;
3221
0
  singleLine.emplace_back(cmSystemTools::GetCPackCommand());
3222
0
  singleLine.emplace_back("--config");
3223
0
  singleLine.emplace_back("./CPackSourceConfig.cmake");
3224
0
  gti.CommandLines.emplace_back(std::move(singleLine));
3225
0
  targets.emplace_back(std::move(gti));
3226
0
}
3227
3228
void cmGlobalGenerator::AddGlobalTarget_Test(
3229
  std::vector<GlobalTargetInfo>& targets)
3230
0
{
3231
0
  auto& mf = this->Makefiles[0];
3232
0
  if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
3233
0
    return;
3234
0
  }
3235
3236
0
  static auto const reservedTargets = { "test", "RUN_TESTS" };
3237
0
  for (auto const& target : reservedTargets) {
3238
0
    if (!this->CheckReservedTargetName(target,
3239
0
                                       "when CTest testing is enabled")) {
3240
0
      return;
3241
0
    }
3242
0
  }
3243
3244
0
  char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
3245
0
  GlobalTargetInfo gti;
3246
0
  gti.Name = this->GetTestTargetName();
3247
0
  gti.Message = "Running tests...";
3248
0
  gti.UsesTerminal = true;
3249
  // Unlike the 'install' target, the 'test' target does not depend on 'all'
3250
  // by default.  Enable it only if CMAKE_SKIP_TEST_ALL_DEPENDENCY is
3251
  // explicitly set to OFF.
3252
0
  if (cmValue noall = mf->GetDefinition("CMAKE_SKIP_TEST_ALL_DEPENDENCY")) {
3253
0
    if (noall.IsOff()) {
3254
0
      gti.Depends.emplace_back(this->GetAllTargetName());
3255
0
    }
3256
0
  }
3257
0
  cmCustomCommandLine singleLine;
3258
0
  singleLine.emplace_back(cmSystemTools::GetCTestCommand());
3259
0
  cmList args(mf->GetDefinition("CMAKE_CTEST_ARGUMENTS"));
3260
0
  for (auto const& arg : args) {
3261
0
    singleLine.emplace_back(arg);
3262
0
  }
3263
0
  if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
3264
0
    singleLine.emplace_back("-C");
3265
0
    singleLine.emplace_back(cmakeCfgIntDir);
3266
0
  } else // TODO: This is a hack. Should be something to do with the
3267
         // generator
3268
0
  {
3269
0
    singleLine.emplace_back("$(ARGS)");
3270
0
  }
3271
0
  gti.CommandLines.emplace_back(std::move(singleLine));
3272
0
  targets.emplace_back(std::move(gti));
3273
0
}
3274
3275
void cmGlobalGenerator::ReserveGlobalTargetCodegen()
3276
0
{
3277
  // Read the policy value at the end of the top-level CMakeLists.txt file
3278
  // since it's a global policy that affects the whole project.
3279
0
  auto& mf = this->Makefiles[0];
3280
0
  auto const policyStatus = mf->GetPolicyStatus(cmPolicies::CMP0171);
3281
3282
0
  this->AllowGlobalTargetCodegen = (policyStatus == cmPolicies::NEW);
3283
3284
0
  cmTarget* tgt = this->FindTarget("codegen");
3285
0
  if (!tgt) {
3286
0
    return;
3287
0
  }
3288
3289
0
  switch (policyStatus) {
3290
0
    case cmPolicies::WARN:
3291
0
      tgt->GetMakefile()->IssuePolicyWarning(
3292
0
        cmPolicies::CMP0171, {}, "The target name \"codegen\" is reserved.",
3293
0
        tgt->GetBacktrace());
3294
0
      break;
3295
0
    case cmPolicies::OLD:
3296
0
      break;
3297
0
    case cmPolicies::NEW:
3298
0
      this->GetCMakeInstance()->IssueMessage(
3299
0
        MessageType::FATAL_ERROR, "The target name \"codegen\" is reserved.",
3300
0
        tgt->GetBacktrace());
3301
0
      cmSystemTools::SetFatalErrorOccurred();
3302
0
      break;
3303
0
  }
3304
0
}
3305
3306
bool cmGlobalGenerator::CheckCMP0171() const
3307
0
{
3308
0
  return this->AllowGlobalTargetCodegen;
3309
0
}
3310
3311
void cmGlobalGenerator::AddGlobalTarget_EditCache(
3312
  std::vector<GlobalTargetInfo>& targets) const
3313
0
{
3314
0
  char const* editCacheTargetName = this->GetEditCacheTargetName();
3315
0
  if (!editCacheTargetName) {
3316
0
    return;
3317
0
  }
3318
0
  GlobalTargetInfo gti;
3319
0
  gti.Name = editCacheTargetName;
3320
0
  gti.PerConfig = cmTarget::PerConfig::No;
3321
0
  cmCustomCommandLine singleLine;
3322
3323
  // Use generator preference for the edit_cache rule if it is defined.
3324
0
  std::string edit_cmd = this->GetEditCacheCommand();
3325
0
  if (!edit_cmd.empty()) {
3326
0
    singleLine.emplace_back(std::move(edit_cmd));
3327
0
    if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
3328
0
      singleLine.emplace_back("--compile-no-warning-as-error");
3329
0
    }
3330
0
    if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
3331
0
      singleLine.emplace_back("--link-no-warning-as-error");
3332
0
    }
3333
0
    singleLine.emplace_back("-S$(CMAKE_SOURCE_DIR)");
3334
0
    singleLine.emplace_back("-B$(CMAKE_BINARY_DIR)");
3335
0
    gti.Message = "Running CMake cache editor...";
3336
0
    gti.UsesTerminal = true;
3337
0
  } else {
3338
0
    singleLine.emplace_back(cmSystemTools::GetCMakeCommand());
3339
0
    singleLine.emplace_back("-E");
3340
0
    singleLine.emplace_back("echo");
3341
0
    singleLine.emplace_back("No interactive CMake dialog available.");
3342
0
    gti.Message = "No interactive CMake dialog available...";
3343
0
    gti.UsesTerminal = false;
3344
0
    gti.StdPipesUTF8 = true;
3345
0
  }
3346
0
  gti.CommandLines.emplace_back(std::move(singleLine));
3347
3348
0
  targets.emplace_back(std::move(gti));
3349
0
}
3350
3351
void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
3352
  std::vector<GlobalTargetInfo>& targets) const
3353
0
{
3354
0
  char const* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
3355
0
  if (!rebuildCacheTargetName) {
3356
0
    return;
3357
0
  }
3358
0
  GlobalTargetInfo gti;
3359
0
  gti.Name = rebuildCacheTargetName;
3360
0
  gti.Message = "Running CMake to regenerate build system...";
3361
0
  gti.UsesTerminal = true;
3362
0
  gti.PerConfig = cmTarget::PerConfig::No;
3363
0
  cmCustomCommandLine singleLine;
3364
0
  singleLine.emplace_back(cmSystemTools::GetCMakeCommand());
3365
0
  singleLine.emplace_back("--regenerate-during-build");
3366
0
  if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
3367
0
    singleLine.emplace_back("--compile-no-warning-as-error");
3368
0
  }
3369
0
  if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
3370
0
    singleLine.emplace_back("--link-no-warning-as-error");
3371
0
  }
3372
0
  singleLine.emplace_back("-S$(CMAKE_SOURCE_DIR)");
3373
0
  singleLine.emplace_back("-B$(CMAKE_BINARY_DIR)");
3374
0
  gti.CommandLines.emplace_back(std::move(singleLine));
3375
0
  gti.StdPipesUTF8 = true;
3376
0
  targets.emplace_back(std::move(gti));
3377
0
}
3378
3379
void cmGlobalGenerator::AddGlobalTarget_Install(
3380
  std::vector<GlobalTargetInfo>& targets)
3381
0
{
3382
0
  auto& mf = this->Makefiles[0];
3383
0
  char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
3384
0
  bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
3385
0
  if (this->InstallTargetEnabled && skipInstallRules) {
3386
0
    this->CMakeInstance->IssueMessage(
3387
0
      MessageType::WARNING,
3388
0
      "CMAKE_SKIP_INSTALL_RULES was enabled even though "
3389
0
      "installation rules have been specified",
3390
0
      mf->GetBacktrace());
3391
0
  } else if (this->InstallTargetEnabled && !skipInstallRules) {
3392
0
    if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) {
3393
0
      std::set<std::string>* componentsSet = &this->InstallComponents;
3394
0
      std::ostringstream ostr;
3395
0
      if (!componentsSet->empty()) {
3396
0
        ostr << "Available install components are: "
3397
0
             << cmWrap('"', *componentsSet, '"', " ");
3398
0
      } else {
3399
0
        ostr << "Only default component available";
3400
0
      }
3401
0
      GlobalTargetInfo gti;
3402
0
      gti.Name = "list_install_components";
3403
0
      gti.Message = ostr.str();
3404
0
      gti.UsesTerminal = false;
3405
0
      targets.push_back(std::move(gti));
3406
0
    }
3407
0
    std::string cmd = cmSystemTools::GetCMakeCommand();
3408
0
    GlobalTargetInfo gti;
3409
0
    gti.Name = this->GetInstallTargetName();
3410
0
    gti.Message = "Install the project...";
3411
0
    gti.UsesTerminal = true;
3412
0
    gti.StdPipesUTF8 = true;
3413
0
    gti.Role = "install";
3414
0
    cmCustomCommandLine singleLine;
3415
0
    if (this->GetPreinstallTargetName()) {
3416
0
      gti.Depends.emplace_back(this->GetPreinstallTargetName());
3417
0
    } else {
3418
0
      cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
3419
0
      if (noall.IsOff()) {
3420
0
        gti.Depends.emplace_back(this->GetAllTargetName());
3421
0
      }
3422
0
    }
3423
0
    if (mf->GetDefinition("CMake_BINARY_DIR") &&
3424
0
        !mf->IsOn("CMAKE_CROSSCOMPILING")) {
3425
      // We are building CMake itself.  We cannot use the original
3426
      // executable to install over itself.  The generator will
3427
      // automatically convert this name to the build-time location.
3428
0
      cmd = "cmake";
3429
0
    }
3430
0
    singleLine.push_back(cmd);
3431
0
    if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
3432
0
      std::string cfgArg = "-DBUILD_TYPE=";
3433
0
      bool useEPN = this->UseEffectivePlatformName(mf.get());
3434
0
      if (useEPN) {
3435
0
        cfgArg += "$(CONFIGURATION)";
3436
0
        singleLine.push_back(cfgArg);
3437
0
        cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
3438
0
      } else {
3439
0
        cfgArg += this->GetCMakeCFGIntDir();
3440
0
      }
3441
0
      singleLine.push_back(cfgArg);
3442
0
    }
3443
0
    singleLine.emplace_back("-P");
3444
0
    singleLine.emplace_back("cmake_install.cmake");
3445
0
    gti.CommandLines.emplace_back(singleLine);
3446
0
    targets.emplace_back(gti);
3447
3448
    // install_local
3449
0
    if (char const* install_local = this->GetInstallLocalTargetName()) {
3450
0
      gti.Name = install_local;
3451
0
      gti.Message = "Installing only the local directory...";
3452
0
      gti.Role = "install";
3453
0
      gti.UsesTerminal =
3454
0
        !this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
3455
0
          "INSTALL_PARALLEL");
3456
0
      gti.CommandLines.clear();
3457
3458
0
      cmCustomCommandLine localCmdLine = singleLine;
3459
3460
0
      localCmdLine.insert(localCmdLine.begin() + 1,
3461
0
                          "-DCMAKE_INSTALL_LOCAL_ONLY=1");
3462
3463
0
      gti.CommandLines.push_back(std::move(localCmdLine));
3464
0
      targets.push_back(gti);
3465
0
    }
3466
3467
    // install_strip
3468
0
    char const* install_strip = this->GetInstallStripTargetName();
3469
0
    if (install_strip && mf->IsSet("CMAKE_STRIP")) {
3470
0
      gti.Name = install_strip;
3471
0
      gti.Message = "Installing the project stripped...";
3472
0
      gti.UsesTerminal = true;
3473
0
      gti.Role = "install";
3474
0
      gti.CommandLines.clear();
3475
3476
0
      cmCustomCommandLine stripCmdLine = singleLine;
3477
3478
0
      stripCmdLine.insert(stripCmdLine.begin() + 1,
3479
0
                          "-DCMAKE_INSTALL_DO_STRIP=1");
3480
0
      gti.CommandLines.push_back(std::move(stripCmdLine));
3481
0
      targets.push_back(gti);
3482
0
    }
3483
0
  }
3484
0
}
3485
3486
class ModuleCompilationDatabaseCommandAction
3487
{
3488
public:
3489
  ModuleCompilationDatabaseCommandAction(
3490
    std::string output, std::function<std::vector<std::string>()> inputs)
3491
0
    : Output(std::move(output))
3492
0
    , Inputs(std::move(inputs))
3493
0
  {
3494
0
  }
3495
  void operator()(cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3496
                  std::unique_ptr<cmCustomCommand> cc);
3497
3498
private:
3499
  std::string const Output;
3500
  std::function<std::vector<std::string>()> const Inputs;
3501
};
3502
3503
void ModuleCompilationDatabaseCommandAction::operator()(
3504
  cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3505
  std::unique_ptr<cmCustomCommand> cc)
3506
0
{
3507
0
  auto inputs = this->Inputs();
3508
3509
0
  cmCustomCommandLines command_lines;
3510
0
  cmCustomCommandLine command_line;
3511
0
  {
3512
0
    command_line.emplace_back(cmSystemTools::GetCMakeCommand());
3513
0
    command_line.emplace_back("-E");
3514
0
    command_line.emplace_back("cmake_module_compile_db");
3515
0
    command_line.emplace_back("merge");
3516
0
    command_line.emplace_back("-o");
3517
0
    command_line.emplace_back(this->Output);
3518
0
    for (auto const& input : inputs) {
3519
0
      command_line.emplace_back(input);
3520
0
    }
3521
0
  }
3522
0
  command_lines.emplace_back(std::move(command_line));
3523
3524
0
  cc->SetBacktrace(lfbt);
3525
0
  cc->SetCommandLines(command_lines);
3526
0
  cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
3527
0
  cc->SetDependsExplicitOnly(true);
3528
0
  cc->SetOutputs(this->Output);
3529
0
  if (!inputs.empty()) {
3530
0
    cc->SetMainDependency(inputs[0]);
3531
0
  }
3532
0
  cc->SetDepends(inputs);
3533
0
  detail::AddCustomCommandToOutput(lg, cmCommandOrigin::Generator,
3534
0
                                   std::move(cc), false);
3535
0
}
3536
3537
class ModuleCompilationDatabaseTargetAction
3538
{
3539
public:
3540
  ModuleCompilationDatabaseTargetAction(std::string output, cmTarget* target)
3541
0
    : Output(std::move(output))
3542
0
    , Target(target)
3543
0
  {
3544
0
  }
3545
  void operator()(cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3546
                  std::unique_ptr<cmCustomCommand> cc);
3547
3548
private:
3549
  std::string const Output;
3550
  cmTarget* const Target;
3551
};
3552
3553
void ModuleCompilationDatabaseTargetAction::operator()(
3554
  cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3555
  std::unique_ptr<cmCustomCommand> cc)
3556
0
{
3557
0
  cc->SetBacktrace(lfbt);
3558
0
  cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
3559
0
  std::vector<std::string> target_inputs;
3560
0
  target_inputs.emplace_back(this->Output);
3561
0
  cc->SetDepends(target_inputs);
3562
0
  detail::AddUtilityCommand(lg, cmCommandOrigin::Generator, this->Target,
3563
0
                            std::move(cc));
3564
0
}
3565
3566
void cmGlobalGenerator::AddBuildDatabaseFile(std::string const& lang,
3567
                                             std::string const& config,
3568
                                             std::string const& path)
3569
0
{
3570
0
  if (!config.empty()) {
3571
0
    this->PerConfigModuleDbs[config][lang].push_back(path);
3572
0
  }
3573
0
  this->PerLanguageModuleDbs[lang].push_back(path);
3574
0
}
3575
3576
bool cmGlobalGenerator::AddBuildDatabaseTargets()
3577
0
{
3578
0
  auto& mf = this->Makefiles[0];
3579
0
  if (!mf->IsOn("CMAKE_EXPORT_BUILD_DATABASE")) {
3580
0
    return true;
3581
0
  }
3582
0
  if (!cmExperimental::HasSupportEnabled(
3583
0
        *mf.get(), cmExperimental::Feature::ExportBuildDatabase)) {
3584
0
    return {};
3585
0
  }
3586
3587
0
  static auto const reservedTargets = { "cmake_build_database" };
3588
0
  for (auto const& target : reservedTargets) {
3589
0
    if (!this->CheckReservedTargetName(
3590
0
          target, "when exporting build databases are enabled")) {
3591
0
      return false;
3592
0
    }
3593
0
  }
3594
0
  static auto const reservedPrefixes = { "cmake_build_database-" };
3595
0
  for (auto const& prefix : reservedPrefixes) {
3596
0
    if (!this->CheckReservedTargetNamePrefix(
3597
0
          prefix, "when exporting build databases are enabled")) {
3598
0
      return false;
3599
0
    }
3600
0
  }
3601
3602
0
  if (!this->SupportsBuildDatabase()) {
3603
0
    return true;
3604
0
  }
3605
3606
0
  auto configs = mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
3607
3608
0
  static cm::static_string_view TargetPrefix = "cmake_build_database"_s;
3609
0
  auto AddMergeTarget =
3610
0
    [&mf](std::string const& name, char const* comment,
3611
0
          std::string const& output,
3612
0
          std::function<std::vector<std::string>()> inputs) {
3613
      // Add the custom command.
3614
0
      {
3615
0
        ModuleCompilationDatabaseCommandAction action{ output,
3616
0
                                                       std::move(inputs) };
3617
0
        auto cc = cm::make_unique<cmCustomCommand>();
3618
0
        cc->SetComment(comment);
3619
0
        mf->AddGeneratorAction(
3620
0
          std::move(cc), action,
3621
0
          cmMakefile::GeneratorActionWhen::AfterGeneratorTargets);
3622
0
      }
3623
3624
      // Add a custom target with the given name.
3625
0
      {
3626
0
        cmTarget* target = mf->AddNewUtilityTarget(name, true);
3627
0
        ModuleCompilationDatabaseTargetAction action{ output, target };
3628
0
        auto cc = cm::make_unique<cmCustomCommand>();
3629
0
        mf->AddGeneratorAction(std::move(cc), action);
3630
0
      }
3631
0
    };
3632
3633
0
  std::string module_languages[] = { "CXX" };
3634
3635
  // Handle config-less builds.
3636
0
  if (configs.empty()) {
3637
0
    std::vector<std::string> all_lang_paths;
3638
0
    for (auto const& lang : module_languages) {
3639
0
      auto comment = cmStrCat("Combining module command databases for ", lang);
3640
0
      auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3641
0
                             lang, ".json");
3642
0
      mf->GetOrCreateGeneratedSource(output);
3643
0
      AddMergeTarget(
3644
0
        cmStrCat(TargetPrefix, '-', lang), comment.c_str(), output,
3645
0
        [this, lang]() { return this->PerLanguageModuleDbs[lang]; });
3646
0
      all_lang_paths.emplace_back(std::move(output));
3647
0
    }
3648
3649
    // Add the overall target.
3650
0
    auto const* comment = "Combining module command databases";
3651
0
    auto output =
3652
0
      cmStrCat(mf->GetHomeOutputDirectory(), "/build_database.json");
3653
0
    mf->GetOrCreateGeneratedSource(output);
3654
0
    AddMergeTarget(std::string{ TargetPrefix }, comment, output,
3655
0
                   [all_lang_paths]() { return all_lang_paths; });
3656
3657
0
    return true;
3658
0
  }
3659
3660
  // Add per-configuration targets.
3661
0
  for (auto const& config : configs) {
3662
    // Add per-language targets.
3663
0
    std::vector<std::string> all_config_paths;
3664
0
    for (auto const& lang : module_languages) {
3665
0
      auto comment = cmStrCat("Combining module command databases for ", lang,
3666
0
                              " and ", config);
3667
0
      auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3668
0
                             lang, '_', config, ".json");
3669
0
      mf->GetOrCreateGeneratedSource(output);
3670
0
      AddMergeTarget(cmStrCat(TargetPrefix, '-', lang, '-', config),
3671
0
                     comment.c_str(), output, [this, config, lang]() {
3672
0
                       return this->PerConfigModuleDbs[config][lang];
3673
0
                     });
3674
0
      all_config_paths.emplace_back(std::move(output));
3675
0
    }
3676
3677
    // Add the overall target.
3678
0
    auto comment = cmStrCat("Combining module command databases for ", config);
3679
0
    auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3680
0
                           config, ".json");
3681
0
    mf->GetOrCreateGeneratedSource(output);
3682
0
    AddMergeTarget(cmStrCat(TargetPrefix, '-', config), comment.c_str(),
3683
0
                   output, [all_config_paths]() { return all_config_paths; });
3684
0
  }
3685
3686
  // NMC considerations
3687
  // Add per-language targets.
3688
0
  std::vector<std::string> all_config_paths;
3689
0
  for (auto const& lang : module_languages) {
3690
0
    auto comment = cmStrCat("Combining module command databases for ", lang);
3691
0
    auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3692
0
                           lang, ".json");
3693
0
    mf->GetOrCreateGeneratedSource(output);
3694
0
    AddMergeTarget(
3695
0
      cmStrCat(TargetPrefix, '-', lang), comment.c_str(), output,
3696
0
      [this, lang]() { return this->PerLanguageModuleDbs[lang]; });
3697
0
    all_config_paths.emplace_back(std::move(output));
3698
0
  }
3699
3700
  // Add the overall target.
3701
0
  auto const* comment = "Combining all module command databases";
3702
0
  auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database.json");
3703
0
  mf->GetOrCreateGeneratedSource(output);
3704
0
  AddMergeTarget(std::string(TargetPrefix), comment, output,
3705
0
                 [all_config_paths]() { return all_config_paths; });
3706
3707
0
  return true;
3708
0
}
3709
3710
std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
3711
0
{
3712
0
  cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
3713
0
    "PREDEFINED_TARGETS_FOLDER");
3714
3715
0
  if (prop) {
3716
0
    return *prop;
3717
0
  }
3718
3719
0
  return "CMakePredefinedTargets";
3720
0
}
3721
3722
bool cmGlobalGenerator::UseFolderProperty() const
3723
0
{
3724
0
  cmValue const prop =
3725
0
    this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
3726
3727
  // If this property is defined, let the setter turn this on or off.
3728
0
  if (prop) {
3729
0
    return prop.IsOn();
3730
0
  }
3731
3732
  // If CMP0143 is NEW `treat` "USE_FOLDERS" as ON. Otherwise `treat` it as OFF
3733
0
  assert(!this->Makefiles.empty());
3734
0
  return (this->Makefiles[0]->GetPolicyStatus(cmPolicies::CMP0143) ==
3735
0
          cmPolicies::NEW);
3736
0
}
3737
3738
void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
3739
                                           cmMakefile* mf)
3740
0
{
3741
  // Package
3742
0
  auto tb = mf->CreateNewTarget(gti.Name, cm::TargetType::GLOBAL_TARGET,
3743
0
                                gti.PerConfig);
3744
3745
  // Do nothing if gti.Name is already used
3746
0
  if (!tb.second) {
3747
0
    return;
3748
0
  }
3749
3750
0
  cmTarget& target = tb.first;
3751
0
  target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
3752
3753
  // Store the custom command in the target.
3754
0
  cmCustomCommand cc;
3755
0
  cc.SetCommandLines(gti.CommandLines);
3756
0
  cc.SetWorkingDirectory(gti.WorkingDir.c_str());
3757
0
  cc.SetStdPipesUTF8(gti.StdPipesUTF8);
3758
0
  cc.SetUsesTerminal(gti.UsesTerminal);
3759
0
  cc.SetRole(gti.Role);
3760
0
  target.AddPostBuildCommand(std::move(cc));
3761
0
  if (!gti.Message.empty()) {
3762
0
    target.SetProperty("EchoString", gti.Message);
3763
0
  }
3764
0
  for (std::string const& d : gti.Depends) {
3765
0
    target.AddUtility(d, false);
3766
0
  }
3767
3768
  // Organize in the "predefined targets" folder:
3769
  //
3770
0
  if (this->UseFolderProperty()) {
3771
0
    target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
3772
0
  }
3773
0
}
3774
3775
std::string cmGlobalGenerator::GenerateRuleFile(
3776
  std::string const& output) const
3777
0
{
3778
0
  std::string ruleFile = cmStrCat(output, ".rule");
3779
0
  char const* dir = this->GetCMakeCFGIntDir();
3780
0
  if (dir && dir[0] == '$') {
3781
0
    cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles");
3782
0
  }
3783
0
  return ruleFile;
3784
0
}
3785
3786
bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
3787
0
{
3788
0
  return mf->PlatformIsAppleEmbedded();
3789
0
}
3790
3791
void cmGlobalGenerator::AppendDirectoryForConfig(std::string const& /*unused*/,
3792
                                                 std::string const& /*unused*/,
3793
                                                 std::string const& /*unused*/,
3794
                                                 std::string& /*unused*/)
3795
0
{
3796
  // Subclasses that support multiple configurations should implement
3797
  // this method to append the subdirectory for the given build
3798
  // configuration.
3799
0
}
3800
3801
cmValue cmGlobalGenerator::GetDebuggerWorkingDirectory(
3802
  cmGeneratorTarget* gt) const
3803
0
{
3804
0
  return gt->GetProperty("DEBUGGER_WORKING_DIRECTORY");
3805
0
}
3806
3807
cmGlobalGenerator::TargetDependSet const&
3808
cmGlobalGenerator::GetTargetDirectDepends(
3809
  cmGeneratorTarget const* target) const
3810
0
{
3811
0
  auto i = this->TargetDependencies.find(target);
3812
0
  assert(i != this->TargetDependencies.end());
3813
0
  return i->second;
3814
0
}
3815
3816
bool cmGlobalGenerator::TargetOrderIndexLess(cmGeneratorTarget const* l,
3817
                                             cmGeneratorTarget const* r) const
3818
0
{
3819
0
  return this->TargetOrderIndex.at(l) < this->TargetOrderIndex.at(r);
3820
0
}
3821
3822
bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
3823
0
{
3824
  // The following is a list of targets reserved
3825
  // by one or more of the cmake generators.
3826
3827
  // Adding additional targets to this list will require a policy!
3828
0
  static cm::static_string_view const reservedTargets[] = {
3829
0
    "all"_s,           "ALL_BUILD"_s,  "help"_s,  "install"_s,
3830
0
    "INSTALL"_s,       "preinstall"_s, "clean"_s, "edit_cache"_s,
3831
0
    "rebuild_cache"_s, "ZERO_CHECK"_s
3832
0
  };
3833
3834
0
  return cm::contains(reservedTargets, name);
3835
0
}
3836
3837
void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
3838
  std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
3839
0
{
3840
0
  this->ExtraGenerator = std::move(extraGenerator);
3841
0
  if (this->ExtraGenerator) {
3842
0
    this->ExtraGenerator->SetGlobalGenerator(this);
3843
0
  }
3844
0
}
3845
3846
std::string cmGlobalGenerator::GetExtraGeneratorName() const
3847
0
{
3848
0
  return this->ExtraGenerator ? this->ExtraGenerator->GetName()
3849
0
                              : std::string();
3850
0
}
3851
3852
void cmGlobalGenerator::FileReplacedDuringGenerate(std::string const& filename)
3853
0
{
3854
0
  this->FilesReplacedDuringGenerate.push_back(filename);
3855
0
}
3856
3857
void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
3858
  std::vector<std::string>& filenames)
3859
0
{
3860
0
  filenames.clear();
3861
0
  std::copy(this->FilesReplacedDuringGenerate.begin(),
3862
0
            this->FilesReplacedDuringGenerate.end(),
3863
0
            std::back_inserter(filenames));
3864
0
}
3865
3866
cmGlobalGenerator::TargetDependSet cmGlobalGenerator::GetTargetsForProject(
3867
  cmLocalGenerator const* root,
3868
  std::vector<cmLocalGenerator*> const& generators) const
3869
0
{
3870
0
  TargetDependSet projectTargets;
3871
  // loop over all local generators
3872
0
  for (auto* generator : generators) {
3873
    // check to make sure generator is not excluded
3874
0
    if (this->IsExcluded(root, generator)) {
3875
0
      continue;
3876
0
    }
3877
    // loop over all the generator targets in the makefile
3878
0
    for (auto const& target : generator->GetGeneratorTargets()) {
3879
0
      if (this->IsRootOnlyTarget(target.get()) &&
3880
0
          target->GetLocalGenerator() != root) {
3881
0
        continue;
3882
0
      }
3883
      // Get the set of targets that depend on target
3884
0
      this->AddTargetDepends(target.get(), projectTargets);
3885
0
    }
3886
0
  }
3887
0
  return projectTargets;
3888
0
}
3889
3890
bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
3891
0
{
3892
0
  return (target->GetType() == cm::TargetType::GLOBAL_TARGET ||
3893
0
          target->GetName() == this->GetAllTargetName());
3894
0
}
3895
3896
void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
3897
                                         TargetDependSet& projectTargets) const
3898
0
{
3899
  // add the target itself
3900
0
  if (projectTargets.insert(target).second) {
3901
    // This is the first time we have encountered the target.
3902
    // Recursively follow its dependencies.
3903
0
    for (auto const& t : this->GetTargetDirectDepends(target)) {
3904
0
      this->AddTargetDepends(t, projectTargets);
3905
0
    }
3906
0
  }
3907
0
}
3908
3909
void cmGlobalGenerator::AddToManifest(std::string const& f)
3910
0
{
3911
  // Add to the content listing for the file's directory.
3912
0
  std::string dir = cmSystemTools::GetFilenamePath(f);
3913
0
  std::string file = cmSystemTools::GetFilenameName(f);
3914
0
  DirectoryContent& dc = this->DirectoryContentMap[dir];
3915
0
  dc.Generated.insert(file);
3916
0
  dc.All.insert(file);
3917
0
}
3918
3919
std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
3920
  std::string const& dir, bool needDisk)
3921
0
{
3922
0
  DirectoryContent& dc = this->DirectoryContentMap[dir];
3923
0
  if (needDisk) {
3924
0
    long mt = cmSystemTools::ModifiedTime(dir);
3925
0
    if (mt != dc.LastDiskTime) {
3926
      // Reset to non-loaded directory content.
3927
0
      dc.All = dc.Generated;
3928
3929
      // Load the directory content from disk.
3930
0
      cmsys::Directory d;
3931
0
      if (d.Load(dir)) {
3932
0
        unsigned long n = d.GetNumberOfFiles();
3933
0
        for (unsigned long i = 0; i < n; ++i) {
3934
0
          std::string const& f = d.GetFileName(i);
3935
0
          if (f != "." && f != "..") {
3936
0
            dc.All.insert(f);
3937
0
          }
3938
0
        }
3939
0
      }
3940
0
      dc.LastDiskTime = mt;
3941
0
    }
3942
0
  }
3943
0
  return dc.All;
3944
0
}
3945
3946
void cmGlobalGenerator::AddRuleHash(std::vector<std::string> const& outputs,
3947
                                    std::string const& content)
3948
0
{
3949
  // Ignore if there are no outputs.
3950
0
  if (outputs.empty()) {
3951
0
    return;
3952
0
  }
3953
3954
  // Compute a hash of the rule.
3955
0
  RuleHash hash;
3956
0
  {
3957
0
    cmCryptoHash md5(cmCryptoHash::AlgoMD5);
3958
0
    std::string const md5_hex = md5.HashString(content);
3959
0
    memcpy(hash.Data, md5_hex.c_str(), 32);
3960
0
  }
3961
3962
  // Shorten the output name (in expected use case).
3963
0
  std::string fname =
3964
0
    this->LocalGenerators[0]->MaybeRelativeToTopBinDir(outputs[0]);
3965
3966
  // Associate the hash with this output.
3967
0
  this->RuleHashes[fname] = hash;
3968
0
}
3969
3970
void cmGlobalGenerator::CheckRuleHashes()
3971
0
{
3972
0
  std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
3973
0
  std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt");
3974
0
  this->CheckRuleHashes(pfile, home);
3975
0
  this->WriteRuleHashes(pfile);
3976
0
}
3977
3978
void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
3979
                                        std::string const& home)
3980
0
{
3981
#if defined(_WIN32) || defined(__CYGWIN__)
3982
  cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
3983
#else
3984
0
  cmsys::ifstream fin(pfile.c_str());
3985
0
#endif
3986
0
  if (!fin) {
3987
0
    return;
3988
0
  }
3989
0
  std::string line;
3990
0
  std::string fname;
3991
0
  while (cmSystemTools::GetLineFromStream(fin, line)) {
3992
    // Line format is a 32-byte hex string followed by a space
3993
    // followed by a file name (with no escaping).
3994
3995
    // Skip blank and comment lines.
3996
0
    if (line.size() < 34 || line[0] == '#') {
3997
0
      continue;
3998
0
    }
3999
4000
    // Get the filename.
4001
0
    fname = line.substr(33);
4002
4003
    // Look for a hash for this file's rule.
4004
0
    auto const rhi = this->RuleHashes.find(fname);
4005
0
    if (rhi != this->RuleHashes.end()) {
4006
      // Compare the rule hash in the file to that we were given.
4007
0
      if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
4008
        // The rule has changed.  Delete the output so it will be
4009
        // built again.
4010
0
        fname = cmSystemTools::CollapseFullPath(fname, home);
4011
0
        cmSystemTools::RemoveFile(fname);
4012
0
      }
4013
0
    } else {
4014
      // We have no hash for a rule previously listed.  This may be a
4015
      // case where a user has turned off a build option and might
4016
      // want to turn it back on later, so do not delete the file.
4017
      // Instead, we keep the rule hash as long as the file exists so
4018
      // that if the feature is turned back on and the rule has
4019
      // changed the file is still rebuilt.
4020
0
      std::string fpath = cmSystemTools::CollapseFullPath(fname, home);
4021
0
      if (cmSystemTools::FileExists(fpath)) {
4022
0
        RuleHash hash;
4023
0
        memcpy(hash.Data, line.c_str(), 32);
4024
0
        this->RuleHashes[fname] = hash;
4025
0
      }
4026
0
    }
4027
0
  }
4028
0
}
4029
4030
void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
4031
0
{
4032
  // Now generate a new persistence file with the current hashes.
4033
0
  if (this->RuleHashes.empty()) {
4034
0
    cmSystemTools::RemoveFile(pfile);
4035
0
  } else {
4036
0
    cmGeneratedFileStream fout(pfile);
4037
0
    fout << "# Hashes of file build rules.\n";
4038
0
    for (auto const& rh : this->RuleHashes) {
4039
0
      fout.write(rh.second.Data, 32);
4040
0
      fout << ' ' << rh.first << '\n';
4041
0
    }
4042
0
  }
4043
0
}
4044
4045
void cmGlobalGenerator::WriteSummary()
4046
0
{
4047
  // Record all target directories in a central location.
4048
0
  std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
4049
0
                               "/CMakeFiles/TargetDirectories.txt");
4050
0
  cmGeneratedFileStream fout(fname);
4051
4052
0
  for (auto const& lg : this->LocalGenerators) {
4053
0
    for (auto const& tgt : lg->GetGeneratorTargets()) {
4054
0
      if (!tgt->IsInBuildSystem()) {
4055
0
        continue;
4056
0
      }
4057
0
      this->WriteSummary(tgt.get());
4058
0
      fout << tgt->GetCMFSupportDirectory() << '\n';
4059
0
    }
4060
0
  }
4061
0
}
4062
4063
void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
4064
0
{
4065
  // Place the labels file in a per-target support directory.
4066
0
  std::string dir = target->GetCMFSupportDirectory();
4067
0
  std::string file = cmStrCat(dir, "/Labels.txt");
4068
0
  std::string json_file = cmStrCat(dir, "/Labels.json");
4069
4070
0
#ifndef CMAKE_BOOTSTRAP
4071
  // Check whether labels are enabled for this target.
4072
0
  cmValue targetLabels = target->GetProperty("LABELS");
4073
0
  cmValue directoryLabels =
4074
0
    target->Target->GetMakefile()->GetProperty("LABELS");
4075
0
  cmValue cmakeDirectoryLabels =
4076
0
    target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
4077
0
  if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
4078
0
    Json::Value lj_root(Json::objectValue);
4079
0
    Json::Value& lj_target = lj_root["target"] = Json::objectValue;
4080
0
    lj_target["name"] = target->GetName();
4081
0
    Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
4082
0
    Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
4083
4084
0
    cmSystemTools::MakeDirectory(dir);
4085
0
    cmGeneratedFileStream fout(file);
4086
4087
0
    cmList labels;
4088
4089
    // List the target-wide labels.  All sources in the target get
4090
    // these labels.
4091
0
    if (targetLabels) {
4092
0
      labels.assign(*targetLabels);
4093
0
      if (!labels.empty()) {
4094
0
        fout << "# Target labels\n";
4095
0
        for (std::string const& l : labels) {
4096
0
          fout << ' ' << l << '\n';
4097
0
          lj_target_labels.append(l);
4098
0
        }
4099
0
      }
4100
0
    }
4101
4102
    // List directory labels
4103
0
    cmList directoryLabelsList;
4104
0
    cmList cmakeDirectoryLabelsList;
4105
4106
0
    if (directoryLabels) {
4107
0
      directoryLabelsList.assign(*directoryLabels);
4108
0
    }
4109
4110
0
    if (cmakeDirectoryLabels) {
4111
0
      cmakeDirectoryLabelsList.assign(*cmakeDirectoryLabels);
4112
0
    }
4113
4114
0
    if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
4115
0
      fout << "# Directory labels\n";
4116
0
    }
4117
4118
0
    for (auto const& li : directoryLabelsList) {
4119
0
      fout << ' ' << li << '\n';
4120
0
      lj_target_labels.append(li);
4121
0
    }
4122
4123
0
    for (auto const& li : cmakeDirectoryLabelsList) {
4124
0
      fout << ' ' << li << '\n';
4125
0
      lj_target_labels.append(li);
4126
0
    }
4127
4128
    // List the source files with any per-source labels.
4129
0
    fout << "# Source files and their labels\n";
4130
0
    std::vector<cmSourceFile*> sources;
4131
0
    std::vector<std::string> const& configs =
4132
0
      target->Target->GetMakefile()->GetGeneratorConfigs(
4133
0
        cmMakefile::IncludeEmptyConfig);
4134
0
    for (std::string const& c : configs) {
4135
0
      target->GetSourceFiles(sources, c);
4136
0
    }
4137
0
    auto const sourcesEnd = cmRemoveDuplicates(sources);
4138
0
    for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
4139
0
      Json::Value& lj_source = lj_sources.append(Json::objectValue);
4140
0
      std::string const& sfp = sf->ResolveFullPath();
4141
0
      fout << sfp << '\n';
4142
0
      lj_source["file"] = sfp;
4143
0
      if (cmValue svalue = sf->GetProperty("LABELS")) {
4144
0
        Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
4145
0
        labels.assign(*svalue);
4146
0
        for (auto const& label : labels) {
4147
0
          fout << ' ' << label << '\n';
4148
0
          lj_source_labels.append(label);
4149
0
        }
4150
0
      }
4151
0
    }
4152
0
    cmGeneratedFileStream json_fout(json_file);
4153
0
    json_fout << lj_root;
4154
0
  } else
4155
0
#endif
4156
0
  {
4157
0
    cmSystemTools::RemoveFile(file);
4158
0
    cmSystemTools::RemoveFile(json_file);
4159
0
  }
4160
0
}
4161
4162
// static
4163
std::string cmGlobalGenerator::EscapeJSON(std::string const& s)
4164
0
{
4165
0
  std::string result;
4166
0
  result.reserve(s.size());
4167
0
  for (char i : s) {
4168
0
    switch (i) {
4169
0
      case '"':
4170
0
      case '\\':
4171
0
        result = cmStrCat(std::move(result), '\\', i);
4172
0
        break;
4173
0
      case '\n':
4174
0
        result += "\\n";
4175
0
        break;
4176
0
      case '\t':
4177
0
        result += "\\t";
4178
0
        break;
4179
0
      default:
4180
0
        result += i;
4181
0
    }
4182
0
  }
4183
0
  return result;
4184
0
}
4185
4186
void cmGlobalGenerator::SetFilenameTargetDepends(
4187
  cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
4188
0
{
4189
0
  this->FilenameTargetDepends[sf] = tgts;
4190
0
}
4191
4192
std::set<cmGeneratorTarget const*> const&
4193
cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
4194
0
{
4195
0
  return this->FilenameTargetDepends[sf];
4196
0
}
4197
4198
std::string const& cmGlobalGenerator::GetRealPath(std::string const& dir)
4199
0
{
4200
0
  auto i = this->RealPaths.lower_bound(dir);
4201
0
  if (i == this->RealPaths.end() ||
4202
0
      this->RealPaths.key_comp()(dir, i->first)) {
4203
0
    i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
4204
0
  }
4205
0
  return i->second;
4206
0
}
4207
4208
std::string cmGlobalGenerator::NewDeferId()
4209
0
{
4210
0
  return cmStrCat("__", this->NextDeferId++);
4211
0
}
4212
4213
void cmGlobalGenerator::ProcessEvaluationFiles()
4214
0
{
4215
0
  std::vector<std::string> generatedFiles;
4216
0
  for (auto& localGen : this->LocalGenerators) {
4217
0
    localGen->ProcessEvaluationFiles(generatedFiles);
4218
0
  }
4219
0
}
4220
4221
std::string cmGlobalGenerator::ExpandCFGIntDir(
4222
  std::string const& str, std::string const& /*config*/) const
4223
0
{
4224
0
  return str;
4225
0
}
4226
4227
bool cmGlobalGenerator::GenerateCPackPropertiesFile()
4228
0
{
4229
0
  cmake::InstalledFilesMap const& installedFiles =
4230
0
    this->CMakeInstance->GetInstalledFiles();
4231
4232
0
  auto const& lg = this->LocalGenerators[0];
4233
0
  cmMakefile* mf = lg->GetMakefile();
4234
4235
0
  std::vector<std::string> configs =
4236
0
    mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
4237
0
  std::string config = mf->GetDefaultConfiguration();
4238
4239
0
  std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
4240
0
                              "/CPackProperties.cmake");
4241
4242
0
  if (!cmSystemTools::FileExists(path) && installedFiles.empty()) {
4243
0
    return true;
4244
0
  }
4245
4246
0
  cmGeneratedFileStream file(path);
4247
0
  file << "# CPack properties\n";
4248
4249
0
  for (auto const& i : installedFiles) {
4250
0
    cmInstalledFile const& installedFile = i.second;
4251
4252
0
    cmCPackPropertiesGenerator cpackPropertiesGenerator(
4253
0
      lg.get(), installedFile, configs);
4254
4255
0
    cpackPropertiesGenerator.Generate(file, config, configs);
4256
0
  }
4257
4258
0
  return true;
4259
0
}
4260
4261
cmInstallRuntimeDependencySet*
4262
cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
4263
0
{
4264
0
  auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
4265
0
  auto* retval = set.get();
4266
0
  this->RuntimeDependencySets.push_back(std::move(set));
4267
0
  return retval;
4268
0
}
4269
4270
cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
4271
  std::string const& name)
4272
0
{
4273
0
  auto it = this->RuntimeDependencySetsByName.find(name);
4274
0
  if (it == this->RuntimeDependencySetsByName.end()) {
4275
0
    auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
4276
0
    it =
4277
0
      this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
4278
0
        .first;
4279
0
    this->RuntimeDependencySets.push_back(std::move(set));
4280
0
  }
4281
0
  return it->second;
4282
0
}
4283
4284
cmGlobalGenerator::StripCommandStyle cmGlobalGenerator::GetStripCommandStyle(
4285
  std::string const& strip)
4286
0
{
4287
#ifdef __APPLE__
4288
  auto i = this->StripCommandStyleMap.find(strip);
4289
  if (i == this->StripCommandStyleMap.end()) {
4290
    StripCommandStyle style = StripCommandStyle::Default;
4291
4292
    // Try running strip tool with Apple-specific options.
4293
    std::vector<std::string> cmd{ strip, "-u", "-r" };
4294
    std::string out;
4295
    std::string err;
4296
    int ret;
4297
    if (cmSystemTools::RunSingleCommand(cmd, &out, &err, &ret, nullptr,
4298
                                        cmSystemTools::OUTPUT_NONE) &&
4299
        // Check for Apple-specific output.
4300
        ret != 0 && cmHasLiteralPrefix(err, "fatal error: /") &&
4301
        err.find("/usr/bin/strip: no files specified") != std::string::npos) {
4302
      style = StripCommandStyle::Apple;
4303
    }
4304
    i = this->StripCommandStyleMap.emplace(strip, style).first;
4305
  }
4306
  return i->second;
4307
#else
4308
0
  static_cast<void>(strip);
4309
0
  return StripCommandStyle::Default;
4310
0
#endif
4311
0
}
4312
4313
std::string cmGlobalGenerator::GetEncodedLiteral(std::string const& lit)
4314
0
{
4315
0
  std::string result = lit;
4316
0
  return this->EncodeLiteral(result);
4317
0
}
4318
4319
void cmGlobalGenerator::AddInstallScript(std::string const& file)
4320
0
{
4321
0
  this->InstallScripts.push_back(file);
4322
0
}
4323
4324
void cmGlobalGenerator::AddTestFile(std::string const& file)
4325
0
{
4326
0
  this->TestFiles.push_back(file);
4327
0
}
4328
4329
void cmGlobalGenerator::AddCMakeFilesToRebuild(
4330
  std::vector<std::string>& files) const
4331
0
{
4332
0
  files.insert(files.end(), this->InstallScripts.begin(),
4333
0
               this->InstallScripts.end());
4334
0
  files.insert(files.end(), this->TestFiles.begin(), this->TestFiles.end());
4335
0
}
4336
4337
bool cmGlobalGenerator::ShouldWarnExperimental(cm::string_view featureName,
4338
                                               cm::string_view featureUuid)
4339
0
{
4340
0
  return this->WarnedExperimental
4341
0
    .emplace(cmStrCat(featureName, '-', featureUuid))
4342
0
    .second;
4343
0
}
4344
4345
cm::optional<cmXcFrameworkPlist> cmGlobalGenerator::GetXcFrameworkPListContent(
4346
  std::string const& path) const
4347
0
{
4348
0
  cm::optional<cmXcFrameworkPlist> result;
4349
0
  auto i = this->XcFrameworkPListContentMap.find(path);
4350
0
  if (i != this->XcFrameworkPListContentMap.end()) {
4351
0
    result = i->second;
4352
0
  }
4353
0
  return result;
4354
0
}
4355
4356
void cmGlobalGenerator::SetXcFrameworkPListContent(
4357
  std::string const& path, cmXcFrameworkPlist const& content)
4358
0
{
4359
0
  this->XcFrameworkPListContentMap.emplace(path, content);
4360
0
}