Coverage Report

Created: 2026-03-12 06:35

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