Coverage Report

Created: 2026-02-09 06:05

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::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
1390
0
{
1391
  // If the property is not enabled then okay.
1392
0
  if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1393
0
        "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
1394
0
    return true;
1395
0
  }
1396
1397
  // This generator does not support duplicate custom targets.
1398
0
  std::ostringstream e;
1399
  // clang-format off
1400
0
  e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
1401
0
       "global property.  "
1402
0
       "The \"" << this->GetName() << "\" generator does not support "
1403
0
       "duplicate custom targets.  "
1404
0
       "Consider using a Makefiles generator or fix the project to not "
1405
0
       "use duplicate target names.";
1406
  // clang-format on
1407
0
  cmSystemTools::Error(e.str());
1408
0
  return false;
1409
0
}
1410
1411
void cmGlobalGenerator::ComputeBuildFileGenerators()
1412
0
{
1413
0
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1414
0
    std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens =
1415
0
      this->Makefiles[i]->GetExportBuildFileGenerators();
1416
0
    for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) {
1417
0
      g->Compute(this->LocalGenerators[i].get());
1418
0
    }
1419
0
  }
1420
0
}
1421
1422
bool cmGlobalGenerator::UnsupportedVariableIsDefined(std::string const& name,
1423
                                                     bool supported) const
1424
0
{
1425
0
  if (!supported && this->Makefiles.front()->GetDefinition(name)) {
1426
0
    std::ostringstream e;
1427
    /* clang-format off */
1428
0
    e <<
1429
0
      "Generator\n"
1430
0
      "  " << this->GetName() << "\n"
1431
0
      "does not support variable\n"
1432
0
      "  " << name << "\n"
1433
0
      "but it has been specified."
1434
0
      ;
1435
    /* clang-format on */
1436
0
    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
1437
0
    return true;
1438
0
  }
1439
1440
0
  return false;
1441
0
}
1442
1443
bool cmGlobalGenerator::Compute()
1444
0
{
1445
  // Make sure unsupported variables are not used.
1446
0
  if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE",
1447
0
                                         this->SupportsDefaultBuildType())) {
1448
0
    return false;
1449
0
  }
1450
0
  if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS",
1451
0
                                         this->SupportsCrossConfigs())) {
1452
0
    return false;
1453
0
  }
1454
0
  if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS",
1455
0
                                         this->SupportsDefaultConfigs())) {
1456
0
    return false;
1457
0
  }
1458
0
  if (!this->InspectConfigTypeVariables()) {
1459
0
    return false;
1460
0
  }
1461
1462
0
  if (cmValue v = this->CMakeInstance->GetCacheDefinition(
1463
0
        "CMAKE_INTERMEDIATE_DIR_STRATEGY")) {
1464
0
    this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_INTERMEDIATE_DIR_STRATEGY");
1465
0
    if (*v == "FULL") {
1466
0
      this->IntDirStrategy = IntermediateDirStrategy::Full;
1467
0
    } else if (*v == "SHORT") {
1468
0
      this->IntDirStrategy = IntermediateDirStrategy::Short;
1469
0
    } else {
1470
0
      this->GetCMakeInstance()->IssueMessage(
1471
0
        MessageType::FATAL_ERROR,
1472
0
        cmStrCat("Unsupported intermediate directory strategy '", *v, '\''));
1473
0
      return false;
1474
0
    }
1475
0
  }
1476
0
  if (cmValue v = this->CMakeInstance->GetCacheDefinition(
1477
0
        "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY")) {
1478
0
    this->GetCMakeInstance()->MarkCliAsUsed(
1479
0
      "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY");
1480
0
    if (*v == "FULL") {
1481
0
      this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Full;
1482
0
    } else if (*v == "SHORT") {
1483
0
      this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Short;
1484
0
    } else {
1485
0
      this->GetCMakeInstance()->IssueMessage(
1486
0
        MessageType::FATAL_ERROR,
1487
0
        cmStrCat("Unsupported autogen intermediate directory strategy '", *v,
1488
0
                 '\''));
1489
0
      return false;
1490
0
    }
1491
0
  }
1492
1493
  // Some generators track files replaced during the Generate.
1494
  // Start with an empty vector:
1495
0
  this->FilesReplacedDuringGenerate.clear();
1496
1497
  // clear targets to issue warning CMP0068 for
1498
0
  this->CMP0068WarnTargets.clear();
1499
1500
  // Check whether this generator is allowed to run.
1501
0
  if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
1502
0
    return false;
1503
0
  }
1504
0
  this->FinalizeTargetConfiguration();
1505
1506
0
  if (!this->AddBuildDatabaseTargets()) {
1507
0
    return false;
1508
0
  }
1509
1510
0
  this->CreateGenerationObjects();
1511
1512
  // at this point this->LocalGenerators has been filled,
1513
  // so create the map from project name to vector of local generators
1514
0
  this->FillProjectMap();
1515
1516
0
  this->CreateFileGenerateOutputs();
1517
1518
  // Iterate through all targets and add verification targets for header sets
1519
0
  if (!this->AddHeaderSetVerification()) {
1520
0
    return false;
1521
0
  }
1522
1523
0
#ifndef CMAKE_BOOTSTRAP
1524
0
  this->QtAutoGen =
1525
0
    cm::make_unique<cmQtAutoGenGlobalInitializer>(this->LocalGenerators);
1526
0
  if (!this->QtAutoGen->InitializeCustomTargets()) {
1527
0
    return false;
1528
0
  }
1529
0
#endif
1530
1531
  // Perform up-front computation in order to handle errors (such as unknown
1532
  // features) at this point. While processing the compile features we also
1533
  // calculate and cache the language standard required by the compile
1534
  // features.
1535
  //
1536
  // Synthetic targets performed this inside of
1537
  // `cmLocalGenerator::DiscoverSyntheticTargets`
1538
0
  for (auto const& localGen : this->LocalGenerators) {
1539
0
    if (!localGen->ComputeTargetCompileFeatures()) {
1540
0
      return false;
1541
0
    }
1542
0
  }
1543
1544
  // We now have all targets set up and std levels constructed. Add
1545
  // `__CMAKE::CXX*` targets as link dependencies to all targets which need
1546
  // them.
1547
  //
1548
  // Synthetic targets performed this inside of
1549
  // `cmLocalGenerator::DiscoverSyntheticTargets`
1550
0
  if (!this->ApplyCXXStdTargets()) {
1551
0
    return false;
1552
0
  }
1553
1554
  // Iterate through all targets and set up C++20 module targets.
1555
  // Create target templates for each imported target with C++20 modules.
1556
  // INTERFACE library with BMI-generating rules and a collation step?
1557
  // Maybe INTERFACE libraries with modules files should just do BMI-only?
1558
  // Make `add_dependencies(imported_target
1559
  // $<$<TARGET_NAME_IF_EXISTS:uses_imported>:synth1>
1560
  // $<$<TARGET_NAME_IF_EXISTS:other_uses_imported>:synth2>)`
1561
  //
1562
  // Note that synthetic target creation performs the above marked
1563
  // steps on the created targets.
1564
0
  if (!this->DiscoverSyntheticTargets()) {
1565
0
    return false;
1566
0
  }
1567
1568
  // Perform after-generator-target generator actions. These involve collecting
1569
  // information gathered during the construction of generator targets.
1570
0
  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
1571
0
    this->Makefiles[i]->GenerateAfterGeneratorTargets(
1572
0
      *this->LocalGenerators[i]);
1573
0
  }
1574
1575
  // Add generator specific helper commands
1576
0
  for (auto const& localGen : this->LocalGenerators) {
1577
0
    localGen->AddHelperCommands();
1578
0
  }
1579
1580
0
  this->MarkTargetsForPchReuse();
1581
1582
  // Add automatically generated sources (e.g. unity build).
1583
  // Add unity sources after computing compile features.  Unity sources do
1584
  // not change the set of languages or features, but we need to know them
1585
  // to filter out sources that are scanned for C++ module dependencies.
1586
0
  if (!this->AddAutomaticSources()) {
1587
0
    return false;
1588
0
  }
1589
1590
0
#ifndef CMAKE_BOOTSTRAP
1591
0
  bool isTryCompile = this->GetGlobalSetting("IN_TRY_COMPILE").IsOn();
1592
0
  bool sbomEnabled = cmExperimental::HasSupportEnabled(
1593
0
    *this->Makefiles[0], cmExperimental::Feature::GenerateSbom);
1594
1595
  // Automatically generate SBOM files if enabled.
1596
0
  cmValue sbomFormat = this->GetGlobalSetting("CMAKE_INSTALL_SBOM_FORMATS");
1597
0
  if (sbomFormat.IsSet() && !this->Makefiles[0]->ExplicitlyGeneratesSbom() &&
1598
0
      sbomEnabled && !isTryCompile) {
1599
0
    std::string location =
1600
0
      this->Makefiles[0]->GetSafeDefinition("CMAKE_INSTALL_LIBDIR");
1601
0
    if (location.empty()) {
1602
0
      location = "lib";
1603
0
    }
1604
1605
0
    std::string projectName = this->LocalGenerators[0]->GetProjectName();
1606
0
    cmSbomArguments sbomDefaultArgs;
1607
0
    sbomDefaultArgs.ProjectName = projectName;
1608
0
    for (auto& exportSet : this->ExportSets) {
1609
0
      sbomDefaultArgs.PackageName = exportSet.first;
1610
0
      std::string dest = cmStrCat(location, "/sbom/", projectName);
1611
0
      this->Makefiles[0]->AddInstallGenerator(
1612
0
        cm::make_unique<cmInstallSbomExportGenerator>(
1613
0
          &exportSet.second, dest, "", std::vector<std::string>(), "",
1614
0
          cmInstallGenerator::SelectMessageLevel(this->Makefiles[0].get()),
1615
0
          false, std::move(sbomDefaultArgs), "",
1616
0
          this->Makefiles[0]->GetBacktrace()));
1617
0
    }
1618
0
  }
1619
0
#endif
1620
1621
0
  for (auto const& localGen : this->LocalGenerators) {
1622
0
    cmMakefile* mf = localGen->GetMakefile();
1623
0
    for (auto const& g : mf->GetInstallGenerators()) {
1624
0
      if (!g->Compute(localGen.get())) {
1625
0
        return false;
1626
0
      }
1627
0
    }
1628
0
  }
1629
1630
0
  this->AddExtraIDETargets();
1631
1632
0
#ifndef CMAKE_BOOTSTRAP
1633
0
  for (auto const& localGen : this->LocalGenerators) {
1634
0
    localGen->ResolveSourceGroupGenex();
1635
0
  }
1636
0
#endif
1637
1638
  // Trace the dependencies, after that no custom commands should be added
1639
  // because their dependencies might not be handled correctly
1640
0
  for (auto const& localGen : this->LocalGenerators) {
1641
0
    localGen->TraceDependencies();
1642
0
  }
1643
1644
  // Make sure that all (non-imported) targets have source files added!
1645
0
  if (this->CheckTargetsForMissingSources()) {
1646
0
    return false;
1647
0
  }
1648
1649
0
  this->ForceLinkerLanguages();
1650
1651
  // Compute the manifest of main targets generated.
1652
0
  for (auto const& localGen : this->LocalGenerators) {
1653
0
    localGen->ComputeTargetManifest();
1654
0
  }
1655
1656
  // Compute the inter-target dependencies.
1657
0
  if (!this->ComputeTargetDepends()) {
1658
0
    return false;
1659
0
  }
1660
0
  this->ComputeTargetOrder();
1661
1662
0
  if (this->CheckTargetsForType()) {
1663
0
    return false;
1664
0
  }
1665
1666
0
  for (auto const& localGen : this->LocalGenerators) {
1667
0
    localGen->ComputeHomeRelativeOutputPath();
1668
0
    localGen->ComputeSourceGroupSearchIndex();
1669
0
  }
1670
1671
0
  return true;
1672
0
}
1673
1674
void cmGlobalGenerator::Generate()
1675
0
{
1676
  // Create a map from local generator to the complete set of targets
1677
  // it builds by default.
1678
0
  this->InitializeProgressMarks();
1679
1680
0
  this->ProcessEvaluationFiles();
1681
1682
0
  this->CMakeInstance->UpdateProgress("Generating", 0.1f);
1683
1684
0
#ifndef CMAKE_BOOTSTRAP
1685
0
  if (!this->QtAutoGen->SetupCustomTargets()) {
1686
0
    if (!cmSystemTools::GetErrorOccurredFlag()) {
1687
0
      this->GetCMakeInstance()->IssueMessage(
1688
0
        MessageType::FATAL_ERROR,
1689
0
        "Problem setting up custom targets for QtAutoGen");
1690
0
    }
1691
0
    return;
1692
0
  }
1693
0
#endif
1694
1695
  // Generate project files
1696
0
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1697
0
    this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
1698
0
    this->LocalGenerators[i]->Generate();
1699
0
    if (!this->LocalGenerators[i]->GetMakefile()->IsOn(
1700
0
          "CMAKE_SKIP_INSTALL_RULES")) {
1701
0
      this->LocalGenerators[i]->GenerateInstallRules();
1702
0
    }
1703
0
    this->LocalGenerators[i]->GenerateTestFiles();
1704
0
    this->CMakeInstance->UpdateProgress(
1705
0
      "Generating",
1706
0
      0.1f +
1707
0
        0.9f * (static_cast<float>(i) + 1.0f) /
1708
0
          static_cast<float>(this->LocalGenerators.size()));
1709
0
  }
1710
0
  this->SetCurrentMakefile(nullptr);
1711
1712
0
  if (!this->GenerateCPackPropertiesFile()) {
1713
0
    this->GetCMakeInstance()->IssueMessage(
1714
0
      MessageType::FATAL_ERROR, "Could not write CPack properties file.");
1715
0
  }
1716
1717
0
  for (auto& buildExpSet : this->BuildExportSets) {
1718
0
    if (!buildExpSet.second->GenerateImportFile()) {
1719
0
      if (!cmSystemTools::GetErrorOccurredFlag()) {
1720
0
        this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
1721
0
                                               "Could not write export file.");
1722
0
      }
1723
0
      return;
1724
0
    }
1725
0
  }
1726
  // Update rule hashes.
1727
0
  this->CheckRuleHashes();
1728
1729
0
  this->WriteSummary();
1730
1731
0
  if (this->ExtraGenerator) {
1732
0
    this->ExtraGenerator->Generate();
1733
0
  }
1734
1735
  // Perform validation checks on memoized link structures.
1736
0
  this->CheckTargetLinkLibraries();
1737
1738
0
  if (!this->CMP0068WarnTargets.empty()) {
1739
0
    std::ostringstream w;
1740
    /* clang-format off */
1741
0
    w <<
1742
0
      cmPolicies::GetPolicyWarning(cmPolicies::CMP0068) << "\n"
1743
0
      "For compatibility with older versions of CMake, the install_name "
1744
0
      "fields for the following targets are still affected by RPATH "
1745
0
      "settings:\n"
1746
0
      ;
1747
    /* clang-format on */
1748
0
    for (std::string const& t : this->CMP0068WarnTargets) {
1749
0
      w << ' ' << t << '\n';
1750
0
    }
1751
0
    this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
1752
0
                                           w.str());
1753
0
  }
1754
0
}
1755
1756
#if !defined(CMAKE_BOOTSTRAP)
1757
void cmGlobalGenerator::WriteJsonContent(std::string const& path,
1758
                                         Json::Value const& value) const
1759
0
{
1760
0
  cmsys::ofstream ftmp(path.c_str());
1761
0
  this->JsonWriter->write(value, &ftmp);
1762
0
  ftmp << '\n';
1763
0
  ftmp.close();
1764
0
}
1765
1766
void cmGlobalGenerator::WriteInstallJson() const
1767
0
{
1768
0
  Json::Value index(Json::objectValue);
1769
0
  index["InstallScripts"] = Json::arrayValue;
1770
0
  for (auto const& file : this->InstallScripts) {
1771
0
    index["InstallScripts"].append(file);
1772
0
  }
1773
0
  index["Parallel"] =
1774
0
    this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
1775
0
      "INSTALL_PARALLEL");
1776
0
  if (this->SupportsDefaultConfigs()) {
1777
0
    index["Configs"] = Json::arrayValue;
1778
0
    for (auto const& config : this->GetDefaultConfigs()) {
1779
0
      index["Configs"].append(config);
1780
0
    }
1781
0
  }
1782
0
  this->WriteJsonContent(
1783
0
    cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
1784
0
             "/CMakeFiles/InstallScripts.json"),
1785
0
    index);
1786
0
}
1787
#endif
1788
1789
bool cmGlobalGenerator::ComputeTargetDepends()
1790
0
{
1791
0
  cmComputeTargetDepends ctd(this);
1792
0
  if (!ctd.Compute()) {
1793
0
    return false;
1794
0
  }
1795
0
  for (cmGeneratorTarget const* target : ctd.GetTargets()) {
1796
0
    ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
1797
0
  }
1798
0
  return true;
1799
0
}
1800
1801
std::vector<cmGeneratorTarget*>
1802
cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const
1803
0
{
1804
0
  std::vector<cmGeneratorTarget*> gts;
1805
0
  cm::append(gts, lg->GetGeneratorTargets());
1806
0
  std::sort(gts.begin(), gts.end(),
1807
0
            [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
1808
0
              return this->TargetOrderIndexLess(l, r);
1809
0
            });
1810
0
  return gts;
1811
0
}
1812
1813
void cmGlobalGenerator::ComputeTargetOrder()
1814
0
{
1815
0
  size_t index = 0;
1816
0
  auto const& lgens = this->GetLocalGenerators();
1817
0
  for (auto const& lgen : lgens) {
1818
0
    auto const& targets = lgen->GetGeneratorTargets();
1819
0
    for (auto const& gt : targets) {
1820
0
      this->ComputeTargetOrder(gt.get(), index);
1821
0
    }
1822
0
  }
1823
0
  assert(index == this->TargetOrderIndex.size());
1824
0
}
1825
1826
void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
1827
                                           size_t& index)
1828
0
{
1829
0
  std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0);
1830
0
  auto insertion = this->TargetOrderIndex.insert(value);
1831
0
  if (!insertion.second) {
1832
0
    return;
1833
0
  }
1834
0
  auto entry = insertion.first;
1835
1836
0
  auto const& deps = this->GetTargetDirectDepends(gt);
1837
0
  for (auto const& d : deps) {
1838
0
    this->ComputeTargetOrder(d, index);
1839
0
  }
1840
1841
0
  entry->second = index++;
1842
0
}
1843
1844
bool cmGlobalGenerator::ApplyCXXStdTargets()
1845
0
{
1846
0
  for (auto const& gen : this->LocalGenerators) {
1847
1848
    // tgt->ApplyCXXStd can create targets itself, so we need iterators which
1849
    // won't be invalidated by that target creation
1850
0
    auto const& genTgts = gen->GetGeneratorTargets();
1851
0
    std::vector<cmGeneratorTarget*> existingTgts;
1852
0
    existingTgts.reserve(genTgts.size());
1853
0
    for (auto const& tgt : genTgts) {
1854
0
      existingTgts.push_back(tgt.get());
1855
0
    }
1856
1857
0
    for (auto const& tgt : existingTgts) {
1858
0
      if (!tgt->ApplyCXXStdTargets()) {
1859
0
        return false;
1860
0
      }
1861
0
    }
1862
0
  }
1863
1864
0
  return true;
1865
0
}
1866
1867
bool cmGlobalGenerator::DiscoverSyntheticTargets()
1868
0
{
1869
0
  cmSyntheticTargetCache cache;
1870
1871
0
  for (auto const& gen : this->LocalGenerators) {
1872
    // Because DiscoverSyntheticTargets() adds generator targets, we need to
1873
    // cache the existing list of generator targets before starting.
1874
0
    std::vector<cmGeneratorTarget*> genTargets;
1875
0
    genTargets.reserve(gen->GetGeneratorTargets().size());
1876
0
    for (auto const& tgt : gen->GetGeneratorTargets()) {
1877
0
      genTargets.push_back(tgt.get());
1878
0
    }
1879
1880
0
    for (auto* tgt : genTargets) {
1881
0
      std::vector<std::string> const& configs =
1882
0
        tgt->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
1883
1884
0
      for (auto const& config : configs) {
1885
0
        if (!tgt->DiscoverSyntheticTargets(cache, config)) {
1886
0
          return false;
1887
0
        }
1888
0
      }
1889
0
    }
1890
0
  }
1891
1892
0
  return true;
1893
0
}
1894
1895
bool cmGlobalGenerator::AddHeaderSetVerification()
1896
0
{
1897
0
  for (auto const& gen : this->LocalGenerators) {
1898
    // Because AddHeaderSetVerification() adds generator targets, we need to
1899
    // cache the existing list of generator targets before starting.
1900
0
    std::vector<cmGeneratorTarget*> genTargets;
1901
0
    genTargets.reserve(gen->GetGeneratorTargets().size());
1902
0
    for (auto const& tgt : gen->GetGeneratorTargets()) {
1903
0
      genTargets.push_back(tgt.get());
1904
0
    }
1905
1906
0
    for (auto* tgt : genTargets) {
1907
0
      if (!tgt->AddHeaderSetVerification()) {
1908
0
        return false;
1909
0
      }
1910
0
    }
1911
0
  }
1912
1913
0
  cmTarget* allVerifyInterfaceTarget =
1914
0
    this->Makefiles.front()->FindTargetToUse(
1915
0
      "all_verify_interface_header_sets",
1916
0
      { cmStateEnums::TargetDomain::NATIVE });
1917
0
  if (allVerifyInterfaceTarget) {
1918
0
    this->LocalGenerators.front()->AddGeneratorTarget(
1919
0
      cm::make_unique<cmGeneratorTarget>(allVerifyInterfaceTarget,
1920
0
                                         this->LocalGenerators.front().get()));
1921
0
  }
1922
0
  cmTarget* allVerifyPrivateTarget = this->Makefiles.front()->FindTargetToUse(
1923
0
    "all_verify_private_header_sets", { cmStateEnums::TargetDomain::NATIVE });
1924
0
  if (allVerifyPrivateTarget) {
1925
0
    this->LocalGenerators.front()->AddGeneratorTarget(
1926
0
      cm::make_unique<cmGeneratorTarget>(allVerifyPrivateTarget,
1927
0
                                         this->LocalGenerators.front().get()));
1928
0
  }
1929
1930
0
  if (allVerifyInterfaceTarget || allVerifyPrivateTarget) {
1931
0
    cmTarget* allVerifyTarget =
1932
0
      this->GetMakefiles().front()->AddNewUtilityTarget(
1933
0
        "all_verify_header_sets", true);
1934
0
    this->LocalGenerators.front()->AddGeneratorTarget(
1935
0
      cm::make_unique<cmGeneratorTarget>(allVerifyTarget,
1936
0
                                         this->LocalGenerators.front().get()));
1937
0
    if (allVerifyInterfaceTarget) {
1938
0
      allVerifyTarget->AddUtility(allVerifyInterfaceTarget->GetName(), false);
1939
0
    }
1940
0
    if (allVerifyPrivateTarget) {
1941
0
      allVerifyTarget->AddUtility(allVerifyPrivateTarget->GetName(), false);
1942
0
    }
1943
0
  }
1944
1945
0
  return true;
1946
0
}
1947
1948
void cmGlobalGenerator::CreateFileGenerateOutputs()
1949
0
{
1950
0
  for (auto const& lg : this->LocalGenerators) {
1951
0
    lg->CreateEvaluationFileOutputs();
1952
0
  }
1953
0
}
1954
1955
bool cmGlobalGenerator::AddAutomaticSources()
1956
0
{
1957
0
  for (auto const& lg : this->LocalGenerators) {
1958
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
1959
0
      if (!gt->CanCompileSources()) {
1960
0
        continue;
1961
0
      }
1962
0
      lg->AddUnityBuild(gt.get());
1963
0
      lg->AddISPCDependencies(gt.get());
1964
      // Targets that reuse a PCH are handled below.
1965
0
      if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1966
0
        lg->AddPchDependencies(gt.get());
1967
0
      }
1968
0
      lg->AddXCConfigSources(gt.get());
1969
0
    }
1970
0
  }
1971
0
  for (auto const& lg : this->LocalGenerators) {
1972
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
1973
0
      if (!gt->CanCompileSources()) {
1974
0
        continue;
1975
0
      }
1976
      // Handle targets that reuse a PCH from an above-handled target.
1977
0
      if (gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1978
0
        lg->AddPchDependencies(gt.get());
1979
0
      }
1980
0
    }
1981
0
  }
1982
  // The above transformations may have changed the classification of sources,
1983
  // e.g., sources that go into unity builds become SourceKindUnityBatched.
1984
  // Clear the source list and classification cache (KindedSources) of all
1985
  // targets so that it will be recomputed correctly by the generators later
1986
  // now that the above transformations are done for all targets.
1987
  // Also clear the link interface cache to support $<TARGET_OBJECTS:objlib>
1988
  // in INTERFACE_LINK_LIBRARIES because the list of object files may have
1989
  // been changed by conversion to a unity build or addition of a PCH source.
1990
0
  for (auto const& lg : this->LocalGenerators) {
1991
0
    for (auto const& gt : lg->GetGeneratorTargets()) {
1992
0
      gt->ClearSourcesCache();
1993
0
      gt->ClearLinkInterfaceCache();
1994
0
    }
1995
0
  }
1996
0
  return true;
1997
0
}
1998
1999
std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
2000
  cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
2001
0
{
2002
0
  return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir);
2003
0
}
2004
2005
std::unique_ptr<cmLinkLineComputer>
2006
cmGlobalGenerator::CreateMSVC60LinkLineComputer(
2007
  cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
2008
0
{
2009
0
  return std::unique_ptr<cmLinkLineComputer>(
2010
0
    cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
2011
0
}
2012
2013
void cmGlobalGenerator::FinalizeTargetConfiguration()
2014
0
{
2015
0
  std::vector<std::string> const langs =
2016
0
    this->CMakeInstance->GetState()->GetEnabledLanguages();
2017
2018
  // Construct per-target generator information.
2019
0
  for (auto const& mf : this->Makefiles) {
2020
0
    cmBTStringRange const compileDefinitions =
2021
0
      mf->GetCompileDefinitionsEntries();
2022
0
    for (auto& target : mf->GetTargets()) {
2023
0
      cmTarget* t = &target.second;
2024
0
      t->FinalizeTargetConfiguration(compileDefinitions);
2025
0
    }
2026
2027
    // The standard include directories for each language
2028
    // should be treated as system include directories.
2029
0
    std::set<std::string> standardIncludesSet;
2030
0
    for (std::string const& li : langs) {
2031
0
      std::string const standardIncludesVar =
2032
0
        cmStrCat("CMAKE_", li, "_STANDARD_INCLUDE_DIRECTORIES");
2033
0
      std::string const& standardIncludesStr =
2034
0
        mf->GetSafeDefinition(standardIncludesVar);
2035
0
      cmList standardIncludesList{ standardIncludesStr };
2036
0
      standardIncludesSet.insert(standardIncludesList.begin(),
2037
0
                                 standardIncludesList.end());
2038
0
    }
2039
0
    mf->AddSystemIncludeDirectories(standardIncludesSet);
2040
0
  }
2041
0
}
2042
2043
void cmGlobalGenerator::CreateGeneratorTargets(
2044
  TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
2045
  std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
2046
0
{
2047
0
  if (targetTypes == AllTargets) {
2048
0
    for (cmTarget* target : mf->GetOrderedTargets()) {
2049
0
      lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg));
2050
0
    }
2051
0
  }
2052
2053
0
  for (cmTarget* t : mf->GetImportedTargets()) {
2054
0
    lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
2055
0
  }
2056
0
}
2057
2058
void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes)
2059
0
{
2060
0
  std::map<cmTarget*, cmGeneratorTarget*> importedMap;
2061
0
  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
2062
0
    auto& mf = this->Makefiles[i];
2063
0
    for (auto const& ownedImpTgt : mf->GetOwnedImportedTargets()) {
2064
0
      cmLocalGenerator* lg = this->LocalGenerators[i].get();
2065
0
      auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
2066
0
      importedMap[ownedImpTgt.get()] = gt.get();
2067
0
      lg->AddOwnedImportedGeneratorTarget(std::move(gt));
2068
0
    }
2069
0
  }
2070
2071
  // Construct per-target generator information.
2072
0
  for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
2073
0
    this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(),
2074
0
                                 this->LocalGenerators[i].get(), importedMap);
2075
0
  }
2076
0
}
2077
2078
void cmGlobalGenerator::ClearGeneratorMembers()
2079
1
{
2080
1
  this->BuildExportSets.clear();
2081
2082
1
  this->Makefiles.clear();
2083
2084
1
  this->LocalGenerators.clear();
2085
2086
1
  this->AliasTargets.clear();
2087
1
  this->ExportSets.clear();
2088
1
  this->InstallComponents.clear();
2089
1
  this->TargetDependencies.clear();
2090
1
  this->TargetSearchIndex.clear();
2091
1
  this->GeneratorTargetSearchIndex.clear();
2092
1
  this->MakefileSearchIndex.clear();
2093
1
  this->LocalGeneratorSearchIndex.clear();
2094
1
  this->TargetOrderIndex.clear();
2095
1
  this->ProjectMap.clear();
2096
1
  this->RuleHashes.clear();
2097
1
  this->DirectoryContentMap.clear();
2098
1
  this->XcFrameworkPListContentMap.clear();
2099
1
  this->BinaryDirectories.clear();
2100
1
  this->GeneratedFiles.clear();
2101
1
  this->RuntimeDependencySets.clear();
2102
1
  this->RuntimeDependencySetsByName.clear();
2103
1
  this->WarnedExperimental.clear();
2104
1
}
2105
2106
bool cmGlobalGenerator::SupportsShortObjectNames() const
2107
0
{
2108
0
  return false;
2109
0
}
2110
2111
bool cmGlobalGenerator::UseShortObjectNames(
2112
  cmStateEnums::IntermediateDirKind kind) const
2113
0
{
2114
0
  IntermediateDirStrategy strategy = IntermediateDirStrategy::Full;
2115
0
  switch (kind) {
2116
0
    case cmStateEnums::IntermediateDirKind::ObjectFiles:
2117
0
      strategy = this->IntDirStrategy;
2118
0
      break;
2119
0
    case cmStateEnums::IntermediateDirKind::QtAutogenMetadata:
2120
0
      strategy = this->QtAutogenIntDirStrategy;
2121
0
      break;
2122
0
    default:
2123
0
      assert(false);
2124
0
      break;
2125
0
  }
2126
0
  return this->SupportsShortObjectNames() &&
2127
0
    strategy == IntermediateDirStrategy::Short;
2128
0
}
2129
2130
std::string cmGlobalGenerator::GetShortBinaryOutputDir() const
2131
0
{
2132
0
  return ".o";
2133
0
}
2134
2135
std::string cmGlobalGenerator::ComputeTargetShortName(
2136
  std::string const& bindir, std::string const& targetName) const
2137
0
{
2138
0
  auto const& rcwbd =
2139
0
    this->LocalGenerators[0]->MaybeRelativeToTopBinDir(bindir);
2140
0
  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
2141
0
  constexpr size_t HASH_TRUNCATION = 4;
2142
0
  auto dirHash = hasher.HashString(rcwbd).substr(0, HASH_TRUNCATION);
2143
0
  auto tgtHash = hasher.HashString(targetName).substr(0, HASH_TRUNCATION);
2144
0
  return cmStrCat(tgtHash, dirHash);
2145
0
}
2146
2147
cmGlobalGenerator::TargetDirectoryRegistration&
2148
cmGlobalGenerator::RegisterTargetDirectory(cmGeneratorTarget const* tgt,
2149
                                           std::string const& targetDir) const
2150
0
{
2151
0
  if (!tgt->IsNormal() || tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
2152
0
      tgt->Target->IsForTryCompile()) {
2153
0
    static TargetDirectoryRegistration utilityRegistration(nullptr, true);
2154
0
    return utilityRegistration;
2155
0
  }
2156
2157
  // Get the registration instance for the target.
2158
0
#if __cplusplus >= 201703L
2159
0
  auto registration = this->TargetDirectoryRegistrations.try_emplace(tgt);
2160
#else
2161
  auto registration = this->TargetDirectoryRegistrations.insert(
2162
    std::make_pair(tgt, TargetDirectoryRegistration()));
2163
#endif
2164
  // If it was just inserted, search for a `CollidesWith` possibility.
2165
0
  if (registration.second) {
2166
0
    auto& otherTargets = this->TargetDirectories[targetDir];
2167
0
    if (!otherTargets.empty()) {
2168
0
      registration.first->second.CollidesWith = *otherTargets.begin();
2169
0
    }
2170
0
    otherTargets.insert(tgt);
2171
0
  }
2172
2173
0
  return registration.first->second;
2174
0
}
2175
2176
void cmGlobalGenerator::ComputeTargetObjectDirectory(
2177
  cmGeneratorTarget* /*unused*/) const
2178
0
{
2179
0
}
2180
2181
void cmGlobalGenerator::CheckTargetProperties()
2182
0
{
2183
  // check for link libraries and include directories containing "NOTFOUND"
2184
  // and for infinite loops
2185
0
  std::map<std::string, std::string> notFoundMap;
2186
0
  cmState* state = this->GetCMakeInstance()->GetState();
2187
0
  for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
2188
0
    this->Makefiles[i]->Generate(*this->LocalGenerators[i]);
2189
0
    for (auto const& target : this->Makefiles[i]->GetTargets()) {
2190
0
      if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2191
0
        continue;
2192
0
      }
2193
0
      for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
2194
0
        if (lib.first.size() > 9 && cmIsNOTFOUND(lib.first)) {
2195
0
          std::string varName = lib.first.substr(0, lib.first.size() - 9);
2196
0
          if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
2197
0
            varName += " (ADVANCED)";
2198
0
          }
2199
0
          std::string text =
2200
0
            cmStrCat(notFoundMap[varName], "\n    linked by target \"",
2201
0
                     target.second.GetName(), "\" in directory ",
2202
0
                     this->Makefiles[i]->GetCurrentSourceDirectory());
2203
0
          notFoundMap[varName] = text;
2204
0
        }
2205
0
      }
2206
0
      cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
2207
0
      if (!incDirProp) {
2208
0
        continue;
2209
0
      }
2210
2211
0
      std::string incDirs = cmGeneratorExpression::Preprocess(
2212
0
        *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
2213
2214
0
      cmList incs(incDirs);
2215
2216
0
      for (std::string const& incDir : incs) {
2217
0
        if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) {
2218
0
          std::string varName = incDir.substr(0, incDir.size() - 9);
2219
0
          if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
2220
0
            varName += " (ADVANCED)";
2221
0
          }
2222
0
          std::string text =
2223
0
            cmStrCat(notFoundMap[varName],
2224
0
                     "\n   used as include directory in directory ",
2225
0
                     this->Makefiles[i]->GetCurrentSourceDirectory());
2226
0
          notFoundMap[varName] = text;
2227
0
        }
2228
0
      }
2229
0
    }
2230
0
  }
2231
2232
0
  if (!notFoundMap.empty()) {
2233
0
    std::string notFoundVars;
2234
0
    for (auto const& notFound : notFoundMap) {
2235
0
      notFoundVars += notFound.first;
2236
0
      notFoundVars += notFound.second;
2237
0
      notFoundVars += '\n';
2238
0
    }
2239
0
    cmSystemTools::Error(
2240
0
      cmStrCat("The following variables are used in this project, "
2241
0
               "but they are set to NOTFOUND.\n"
2242
0
               "Please set them or make sure they are set and "
2243
0
               "tested correctly in the CMake files:\n",
2244
0
               notFoundVars));
2245
0
  }
2246
0
}
2247
2248
int cmGlobalGenerator::TryCompile(int jobs, std::string const& bindir,
2249
                                  std::string const& projectName,
2250
                                  std::string const& target, bool fast,
2251
                                  std::string& output, cmMakefile* mf)
2252
0
{
2253
0
  cmBuildArgs buildArgs;
2254
0
  buildArgs.jobs = jobs;
2255
0
  buildArgs.binaryDir = bindir;
2256
0
  buildArgs.projectName = projectName;
2257
0
  buildArgs.verbose = true;
2258
2259
  // if this is not set, then this is a first time configure
2260
  // and there is a good chance that the try compile stuff will
2261
  // take the bulk of the time, so try and guess some progress
2262
  // by getting closer and closer to 100 without actually getting there.
2263
0
  if (!this->CMakeInstance->GetState()->GetInitializedCacheValue(
2264
0
        "CMAKE_NUMBER_OF_MAKEFILES")) {
2265
    // If CMAKE_NUMBER_OF_MAKEFILES is not set
2266
    // we are in the first time progress and we have no
2267
    // idea how long it will be.  So, just move 1/10th of the way
2268
    // there each time, and don't go over 95%
2269
0
    this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2270
0
    if (this->FirstTimeProgress > 0.95f) {
2271
0
      this->FirstTimeProgress = 0.95f;
2272
0
    }
2273
0
    this->CMakeInstance->UpdateProgress("Configuring",
2274
0
                                        this->FirstTimeProgress);
2275
0
  }
2276
2277
0
  std::vector<std::string> newTarget = {};
2278
0
  if (!target.empty()) {
2279
0
    newTarget = { target };
2280
0
  }
2281
0
  std::string config =
2282
0
    mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
2283
0
  cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
2284
2285
0
  std::stringstream ostr;
2286
0
  auto ret = this->Build(buildArgs, newTarget, ostr, "", config,
2287
0
                         defaultBuildOptions, this->TryCompileTimeout,
2288
0
                         cmSystemTools::OUTPUT_NONE, {}, BuildTryCompile::Yes);
2289
0
  output = ostr.str();
2290
0
  return ret;
2291
0
}
2292
2293
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
2294
cmGlobalGenerator::GenerateBuildCommand(
2295
  std::string const& /*unused*/, std::string const& /*unused*/,
2296
  std::string const& /*unused*/, std::vector<std::string> const& /*unused*/,
2297
  std::string const& /*unused*/, int /*unused*/, bool /*unused*/,
2298
  cmBuildOptions /*unused*/, std::vector<std::string> const& /*unused*/,
2299
  BuildTryCompile /*unused*/)
2300
0
{
2301
0
  GeneratedMakeCommand makeCommand;
2302
0
  makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
2303
0
  return { std::move(makeCommand) };
2304
0
}
2305
2306
void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
2307
                                                int /*jobs*/) const
2308
0
{
2309
  // Subclasses override this method if they e.g want to give a warning that
2310
  // they do not support certain build command line options
2311
0
}
2312
2313
int cmGlobalGenerator::Build(cmBuildArgs const& buildArgs,
2314
                             std::vector<std::string> const& targets,
2315
                             std::ostream& ostr,
2316
                             std::string const& makeCommandCSTR,
2317
                             std::string const& config,
2318
                             cmBuildOptions buildOptions, cmDuration timeout,
2319
                             cmSystemTools::OutputOption outputMode,
2320
                             std::vector<std::string> const& nativeOptions,
2321
                             BuildTryCompile isInTryCompile)
2322
0
{
2323
0
  bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
2324
2325
  /**
2326
   * Run an executable command and put the stdout in output.
2327
   */
2328
0
  cmWorkingDirectory workdir(buildArgs.binaryDir);
2329
0
  ostr << "Change Dir: '" << buildArgs.binaryDir << '\'' << std::endl;
2330
0
  if (workdir.Failed()) {
2331
0
    cmSystemTools::SetRunCommandHideConsole(hideconsole);
2332
0
    std::string const& err = workdir.GetError();
2333
0
    cmSystemTools::Error(err);
2334
0
    ostr << err << std::endl;
2335
0
    return 1;
2336
0
  }
2337
0
  std::string realConfig = config;
2338
0
  if (realConfig.empty()) {
2339
0
    realConfig = this->GetDefaultBuildConfig();
2340
0
  }
2341
2342
0
  int retVal = 0;
2343
0
  cmSystemTools::SetRunCommandHideConsole(true);
2344
2345
  // Capture build command output when outputMode == OUTPUT_NONE.
2346
0
  std::string outputBuf;
2347
2348
0
  std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(
2349
0
    makeCommandCSTR, buildArgs.projectName, buildArgs.binaryDir, targets,
2350
0
    realConfig, buildArgs.jobs, buildArgs.verbose, buildOptions, nativeOptions,
2351
0
    isInTryCompile);
2352
2353
  // Workaround to convince some commands to produce output.
2354
0
  if (outputMode == cmSystemTools::OUTPUT_PASSTHROUGH &&
2355
0
      makeCommand.back().RequiresOutputForward) {
2356
0
    outputMode = cmSystemTools::OUTPUT_FORWARD;
2357
0
  }
2358
2359
  // should we do a clean first?
2360
0
  if (buildOptions.Clean) {
2361
0
    std::vector<GeneratedMakeCommand> cleanCommand =
2362
0
      this->GenerateBuildCommand(makeCommandCSTR, buildArgs.projectName,
2363
0
                                 buildArgs.binaryDir, { "clean" }, realConfig,
2364
0
                                 buildArgs.jobs, buildArgs.verbose,
2365
0
                                 buildOptions);
2366
0
    ostr << "\nRun Clean Command: " << cleanCommand.front().QuotedPrintable()
2367
0
         << std::endl;
2368
0
    if (cleanCommand.size() != 1) {
2369
0
      this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
2370
0
                                             "The generator did not produce "
2371
0
                                             "exactly one command for the "
2372
0
                                             "'clean' target");
2373
0
      return 1;
2374
0
    }
2375
0
    if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
2376
0
                                         &outputBuf, &outputBuf, &retVal,
2377
0
                                         nullptr, outputMode, timeout)) {
2378
0
      cmSystemTools::SetRunCommandHideConsole(hideconsole);
2379
0
      cmSystemTools::Error("Generator: execution of make clean failed.");
2380
0
      ostr << outputBuf << "\nGenerator: execution of make clean failed."
2381
0
           << std::endl;
2382
2383
0
      return 1;
2384
0
    }
2385
0
    ostr << outputBuf;
2386
0
  }
2387
2388
  // now build
2389
0
  std::string makeCommandStr;
2390
0
  std::string outputMakeCommandStr;
2391
0
  bool isWatcomWMake = this->CMakeInstance->GetState()->UseWatcomWMake();
2392
0
  bool needBuildOutput = isWatcomWMake;
2393
0
  std::string buildOutput;
2394
0
  ostr << "\nRun Build Command(s): ";
2395
2396
0
  retVal = 0;
2397
0
  for (auto command = makeCommand.begin();
2398
0
       command != makeCommand.end() && retVal == 0; ++command) {
2399
0
    makeCommandStr = command->Printable();
2400
0
    outputMakeCommandStr = command->QuotedPrintable();
2401
0
    if ((command + 1) != makeCommand.end()) {
2402
0
      makeCommandStr += " && ";
2403
0
      outputMakeCommandStr += " && ";
2404
0
    }
2405
2406
0
    ostr << outputMakeCommandStr << std::endl;
2407
0
    if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, &outputBuf,
2408
0
                                         &outputBuf, &retVal, nullptr,
2409
0
                                         outputMode, timeout)) {
2410
0
      cmSystemTools::SetRunCommandHideConsole(hideconsole);
2411
0
      cmSystemTools::Error(
2412
0
        cmStrCat("Generator: build tool execution failed, command was: ",
2413
0
                 makeCommandStr));
2414
0
      ostr << outputBuf
2415
0
           << "\nGenerator: build tool execution failed, command was: "
2416
0
           << outputMakeCommandStr << std::endl;
2417
2418
0
      return 1;
2419
0
    }
2420
0
    ostr << outputBuf << std::flush;
2421
0
    if (needBuildOutput) {
2422
0
      buildOutput += outputBuf;
2423
0
    }
2424
0
  }
2425
0
  ostr << std::endl;
2426
0
  cmSystemTools::SetRunCommandHideConsole(hideconsole);
2427
2428
  // The OpenWatcom tools do not return an error code when a link
2429
  // library is not found!
2430
0
  if (isWatcomWMake && retVal == 0 &&
2431
0
      buildOutput.find("W1008: cannot open") != std::string::npos) {
2432
0
    retVal = 1;
2433
0
  }
2434
2435
0
  return retVal;
2436
0
}
2437
2438
bool cmGlobalGenerator::Open(std::string const& bindir,
2439
                             std::string const& projectName, bool dryRun)
2440
0
{
2441
0
  if (this->ExtraGenerator) {
2442
0
    return this->ExtraGenerator->Open(bindir, projectName, dryRun);
2443
0
  }
2444
2445
0
  return false;
2446
0
}
2447
2448
std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
2449
  std::string const& target, std::string const& config,
2450
  std::string const& parallel, std::string const& native, bool ignoreErrors)
2451
0
{
2452
0
  std::string makeCommand = cmSystemTools::GetCMakeCommand();
2453
0
  makeCommand =
2454
0
    cmStrCat(cmSystemTools::ConvertToOutputPath(makeCommand), " --build .");
2455
0
  if (!config.empty()) {
2456
0
    makeCommand = cmStrCat(makeCommand, " --config \"", config, '"');
2457
0
  }
2458
0
  if (!parallel.empty()) {
2459
0
    makeCommand = cmStrCat(makeCommand, " --parallel \"", parallel, '"');
2460
0
  }
2461
0
  if (!target.empty()) {
2462
0
    makeCommand = cmStrCat(makeCommand, " --target \"", target, '"');
2463
0
  }
2464
0
  char const* sep = " -- ";
2465
0
  if (ignoreErrors) {
2466
0
    char const* iflag = this->GetBuildIgnoreErrorsFlag();
2467
0
    if (iflag && *iflag) {
2468
0
      makeCommand = cmStrCat(makeCommand, sep, iflag);
2469
0
      sep = " ";
2470
0
    }
2471
0
  }
2472
0
  if (!native.empty()) {
2473
0
    makeCommand = cmStrCat(makeCommand, sep, native);
2474
0
  }
2475
0
  return makeCommand;
2476
0
}
2477
2478
void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
2479
0
{
2480
0
  this->IndexMakefile(mf.get());
2481
0
  this->Makefiles.push_back(std::move(mf));
2482
2483
  // update progress
2484
  // estimate how many lg there will be
2485
0
  cmValue numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
2486
0
    "CMAKE_NUMBER_OF_MAKEFILES");
2487
2488
0
  if (!numGenC) {
2489
    // If CMAKE_NUMBER_OF_MAKEFILES is not set
2490
    // we are in the first time progress and we have no
2491
    // idea how long it will be.  So, just move half way
2492
    // there each time, and don't go over 95%
2493
0
    this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2494
0
    if (this->FirstTimeProgress > 0.95f) {
2495
0
      this->FirstTimeProgress = 0.95f;
2496
0
    }
2497
0
    this->CMakeInstance->UpdateProgress("Configuring",
2498
0
                                        this->FirstTimeProgress);
2499
0
    return;
2500
0
  }
2501
2502
0
  int numGen = atoi(numGenC->c_str());
2503
0
  float prog =
2504
0
    static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen);
2505
0
  if (prog > 1.0f) {
2506
0
    prog = 1.0f;
2507
0
  }
2508
0
  this->CMakeInstance->UpdateProgress("Configuring", prog);
2509
0
}
2510
2511
void cmGlobalGenerator::AddInstallComponent(std::string const& component)
2512
0
{
2513
0
  if (!component.empty()) {
2514
0
    this->InstallComponents.insert(component);
2515
0
  }
2516
0
}
2517
2518
void cmGlobalGenerator::MarkAsGeneratedFile(std::string const& filepath)
2519
0
{
2520
0
  this->GeneratedFiles.insert(filepath);
2521
0
}
2522
2523
bool cmGlobalGenerator::IsGeneratedFile(std::string const& filepath)
2524
0
{
2525
0
  return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end();
2526
0
}
2527
2528
void cmGlobalGenerator::EnableInstallTarget()
2529
0
{
2530
0
  this->InstallTargetEnabled = true;
2531
0
}
2532
2533
std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator(
2534
  cmMakefile* mf)
2535
0
{
2536
0
  return cm::make_unique<cmLocalGenerator>(this, mf);
2537
0
}
2538
2539
void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
2540
                                                     cmMakefile* mf)
2541
0
{
2542
0
  this->SetConfiguredFilesPath(gen);
2543
0
  this->TryCompileOuterMakefile = mf;
2544
0
  cmValue make =
2545
0
    gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
2546
0
  this->GetCMakeInstance()->AddCacheEntry(
2547
0
    "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH);
2548
  // copy the enabled languages
2549
0
  this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
2550
0
    gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
2551
0
  this->LanguagesReady = gen->LanguagesReady;
2552
0
  this->ExtensionToLanguage = gen->ExtensionToLanguage;
2553
0
  this->IgnoreExtensions = gen->IgnoreExtensions;
2554
0
  this->LanguageToOutputExtension = gen->LanguageToOutputExtension;
2555
0
  this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference;
2556
0
  this->OutputExtensions = gen->OutputExtensions;
2557
0
}
2558
2559
void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
2560
0
{
2561
0
  if (!gen->ConfiguredFilesPath.empty()) {
2562
0
    this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
2563
0
  } else {
2564
0
    this->ConfiguredFilesPath =
2565
0
      cmStrCat(gen->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
2566
0
  }
2567
0
}
2568
2569
bool cmGlobalGenerator::IsExcluded(cmStateSnapshot const& rootSnp,
2570
                                   cmStateSnapshot const& snp_) const
2571
0
{
2572
0
  cmStateSnapshot snp = snp_;
2573
0
  while (snp.IsValid()) {
2574
0
    if (snp == rootSnp) {
2575
      // No directory excludes itself.
2576
0
      return false;
2577
0
    }
2578
2579
0
    if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
2580
      // This directory is excluded from its parent.
2581
0
      return true;
2582
0
    }
2583
0
    snp = snp.GetBuildsystemDirectoryParent();
2584
0
  }
2585
0
  return false;
2586
0
}
2587
2588
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator const* root,
2589
                                   cmLocalGenerator const* gen) const
2590
0
{
2591
0
  assert(gen);
2592
2593
0
  cmStateSnapshot rootSnp = root->GetStateSnapshot();
2594
0
  cmStateSnapshot snp = gen->GetStateSnapshot();
2595
2596
0
  return this->IsExcluded(rootSnp, snp);
2597
0
}
2598
2599
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator const* root,
2600
                                   cmGeneratorTarget const* target) const
2601
0
{
2602
0
  if (!target->IsInBuildSystem()) {
2603
0
    return true;
2604
0
  }
2605
0
  cmMakefile* mf = root->GetMakefile();
2606
0
  std::string const EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
2607
0
  if (cmValue exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
2608
    // Expand the property value per configuration.
2609
0
    unsigned int trueCount = 0;
2610
0
    unsigned int falseCount = 0;
2611
0
    std::vector<std::string> const& configs =
2612
0
      mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2613
0
    for (std::string const& config : configs) {
2614
0
      cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
2615
0
      if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
2616
0
        ++trueCount;
2617
0
      } else {
2618
0
        ++falseCount;
2619
0
      }
2620
0
    }
2621
2622
    // Check whether the genex expansion of the property agrees in all
2623
    // configurations.
2624
0
    if (trueCount > 0 && falseCount > 0) {
2625
0
      std::ostringstream e;
2626
0
      e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName()
2627
0
        << "\" varies by configuration. This is not supported by the \""
2628
0
        << root->GetGlobalGenerator()->GetName() << "\" generator.";
2629
0
      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
2630
0
    }
2631
0
    return trueCount;
2632
0
  }
2633
  // This target is included in its directory.  Check whether the
2634
  // directory is excluded.
2635
0
  return this->IsExcluded(root, target->GetLocalGenerator());
2636
0
}
2637
2638
void cmGlobalGenerator::GetEnabledLanguages(
2639
  std::vector<std::string>& lang) const
2640
0
{
2641
0
  lang = this->CMakeInstance->GetState()->GetEnabledLanguages();
2642
0
}
2643
2644
int cmGlobalGenerator::GetLinkerPreference(std::string const& lang) const
2645
0
{
2646
0
  auto const it = this->LanguageToLinkerPreference.find(lang);
2647
0
  if (it != this->LanguageToLinkerPreference.end()) {
2648
0
    return it->second;
2649
0
  }
2650
0
  return 0;
2651
0
}
2652
2653
void cmGlobalGenerator::FillProjectMap()
2654
0
{
2655
0
  this->ProjectMap.clear(); // make sure we start with a clean map
2656
0
  for (auto const& localGen : this->LocalGenerators) {
2657
    // for each local generator add all projects
2658
0
    cmStateSnapshot snp = localGen->GetStateSnapshot();
2659
0
    std::string name;
2660
0
    do {
2661
0
      std::string snpProjName = snp.GetProjectName();
2662
0
      if (name != snpProjName) {
2663
0
        name = snpProjName;
2664
0
        this->ProjectMap[name].push_back(localGen.get());
2665
0
      }
2666
0
      snp = snp.GetBuildsystemDirectoryParent();
2667
0
    } while (snp.IsValid());
2668
0
  }
2669
0
}
2670
2671
cmMakefile* cmGlobalGenerator::FindMakefile(std::string const& start_dir) const
2672
0
{
2673
0
  auto const it = this->MakefileSearchIndex.find(start_dir);
2674
0
  if (it != this->MakefileSearchIndex.end()) {
2675
0
    return it->second;
2676
0
  }
2677
0
  return nullptr;
2678
0
}
2679
2680
cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
2681
  cmDirectoryId const& id) const
2682
0
{
2683
0
  auto const it = this->LocalGeneratorSearchIndex.find(id.String);
2684
0
  if (it != this->LocalGeneratorSearchIndex.end()) {
2685
0
    return it->second;
2686
0
  }
2687
0
  return nullptr;
2688
0
}
2689
2690
void cmGlobalGenerator::AddAlias(std::string const& name,
2691
                                 std::string const& tgtName)
2692
0
{
2693
0
  this->AliasTargets[name] = tgtName;
2694
0
}
2695
2696
bool cmGlobalGenerator::IsAlias(std::string const& name) const
2697
0
{
2698
0
  return cm::contains(this->AliasTargets, name);
2699
0
}
2700
2701
void cmGlobalGenerator::IndexTarget(cmTarget* t)
2702
0
{
2703
0
  if (!t->IsImported() || t->IsImportedGloballyVisible()) {
2704
0
    this->TargetSearchIndex[t->GetName()] = t;
2705
0
  }
2706
0
}
2707
2708
void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
2709
0
{
2710
0
  if (!gt->IsImported() || gt->IsImportedGloballyVisible()) {
2711
0
    this->GeneratorTargetSearchIndex[gt->GetName()] = gt;
2712
0
  }
2713
0
}
2714
2715
static char const hexDigits[] = "0123456789abcdef";
2716
2717
std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
2718
  cmGeneratorTarget const* gt)
2719
0
{
2720
  // Use the pointer value to uniquely identify the target instance.
2721
  // Use a ":" prefix to avoid conflict with project-defined targets.
2722
  // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
2723
  // other special characters.
2724
0
  constexpr size_t sizeof_ptr =
2725
0
    sizeof(gt); // NOLINT(bugprone-sizeof-expression)
2726
0
  char buf[1 + sizeof_ptr * 2];
2727
0
  char* b = buf;
2728
0
  *b++ = ':';
2729
0
  for (size_t i = 0; i < sizeof_ptr; ++i) {
2730
0
    unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
2731
0
    *b++ = hexDigits[(c & 0xf0) >> 4];
2732
0
    *b++ = hexDigits[(c & 0x0f)];
2733
0
  }
2734
0
  std::string id(buf, sizeof(buf));
2735
  // We internally index pointers to non-const generator targets
2736
  // but our callers only have pointers to const generator targets.
2737
  // They will give up non-const privileges when looking up anyway.
2738
0
  this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt);
2739
0
  return id;
2740
0
}
2741
2742
void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
2743
0
{
2744
  // We index by both source and binary directory.  add_subdirectory
2745
  // supports multiple build directories sharing the same source directory.
2746
  // The source directory index will reference only the first time it is used.
2747
0
  this->MakefileSearchIndex.insert(
2748
0
    MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf));
2749
0
  this->MakefileSearchIndex.insert(
2750
0
    MakefileMap::value_type(mf->GetCurrentBinaryDirectory(), mf));
2751
0
}
2752
2753
void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
2754
0
{
2755
0
  cmDirectoryId id = lg->GetMakefile()->GetDirectoryId();
2756
0
  this->LocalGeneratorSearchIndex[id.String] = lg;
2757
0
}
2758
2759
cmTarget* cmGlobalGenerator::FindTargetImpl(
2760
  std::string const& name, cmStateEnums::TargetDomainSet domains) const
2761
0
{
2762
0
  bool const useForeign =
2763
0
    domains.contains(cmStateEnums::TargetDomain::FOREIGN);
2764
0
  bool const useNative = domains.contains(cmStateEnums::TargetDomain::NATIVE);
2765
2766
0
  auto const it = this->TargetSearchIndex.find(name);
2767
0
  if (it != this->TargetSearchIndex.end()) {
2768
0
    if (it->second->IsForeign() ? useForeign : useNative) {
2769
0
      return it->second;
2770
0
    }
2771
0
  }
2772
0
  return nullptr;
2773
0
}
2774
2775
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
2776
  std::string const& name) const
2777
0
{
2778
0
  auto const it = this->GeneratorTargetSearchIndex.find(name);
2779
0
  if (it != this->GeneratorTargetSearchIndex.end()) {
2780
0
    return it->second;
2781
0
  }
2782
0
  return nullptr;
2783
0
}
2784
2785
cmTarget* cmGlobalGenerator::FindTarget(
2786
  std::string const& name, cmStateEnums::TargetDomainSet domains) const
2787
0
{
2788
0
  if (domains.contains(cmStateEnums::TargetDomain::ALIAS)) {
2789
0
    auto const ai = this->AliasTargets.find(name);
2790
0
    if (ai != this->AliasTargets.end()) {
2791
0
      return this->FindTargetImpl(ai->second, domains);
2792
0
    }
2793
0
  }
2794
0
  return this->FindTargetImpl(name, domains);
2795
0
}
2796
2797
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
2798
  std::string const& name) const
2799
0
{
2800
0
  auto const ai = this->AliasTargets.find(name);
2801
0
  if (ai != this->AliasTargets.end()) {
2802
0
    return this->FindGeneratorTargetImpl(ai->second);
2803
0
  }
2804
0
  return this->FindGeneratorTargetImpl(name);
2805
0
}
2806
2807
bool cmGlobalGenerator::NameResolvesToFramework(
2808
  std::string const& libname) const
2809
0
{
2810
0
  if (cmSystemTools::IsPathToFramework(libname)) {
2811
0
    return true;
2812
0
  }
2813
2814
0
  if (cmTarget* tgt = this->FindTarget(libname)) {
2815
0
    if (tgt->IsFrameworkOnApple()) {
2816
0
      return true;
2817
0
    }
2818
0
  }
2819
2820
0
  return false;
2821
0
}
2822
2823
// If the file has no extension it's either a raw executable or might
2824
// be a direct reference to a binary within a framework (bad practice!).
2825
// This is where we change the path to point to the framework directory.
2826
// .tbd files also can be located in SDK frameworks (they are
2827
// placeholders for actual libraries shipped with the OS)
2828
cm::optional<cmGlobalGenerator::FrameworkDescriptor>
2829
cmGlobalGenerator::SplitFrameworkPath(std::string const& path,
2830
                                      FrameworkFormat format) const
2831
0
{
2832
  // Check for framework structure:
2833
  //    (/path/to/)?FwName.framework
2834
  // or (/path/to/)?FwName.framework/FwName(.tbd)?
2835
  // or (/path/to/)?FwName.framework/Versions/*/FwName(.tbd)?
2836
0
  static cmsys::RegularExpression frameworkPath(
2837
0
    "((.+)/)?([^/]+)\\.framework(/Versions/([^/]+))?(/(.+))?$");
2838
2839
0
  auto ext = cmSystemTools::GetFilenameLastExtensionView(path);
2840
0
  if ((ext.empty() || ext == ".tbd" || ext == ".framework") &&
2841
0
      frameworkPath.find(path)) {
2842
0
    auto name = frameworkPath.match(3);
2843
0
    auto libname =
2844
0
      cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(7));
2845
0
    if (format == FrameworkFormat::Strict && libname.empty()) {
2846
0
      return cm::nullopt;
2847
0
    }
2848
0
    if (!libname.empty() && !cmHasPrefix(libname, name)) {
2849
0
      return cm::nullopt;
2850
0
    }
2851
2852
0
    if (libname.empty() || name.size() == libname.size()) {
2853
0
      return FrameworkDescriptor{ frameworkPath.match(2),
2854
0
                                  frameworkPath.match(5), name };
2855
0
    }
2856
2857
0
    return FrameworkDescriptor{ frameworkPath.match(2), frameworkPath.match(5),
2858
0
                                name, libname.substr(name.size()) };
2859
0
  }
2860
2861
0
  if (format == FrameworkFormat::Extended) {
2862
    // path format can be more flexible: (/path/to/)?fwName(.framework)?
2863
0
    auto fwDir = cmSystemTools::GetParentDirectory(path);
2864
0
    auto name = ext == ".framework"
2865
0
      ? cmSystemTools::GetFilenameWithoutExtension(path)
2866
0
      : cmSystemTools::GetFilenameName(path);
2867
2868
0
    return FrameworkDescriptor{ fwDir, name };
2869
0
  }
2870
2871
0
  return cm::nullopt;
2872
0
}
2873
2874
namespace {
2875
void IssueReservedTargetNameError(cmake* cm, cmTarget* tgt,
2876
                                  std::string const& targetNameAsWritten,
2877
                                  std::string const& reason)
2878
0
{
2879
0
  cm->IssueMessage(MessageType::FATAL_ERROR,
2880
0
                   cmStrCat("The target name \"", targetNameAsWritten,
2881
0
                            "\" is reserved ", reason, '.'),
2882
0
                   tgt->GetBacktrace());
2883
0
}
2884
}
2885
2886
bool cmGlobalGenerator::CheckReservedTargetName(
2887
  std::string const& targetName, std::string const& reason) const
2888
0
{
2889
0
  cmTarget* tgt = this->FindTarget(targetName);
2890
0
  if (!tgt) {
2891
0
    return true;
2892
0
  }
2893
0
  IssueReservedTargetNameError(this->GetCMakeInstance(), tgt, targetName,
2894
0
                               reason);
2895
0
  return false;
2896
0
}
2897
2898
bool cmGlobalGenerator::CheckReservedTargetNamePrefix(
2899
  std::string const& targetPrefix, std::string const& reason) const
2900
0
{
2901
0
  bool ret = true;
2902
0
  for (auto const& tgtPair : this->TargetSearchIndex) {
2903
0
    if (cmHasPrefix(tgtPair.first, targetPrefix)) {
2904
0
      IssueReservedTargetNameError(this->GetCMakeInstance(), tgtPair.second,
2905
0
                                   tgtPair.first, reason);
2906
0
      ret = false;
2907
0
    }
2908
0
  }
2909
0
  return ret;
2910
0
}
2911
2912
void cmGlobalGenerator::CreateDefaultGlobalTargets(
2913
  std::vector<GlobalTargetInfo>& targets)
2914
0
{
2915
0
  this->AddGlobalTarget_Package(targets);
2916
0
  this->AddGlobalTarget_PackageSource(targets);
2917
0
  this->AddGlobalTarget_Test(targets);
2918
0
  this->AddGlobalTarget_EditCache(targets);
2919
0
  this->AddGlobalTarget_RebuildCache(targets);
2920
0
  this->AddGlobalTarget_Install(targets);
2921
0
}
2922
2923
void cmGlobalGenerator::AddGlobalTarget_Package(
2924
  std::vector<GlobalTargetInfo>& targets)
2925
0
{
2926
0
  auto& mf = this->Makefiles[0];
2927
0
  std::string configFile =
2928
0
    cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
2929
0
  if (!cmSystemTools::FileExists(configFile)) {
2930
0
    return;
2931
0
  }
2932
2933
0
  static auto const reservedTargets = { "package", "PACKAGE" };
2934
0
  for (auto const& target : reservedTargets) {
2935
0
    if (!this->CheckReservedTargetName(target,
2936
0
                                       "when CPack packaging is enabled")) {
2937
0
      return;
2938
0
    }
2939
0
  }
2940
2941
0
  char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2942
0
  GlobalTargetInfo gti;
2943
0
  gti.Name = this->GetPackageTargetName();
2944
0
  gti.Message = "Run CPack packaging tool...";
2945
0
  gti.UsesTerminal = true;
2946
0
  gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2947
0
  cmCustomCommandLine singleLine;
2948
0
  singleLine.push_back(cmSystemTools::GetCPackCommand());
2949
0
  if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2950
0
    singleLine.push_back("-C");
2951
0
    singleLine.push_back(cmakeCfgIntDir);
2952
0
  }
2953
0
  singleLine.push_back("--config");
2954
0
  singleLine.push_back("./CPackConfig.cmake");
2955
0
  gti.CommandLines.push_back(std::move(singleLine));
2956
0
  if (this->GetPreinstallTargetName()) {
2957
0
    gti.Depends.emplace_back(this->GetPreinstallTargetName());
2958
0
  } else {
2959
0
    cmValue noPackageAll =
2960
0
      mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
2961
0
    if (noPackageAll.IsOff()) {
2962
0
      gti.Depends.emplace_back(this->GetAllTargetName());
2963
0
    }
2964
0
  }
2965
0
  targets.push_back(std::move(gti));
2966
0
}
2967
2968
void cmGlobalGenerator::AddGlobalTarget_PackageSource(
2969
  std::vector<GlobalTargetInfo>& targets)
2970
0
{
2971
0
  char const* packageSourceTargetName = this->GetPackageSourceTargetName();
2972
0
  if (!packageSourceTargetName) {
2973
0
    return;
2974
0
  }
2975
2976
0
  auto& mf = this->Makefiles[0];
2977
0
  std::string configFile =
2978
0
    cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
2979
0
  if (!cmSystemTools::FileExists(configFile)) {
2980
0
    return;
2981
0
  }
2982
2983
0
  static auto const reservedTargets = { "package_source" };
2984
0
  for (auto const& target : reservedTargets) {
2985
0
    if (!this->CheckReservedTargetName(
2986
0
          target, "when CPack source packaging is enabled")) {
2987
0
      return;
2988
0
    }
2989
0
  }
2990
2991
0
  GlobalTargetInfo gti;
2992
0
  gti.Name = packageSourceTargetName;
2993
0
  gti.Message = "Run CPack packaging tool for source...";
2994
0
  gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2995
0
  gti.UsesTerminal = true;
2996
0
  cmCustomCommandLine singleLine;
2997
0
  singleLine.push_back(cmSystemTools::GetCPackCommand());
2998
0
  singleLine.push_back("--config");
2999
0
  singleLine.push_back("./CPackSourceConfig.cmake");
3000
0
  gti.CommandLines.push_back(std::move(singleLine));
3001
0
  targets.push_back(std::move(gti));
3002
0
}
3003
3004
void cmGlobalGenerator::AddGlobalTarget_Test(
3005
  std::vector<GlobalTargetInfo>& targets)
3006
0
{
3007
0
  auto& mf = this->Makefiles[0];
3008
0
  if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
3009
0
    return;
3010
0
  }
3011
3012
0
  static auto const reservedTargets = { "test", "RUN_TESTS" };
3013
0
  for (auto const& target : reservedTargets) {
3014
0
    if (!this->CheckReservedTargetName(target,
3015
0
                                       "when CTest testing is enabled")) {
3016
0
      return;
3017
0
    }
3018
0
  }
3019
3020
0
  char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
3021
0
  GlobalTargetInfo gti;
3022
0
  gti.Name = this->GetTestTargetName();
3023
0
  gti.Message = "Running tests...";
3024
0
  gti.UsesTerminal = true;
3025
  // Unlike the 'install' target, the 'test' target does not depend on 'all'
3026
  // by default.  Enable it only if CMAKE_SKIP_TEST_ALL_DEPENDENCY is
3027
  // explicitly set to OFF.
3028
0
  if (cmValue noall = mf->GetDefinition("CMAKE_SKIP_TEST_ALL_DEPENDENCY")) {
3029
0
    if (noall.IsOff()) {
3030
0
      gti.Depends.emplace_back(this->GetAllTargetName());
3031
0
    }
3032
0
  }
3033
0
  cmCustomCommandLine singleLine;
3034
0
  singleLine.push_back(cmSystemTools::GetCTestCommand());
3035
0
  cmList args(mf->GetDefinition("CMAKE_CTEST_ARGUMENTS"));
3036
0
  for (auto const& arg : args) {
3037
0
    singleLine.push_back(arg);
3038
0
  }
3039
0
  if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
3040
0
    singleLine.push_back("-C");
3041
0
    singleLine.push_back(cmakeCfgIntDir);
3042
0
  } else // TODO: This is a hack. Should be something to do with the
3043
         // generator
3044
0
  {
3045
0
    singleLine.push_back("$(ARGS)");
3046
0
  }
3047
0
  gti.CommandLines.push_back(std::move(singleLine));
3048
0
  targets.push_back(std::move(gti));
3049
0
}
3050
3051
void cmGlobalGenerator::ReserveGlobalTargetCodegen()
3052
0
{
3053
  // Read the policy value at the end of the top-level CMakeLists.txt file
3054
  // since it's a global policy that affects the whole project.
3055
0
  auto& mf = this->Makefiles[0];
3056
0
  auto const policyStatus = mf->GetPolicyStatus(cmPolicies::CMP0171);
3057
3058
0
  this->AllowGlobalTargetCodegen = (policyStatus == cmPolicies::NEW);
3059
3060
0
  cmTarget* tgt = this->FindTarget("codegen");
3061
0
  if (!tgt) {
3062
0
    return;
3063
0
  }
3064
3065
0
  MessageType messageType = MessageType::AUTHOR_WARNING;
3066
0
  std::ostringstream e;
3067
0
  bool issueMessage = false;
3068
0
  switch (policyStatus) {
3069
0
    case cmPolicies::WARN:
3070
0
      e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0171) << '\n';
3071
0
      issueMessage = true;
3072
0
      CM_FALLTHROUGH;
3073
0
    case cmPolicies::OLD:
3074
0
      break;
3075
0
    case cmPolicies::NEW:
3076
0
      issueMessage = true;
3077
0
      messageType = MessageType::FATAL_ERROR;
3078
0
      break;
3079
0
  }
3080
0
  if (issueMessage) {
3081
0
    e << "The target name \"codegen\" is reserved.";
3082
0
    this->GetCMakeInstance()->IssueMessage(messageType, e.str(),
3083
0
                                           tgt->GetBacktrace());
3084
0
    if (messageType == MessageType::FATAL_ERROR) {
3085
0
      cmSystemTools::SetFatalErrorOccurred();
3086
0
      return;
3087
0
    }
3088
0
  }
3089
0
}
3090
3091
bool cmGlobalGenerator::CheckCMP0171() const
3092
0
{
3093
0
  return this->AllowGlobalTargetCodegen;
3094
0
}
3095
3096
void cmGlobalGenerator::AddGlobalTarget_EditCache(
3097
  std::vector<GlobalTargetInfo>& targets) const
3098
0
{
3099
0
  char const* editCacheTargetName = this->GetEditCacheTargetName();
3100
0
  if (!editCacheTargetName) {
3101
0
    return;
3102
0
  }
3103
0
  GlobalTargetInfo gti;
3104
0
  gti.Name = editCacheTargetName;
3105
0
  gti.PerConfig = cmTarget::PerConfig::No;
3106
0
  cmCustomCommandLine singleLine;
3107
3108
  // Use generator preference for the edit_cache rule if it is defined.
3109
0
  std::string edit_cmd = this->GetEditCacheCommand();
3110
0
  if (!edit_cmd.empty()) {
3111
0
    singleLine.push_back(std::move(edit_cmd));
3112
0
    if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
3113
0
      singleLine.push_back("--compile-no-warning-as-error");
3114
0
    }
3115
0
    if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
3116
0
      singleLine.push_back("--link-no-warning-as-error");
3117
0
    }
3118
0
    singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
3119
0
    singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
3120
0
    gti.Message = "Running CMake cache editor...";
3121
0
    gti.UsesTerminal = true;
3122
0
  } else {
3123
0
    singleLine.push_back(cmSystemTools::GetCMakeCommand());
3124
0
    singleLine.push_back("-E");
3125
0
    singleLine.push_back("echo");
3126
0
    singleLine.push_back("No interactive CMake dialog available.");
3127
0
    gti.Message = "No interactive CMake dialog available...";
3128
0
    gti.UsesTerminal = false;
3129
0
    gti.StdPipesUTF8 = true;
3130
0
  }
3131
0
  gti.CommandLines.push_back(std::move(singleLine));
3132
3133
0
  targets.push_back(std::move(gti));
3134
0
}
3135
3136
void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
3137
  std::vector<GlobalTargetInfo>& targets) const
3138
0
{
3139
0
  char const* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
3140
0
  if (!rebuildCacheTargetName) {
3141
0
    return;
3142
0
  }
3143
0
  GlobalTargetInfo gti;
3144
0
  gti.Name = rebuildCacheTargetName;
3145
0
  gti.Message = "Running CMake to regenerate build system...";
3146
0
  gti.UsesTerminal = true;
3147
0
  gti.PerConfig = cmTarget::PerConfig::No;
3148
0
  cmCustomCommandLine singleLine;
3149
0
  singleLine.push_back(cmSystemTools::GetCMakeCommand());
3150
0
  singleLine.push_back("--regenerate-during-build");
3151
0
  if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
3152
0
    singleLine.push_back("--compile-no-warning-as-error");
3153
0
  }
3154
0
  if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
3155
0
    singleLine.push_back("--link-no-warning-as-error");
3156
0
  }
3157
0
  singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
3158
0
  singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
3159
0
  gti.CommandLines.push_back(std::move(singleLine));
3160
0
  gti.StdPipesUTF8 = true;
3161
0
  targets.push_back(std::move(gti));
3162
0
}
3163
3164
void cmGlobalGenerator::AddGlobalTarget_Install(
3165
  std::vector<GlobalTargetInfo>& targets)
3166
0
{
3167
0
  auto& mf = this->Makefiles[0];
3168
0
  char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
3169
0
  bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
3170
0
  if (this->InstallTargetEnabled && skipInstallRules) {
3171
0
    this->CMakeInstance->IssueMessage(
3172
0
      MessageType::WARNING,
3173
0
      "CMAKE_SKIP_INSTALL_RULES was enabled even though "
3174
0
      "installation rules have been specified",
3175
0
      mf->GetBacktrace());
3176
0
  } else if (this->InstallTargetEnabled && !skipInstallRules) {
3177
0
    if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) {
3178
0
      std::set<std::string>* componentsSet = &this->InstallComponents;
3179
0
      std::ostringstream ostr;
3180
0
      if (!componentsSet->empty()) {
3181
0
        ostr << "Available install components are: "
3182
0
             << cmWrap('"', *componentsSet, '"', " ");
3183
0
      } else {
3184
0
        ostr << "Only default component available";
3185
0
      }
3186
0
      GlobalTargetInfo gti;
3187
0
      gti.Name = "list_install_components";
3188
0
      gti.Message = ostr.str();
3189
0
      gti.UsesTerminal = false;
3190
0
      targets.push_back(std::move(gti));
3191
0
    }
3192
0
    std::string cmd = cmSystemTools::GetCMakeCommand();
3193
0
    GlobalTargetInfo gti;
3194
0
    gti.Name = this->GetInstallTargetName();
3195
0
    gti.Message = "Install the project...";
3196
0
    gti.UsesTerminal = true;
3197
0
    gti.StdPipesUTF8 = true;
3198
0
    gti.Role = "install";
3199
0
    cmCustomCommandLine singleLine;
3200
0
    if (this->GetPreinstallTargetName()) {
3201
0
      gti.Depends.emplace_back(this->GetPreinstallTargetName());
3202
0
    } else {
3203
0
      cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
3204
0
      if (noall.IsOff()) {
3205
0
        gti.Depends.emplace_back(this->GetAllTargetName());
3206
0
      }
3207
0
    }
3208
0
    if (mf->GetDefinition("CMake_BINARY_DIR") &&
3209
0
        !mf->IsOn("CMAKE_CROSSCOMPILING")) {
3210
      // We are building CMake itself.  We cannot use the original
3211
      // executable to install over itself.  The generator will
3212
      // automatically convert this name to the build-time location.
3213
0
      cmd = "cmake";
3214
0
    }
3215
0
    singleLine.push_back(cmd);
3216
0
    if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
3217
0
      std::string cfgArg = "-DBUILD_TYPE=";
3218
0
      bool useEPN = this->UseEffectivePlatformName(mf.get());
3219
0
      if (useEPN) {
3220
0
        cfgArg += "$(CONFIGURATION)";
3221
0
        singleLine.push_back(cfgArg);
3222
0
        cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
3223
0
      } else {
3224
0
        cfgArg += this->GetCMakeCFGIntDir();
3225
0
      }
3226
0
      singleLine.push_back(cfgArg);
3227
0
    }
3228
0
    singleLine.push_back("-P");
3229
0
    singleLine.push_back("cmake_install.cmake");
3230
0
    gti.CommandLines.push_back(singleLine);
3231
0
    targets.push_back(gti);
3232
3233
    // install_local
3234
0
    if (char const* install_local = this->GetInstallLocalTargetName()) {
3235
0
      gti.Name = install_local;
3236
0
      gti.Message = "Installing only the local directory...";
3237
0
      gti.Role = "install";
3238
0
      gti.UsesTerminal =
3239
0
        !this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool(
3240
0
          "INSTALL_PARALLEL");
3241
0
      gti.CommandLines.clear();
3242
3243
0
      cmCustomCommandLine localCmdLine = singleLine;
3244
3245
0
      localCmdLine.insert(localCmdLine.begin() + 1,
3246
0
                          "-DCMAKE_INSTALL_LOCAL_ONLY=1");
3247
3248
0
      gti.CommandLines.push_back(std::move(localCmdLine));
3249
0
      targets.push_back(gti);
3250
0
    }
3251
3252
    // install_strip
3253
0
    char const* install_strip = this->GetInstallStripTargetName();
3254
0
    if (install_strip && mf->IsSet("CMAKE_STRIP")) {
3255
0
      gti.Name = install_strip;
3256
0
      gti.Message = "Installing the project stripped...";
3257
0
      gti.UsesTerminal = true;
3258
0
      gti.Role = "install";
3259
0
      gti.CommandLines.clear();
3260
3261
0
      cmCustomCommandLine stripCmdLine = singleLine;
3262
3263
0
      stripCmdLine.insert(stripCmdLine.begin() + 1,
3264
0
                          "-DCMAKE_INSTALL_DO_STRIP=1");
3265
0
      gti.CommandLines.push_back(std::move(stripCmdLine));
3266
0
      targets.push_back(gti);
3267
0
    }
3268
0
  }
3269
0
}
3270
3271
class ModuleCompilationDatabaseCommandAction
3272
{
3273
public:
3274
  ModuleCompilationDatabaseCommandAction(
3275
    std::string output, std::function<std::vector<std::string>()> inputs)
3276
0
    : Output(std::move(output))
3277
0
    , Inputs(std::move(inputs))
3278
0
  {
3279
0
  }
3280
  void operator()(cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3281
                  std::unique_ptr<cmCustomCommand> cc);
3282
3283
private:
3284
  std::string const Output;
3285
  std::function<std::vector<std::string>()> const Inputs;
3286
};
3287
3288
void ModuleCompilationDatabaseCommandAction::operator()(
3289
  cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3290
  std::unique_ptr<cmCustomCommand> cc)
3291
0
{
3292
0
  auto inputs = this->Inputs();
3293
3294
0
  cmCustomCommandLines command_lines;
3295
0
  cmCustomCommandLine command_line;
3296
0
  {
3297
0
    command_line.emplace_back(cmSystemTools::GetCMakeCommand());
3298
0
    command_line.emplace_back("-E");
3299
0
    command_line.emplace_back("cmake_module_compile_db");
3300
0
    command_line.emplace_back("merge");
3301
0
    command_line.emplace_back("-o");
3302
0
    command_line.emplace_back(this->Output);
3303
0
    for (auto const& input : inputs) {
3304
0
      command_line.emplace_back(input);
3305
0
    }
3306
0
  }
3307
0
  command_lines.emplace_back(std::move(command_line));
3308
3309
0
  cc->SetBacktrace(lfbt);
3310
0
  cc->SetCommandLines(command_lines);
3311
0
  cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
3312
0
  cc->SetDependsExplicitOnly(true);
3313
0
  cc->SetOutputs(this->Output);
3314
0
  if (!inputs.empty()) {
3315
0
    cc->SetMainDependency(inputs[0]);
3316
0
  }
3317
0
  cc->SetDepends(inputs);
3318
0
  detail::AddCustomCommandToOutput(lg, cmCommandOrigin::Generator,
3319
0
                                   std::move(cc), false);
3320
0
}
3321
3322
class ModuleCompilationDatabaseTargetAction
3323
{
3324
public:
3325
  ModuleCompilationDatabaseTargetAction(std::string output, cmTarget* target)
3326
0
    : Output(std::move(output))
3327
0
    , Target(target)
3328
0
  {
3329
0
  }
3330
  void operator()(cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3331
                  std::unique_ptr<cmCustomCommand> cc);
3332
3333
private:
3334
  std::string const Output;
3335
  cmTarget* const Target;
3336
};
3337
3338
void ModuleCompilationDatabaseTargetAction::operator()(
3339
  cmLocalGenerator& lg, cmListFileBacktrace const& lfbt,
3340
  std::unique_ptr<cmCustomCommand> cc)
3341
0
{
3342
0
  cc->SetBacktrace(lfbt);
3343
0
  cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
3344
0
  std::vector<std::string> target_inputs;
3345
0
  target_inputs.emplace_back(this->Output);
3346
0
  cc->SetDepends(target_inputs);
3347
0
  detail::AddUtilityCommand(lg, cmCommandOrigin::Generator, this->Target,
3348
0
                            std::move(cc));
3349
0
}
3350
3351
void cmGlobalGenerator::AddBuildDatabaseFile(std::string const& lang,
3352
                                             std::string const& config,
3353
                                             std::string const& path)
3354
0
{
3355
0
  if (!config.empty()) {
3356
0
    this->PerConfigModuleDbs[config][lang].push_back(path);
3357
0
  }
3358
0
  this->PerLanguageModuleDbs[lang].push_back(path);
3359
0
}
3360
3361
bool cmGlobalGenerator::AddBuildDatabaseTargets()
3362
0
{
3363
0
  auto& mf = this->Makefiles[0];
3364
0
  if (!mf->IsOn("CMAKE_EXPORT_BUILD_DATABASE")) {
3365
0
    return true;
3366
0
  }
3367
0
  if (!cmExperimental::HasSupportEnabled(
3368
0
        *mf.get(), cmExperimental::Feature::ExportBuildDatabase)) {
3369
0
    return {};
3370
0
  }
3371
3372
0
  static auto const reservedTargets = { "cmake_build_database" };
3373
0
  for (auto const& target : reservedTargets) {
3374
0
    if (!this->CheckReservedTargetName(
3375
0
          target, "when exporting build databases are enabled")) {
3376
0
      return false;
3377
0
    }
3378
0
  }
3379
0
  static auto const reservedPrefixes = { "cmake_build_database-" };
3380
0
  for (auto const& prefix : reservedPrefixes) {
3381
0
    if (!this->CheckReservedTargetNamePrefix(
3382
0
          prefix, "when exporting build databases are enabled")) {
3383
0
      return false;
3384
0
    }
3385
0
  }
3386
3387
0
  if (!this->SupportsBuildDatabase()) {
3388
0
    return true;
3389
0
  }
3390
3391
0
  auto configs = mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
3392
3393
0
  static cm::static_string_view TargetPrefix = "cmake_build_database"_s;
3394
0
  auto AddMergeTarget =
3395
0
    [&mf](std::string const& name, char const* comment,
3396
0
          std::string const& output,
3397
0
          std::function<std::vector<std::string>()> inputs) {
3398
      // Add the custom command.
3399
0
      {
3400
0
        ModuleCompilationDatabaseCommandAction action{ output,
3401
0
                                                       std::move(inputs) };
3402
0
        auto cc = cm::make_unique<cmCustomCommand>();
3403
0
        cc->SetComment(comment);
3404
0
        mf->AddGeneratorAction(
3405
0
          std::move(cc), action,
3406
0
          cmMakefile::GeneratorActionWhen::AfterGeneratorTargets);
3407
0
      }
3408
3409
      // Add a custom target with the given name.
3410
0
      {
3411
0
        cmTarget* target = mf->AddNewUtilityTarget(name, true);
3412
0
        ModuleCompilationDatabaseTargetAction action{ output, target };
3413
0
        auto cc = cm::make_unique<cmCustomCommand>();
3414
0
        mf->AddGeneratorAction(std::move(cc), action);
3415
0
      }
3416
0
    };
3417
3418
0
  std::string module_languages[] = { "CXX" };
3419
3420
  // Add per-configuration targets.
3421
0
  for (auto const& config : configs) {
3422
    // Add per-language targets.
3423
0
    std::vector<std::string> all_config_paths;
3424
0
    for (auto const& lang : module_languages) {
3425
0
      auto comment = cmStrCat("Combining module command databases for ", lang,
3426
0
                              " and ", config);
3427
0
      auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3428
0
                             lang, '_', config, ".json");
3429
0
      mf->GetOrCreateGeneratedSource(output);
3430
0
      AddMergeTarget(cmStrCat(TargetPrefix, '-', lang, '-', config),
3431
0
                     comment.c_str(), output, [this, config, lang]() {
3432
0
                       return this->PerConfigModuleDbs[config][lang];
3433
0
                     });
3434
0
      all_config_paths.emplace_back(std::move(output));
3435
0
    }
3436
3437
    // Add the overall target.
3438
0
    auto comment = cmStrCat("Combining module command databases for ", config);
3439
0
    auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3440
0
                           config, ".json");
3441
0
    mf->GetOrCreateGeneratedSource(output);
3442
0
    AddMergeTarget(cmStrCat(TargetPrefix, '-', config), comment.c_str(),
3443
0
                   output, [all_config_paths]() { return all_config_paths; });
3444
0
  }
3445
3446
  // NMC considerations
3447
  // Add per-language targets.
3448
0
  std::vector<std::string> all_config_paths;
3449
0
  for (auto const& lang : module_languages) {
3450
0
    auto comment = cmStrCat("Combining module command databases for ", lang);
3451
0
    auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
3452
0
                           lang, ".json");
3453
0
    mf->GetOrCreateGeneratedSource(output);
3454
0
    AddMergeTarget(
3455
0
      cmStrCat(TargetPrefix, '-', lang), comment.c_str(), output,
3456
0
      [this, lang]() { return this->PerLanguageModuleDbs[lang]; });
3457
0
    all_config_paths.emplace_back(std::move(output));
3458
0
  }
3459
3460
  // Add the overall target.
3461
0
  auto const* comment = "Combining all module command databases";
3462
0
  auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database.json");
3463
0
  mf->GetOrCreateGeneratedSource(output);
3464
0
  AddMergeTarget(std::string(TargetPrefix), comment, output,
3465
0
                 [all_config_paths]() { return all_config_paths; });
3466
3467
0
  return true;
3468
0
}
3469
3470
std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
3471
0
{
3472
0
  cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
3473
0
    "PREDEFINED_TARGETS_FOLDER");
3474
3475
0
  if (prop) {
3476
0
    return *prop;
3477
0
  }
3478
3479
0
  return "CMakePredefinedTargets";
3480
0
}
3481
3482
bool cmGlobalGenerator::UseFolderProperty() const
3483
0
{
3484
0
  cmValue const prop =
3485
0
    this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
3486
3487
  // If this property is defined, let the setter turn this on or off.
3488
0
  if (prop) {
3489
0
    return prop.IsOn();
3490
0
  }
3491
3492
  // If CMP0143 is NEW `treat` "USE_FOLDERS" as ON. Otherwise `treat` it as OFF
3493
0
  assert(!this->Makefiles.empty());
3494
0
  return (this->Makefiles[0]->GetPolicyStatus(cmPolicies::CMP0143) ==
3495
0
          cmPolicies::NEW);
3496
0
}
3497
3498
void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
3499
                                           cmMakefile* mf)
3500
0
{
3501
  // Package
3502
0
  auto tb =
3503
0
    mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig);
3504
3505
  // Do nothing if gti.Name is already used
3506
0
  if (!tb.second) {
3507
0
    return;
3508
0
  }
3509
3510
0
  cmTarget& target = tb.first;
3511
0
  target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
3512
3513
  // Store the custom command in the target.
3514
0
  cmCustomCommand cc;
3515
0
  cc.SetCommandLines(gti.CommandLines);
3516
0
  cc.SetWorkingDirectory(gti.WorkingDir.c_str());
3517
0
  cc.SetStdPipesUTF8(gti.StdPipesUTF8);
3518
0
  cc.SetUsesTerminal(gti.UsesTerminal);
3519
0
  cc.SetRole(gti.Role);
3520
0
  target.AddPostBuildCommand(std::move(cc));
3521
0
  if (!gti.Message.empty()) {
3522
0
    target.SetProperty("EchoString", gti.Message);
3523
0
  }
3524
0
  for (std::string const& d : gti.Depends) {
3525
0
    target.AddUtility(d, false);
3526
0
  }
3527
3528
  // Organize in the "predefined targets" folder:
3529
  //
3530
0
  if (this->UseFolderProperty()) {
3531
0
    target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
3532
0
  }
3533
0
}
3534
3535
std::string cmGlobalGenerator::GenerateRuleFile(
3536
  std::string const& output) const
3537
0
{
3538
0
  std::string ruleFile = cmStrCat(output, ".rule");
3539
0
  char const* dir = this->GetCMakeCFGIntDir();
3540
0
  if (dir && dir[0] == '$') {
3541
0
    cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles");
3542
0
  }
3543
0
  return ruleFile;
3544
0
}
3545
3546
bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
3547
0
{
3548
0
  return mf->PlatformIsAppleEmbedded();
3549
0
}
3550
3551
void cmGlobalGenerator::AppendDirectoryForConfig(std::string const& /*unused*/,
3552
                                                 std::string const& /*unused*/,
3553
                                                 std::string const& /*unused*/,
3554
                                                 std::string& /*unused*/)
3555
0
{
3556
  // Subclasses that support multiple configurations should implement
3557
  // this method to append the subdirectory for the given build
3558
  // configuration.
3559
0
}
3560
3561
cmValue cmGlobalGenerator::GetDebuggerWorkingDirectory(
3562
  cmGeneratorTarget* gt) const
3563
0
{
3564
0
  return gt->GetProperty("DEBUGGER_WORKING_DIRECTORY");
3565
0
}
3566
3567
cmGlobalGenerator::TargetDependSet const&
3568
cmGlobalGenerator::GetTargetDirectDepends(
3569
  cmGeneratorTarget const* target) const
3570
0
{
3571
0
  auto i = this->TargetDependencies.find(target);
3572
0
  assert(i != this->TargetDependencies.end());
3573
0
  return i->second;
3574
0
}
3575
3576
bool cmGlobalGenerator::TargetOrderIndexLess(cmGeneratorTarget const* l,
3577
                                             cmGeneratorTarget const* r) const
3578
0
{
3579
0
  return this->TargetOrderIndex.at(l) < this->TargetOrderIndex.at(r);
3580
0
}
3581
3582
bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
3583
0
{
3584
  // The following is a list of targets reserved
3585
  // by one or more of the cmake generators.
3586
3587
  // Adding additional targets to this list will require a policy!
3588
0
  static cm::static_string_view const reservedTargets[] = {
3589
0
    "all"_s,           "ALL_BUILD"_s,  "help"_s,  "install"_s,
3590
0
    "INSTALL"_s,       "preinstall"_s, "clean"_s, "edit_cache"_s,
3591
0
    "rebuild_cache"_s, "ZERO_CHECK"_s
3592
0
  };
3593
3594
0
  return cm::contains(reservedTargets, name);
3595
0
}
3596
3597
void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
3598
  std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
3599
0
{
3600
0
  this->ExtraGenerator = std::move(extraGenerator);
3601
0
  if (this->ExtraGenerator) {
3602
0
    this->ExtraGenerator->SetGlobalGenerator(this);
3603
0
  }
3604
0
}
3605
3606
std::string cmGlobalGenerator::GetExtraGeneratorName() const
3607
0
{
3608
0
  return this->ExtraGenerator ? this->ExtraGenerator->GetName()
3609
0
                              : std::string();
3610
0
}
3611
3612
void cmGlobalGenerator::FileReplacedDuringGenerate(std::string const& filename)
3613
0
{
3614
0
  this->FilesReplacedDuringGenerate.push_back(filename);
3615
0
}
3616
3617
void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
3618
  std::vector<std::string>& filenames)
3619
0
{
3620
0
  filenames.clear();
3621
0
  std::copy(this->FilesReplacedDuringGenerate.begin(),
3622
0
            this->FilesReplacedDuringGenerate.end(),
3623
0
            std::back_inserter(filenames));
3624
0
}
3625
3626
cmGlobalGenerator::TargetDependSet cmGlobalGenerator::GetTargetsForProject(
3627
  cmLocalGenerator const* root,
3628
  std::vector<cmLocalGenerator*> const& generators) const
3629
0
{
3630
0
  TargetDependSet projectTargets;
3631
  // loop over all local generators
3632
0
  for (auto* generator : generators) {
3633
    // check to make sure generator is not excluded
3634
0
    if (this->IsExcluded(root, generator)) {
3635
0
      continue;
3636
0
    }
3637
    // loop over all the generator targets in the makefile
3638
0
    for (auto const& target : generator->GetGeneratorTargets()) {
3639
0
      if (this->IsRootOnlyTarget(target.get()) &&
3640
0
          target->GetLocalGenerator() != root) {
3641
0
        continue;
3642
0
      }
3643
      // Get the set of targets that depend on target
3644
0
      this->AddTargetDepends(target.get(), projectTargets);
3645
0
    }
3646
0
  }
3647
0
  return projectTargets;
3648
0
}
3649
3650
bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
3651
0
{
3652
0
  return (target->GetType() == cmStateEnums::GLOBAL_TARGET ||
3653
0
          target->GetName() == this->GetAllTargetName());
3654
0
}
3655
3656
void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
3657
                                         TargetDependSet& projectTargets) const
3658
0
{
3659
  // add the target itself
3660
0
  if (projectTargets.insert(target).second) {
3661
    // This is the first time we have encountered the target.
3662
    // Recursively follow its dependencies.
3663
0
    for (auto const& t : this->GetTargetDirectDepends(target)) {
3664
0
      this->AddTargetDepends(t, projectTargets);
3665
0
    }
3666
0
  }
3667
0
}
3668
3669
void cmGlobalGenerator::AddToManifest(std::string const& f)
3670
0
{
3671
  // Add to the content listing for the file's directory.
3672
0
  std::string dir = cmSystemTools::GetFilenamePath(f);
3673
0
  std::string file = cmSystemTools::GetFilenameName(f);
3674
0
  DirectoryContent& dc = this->DirectoryContentMap[dir];
3675
0
  dc.Generated.insert(file);
3676
0
  dc.All.insert(file);
3677
0
}
3678
3679
std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
3680
  std::string const& dir, bool needDisk)
3681
0
{
3682
0
  DirectoryContent& dc = this->DirectoryContentMap[dir];
3683
0
  if (needDisk) {
3684
0
    long mt = cmSystemTools::ModifiedTime(dir);
3685
0
    if (mt != dc.LastDiskTime) {
3686
      // Reset to non-loaded directory content.
3687
0
      dc.All = dc.Generated;
3688
3689
      // Load the directory content from disk.
3690
0
      cmsys::Directory d;
3691
0
      if (d.Load(dir)) {
3692
0
        unsigned long n = d.GetNumberOfFiles();
3693
0
        for (unsigned long i = 0; i < n; ++i) {
3694
0
          char const* f = d.GetFile(i);
3695
0
          if (strcmp(f, ".") != 0 && strcmp(f, "..") != 0) {
3696
0
            dc.All.insert(f);
3697
0
          }
3698
0
        }
3699
0
      }
3700
0
      dc.LastDiskTime = mt;
3701
0
    }
3702
0
  }
3703
0
  return dc.All;
3704
0
}
3705
3706
void cmGlobalGenerator::AddRuleHash(std::vector<std::string> const& outputs,
3707
                                    std::string const& content)
3708
0
{
3709
  // Ignore if there are no outputs.
3710
0
  if (outputs.empty()) {
3711
0
    return;
3712
0
  }
3713
3714
  // Compute a hash of the rule.
3715
0
  RuleHash hash;
3716
0
  {
3717
0
    cmCryptoHash md5(cmCryptoHash::AlgoMD5);
3718
0
    std::string const md5_hex = md5.HashString(content);
3719
0
    memcpy(hash.Data, md5_hex.c_str(), 32);
3720
0
  }
3721
3722
  // Shorten the output name (in expected use case).
3723
0
  std::string fname =
3724
0
    this->LocalGenerators[0]->MaybeRelativeToTopBinDir(outputs[0]);
3725
3726
  // Associate the hash with this output.
3727
0
  this->RuleHashes[fname] = hash;
3728
0
}
3729
3730
void cmGlobalGenerator::CheckRuleHashes()
3731
0
{
3732
0
  std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
3733
0
  std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt");
3734
0
  this->CheckRuleHashes(pfile, home);
3735
0
  this->WriteRuleHashes(pfile);
3736
0
}
3737
3738
void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
3739
                                        std::string const& home)
3740
0
{
3741
#if defined(_WIN32) || defined(__CYGWIN__)
3742
  cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
3743
#else
3744
0
  cmsys::ifstream fin(pfile.c_str());
3745
0
#endif
3746
0
  if (!fin) {
3747
0
    return;
3748
0
  }
3749
0
  std::string line;
3750
0
  std::string fname;
3751
0
  while (cmSystemTools::GetLineFromStream(fin, line)) {
3752
    // Line format is a 32-byte hex string followed by a space
3753
    // followed by a file name (with no escaping).
3754
3755
    // Skip blank and comment lines.
3756
0
    if (line.size() < 34 || line[0] == '#') {
3757
0
      continue;
3758
0
    }
3759
3760
    // Get the filename.
3761
0
    fname = line.substr(33);
3762
3763
    // Look for a hash for this file's rule.
3764
0
    auto const rhi = this->RuleHashes.find(fname);
3765
0
    if (rhi != this->RuleHashes.end()) {
3766
      // Compare the rule hash in the file to that we were given.
3767
0
      if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
3768
        // The rule has changed.  Delete the output so it will be
3769
        // built again.
3770
0
        fname = cmSystemTools::CollapseFullPath(fname, home);
3771
0
        cmSystemTools::RemoveFile(fname);
3772
0
      }
3773
0
    } else {
3774
      // We have no hash for a rule previously listed.  This may be a
3775
      // case where a user has turned off a build option and might
3776
      // want to turn it back on later, so do not delete the file.
3777
      // Instead, we keep the rule hash as long as the file exists so
3778
      // that if the feature is turned back on and the rule has
3779
      // changed the file is still rebuilt.
3780
0
      std::string fpath = cmSystemTools::CollapseFullPath(fname, home);
3781
0
      if (cmSystemTools::FileExists(fpath)) {
3782
0
        RuleHash hash;
3783
0
        memcpy(hash.Data, line.c_str(), 32);
3784
0
        this->RuleHashes[fname] = hash;
3785
0
      }
3786
0
    }
3787
0
  }
3788
0
}
3789
3790
void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
3791
0
{
3792
  // Now generate a new persistence file with the current hashes.
3793
0
  if (this->RuleHashes.empty()) {
3794
0
    cmSystemTools::RemoveFile(pfile);
3795
0
  } else {
3796
0
    cmGeneratedFileStream fout(pfile);
3797
0
    fout << "# Hashes of file build rules.\n";
3798
0
    for (auto const& rh : this->RuleHashes) {
3799
0
      fout.write(rh.second.Data, 32);
3800
0
      fout << ' ' << rh.first << '\n';
3801
0
    }
3802
0
  }
3803
0
}
3804
3805
void cmGlobalGenerator::WriteSummary()
3806
0
{
3807
  // Record all target directories in a central location.
3808
0
  std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3809
0
                               "/CMakeFiles/TargetDirectories.txt");
3810
0
  cmGeneratedFileStream fout(fname);
3811
3812
0
  for (auto const& lg : this->LocalGenerators) {
3813
0
    for (auto const& tgt : lg->GetGeneratorTargets()) {
3814
0
      if (!tgt->IsInBuildSystem()) {
3815
0
        continue;
3816
0
      }
3817
0
      this->WriteSummary(tgt.get());
3818
0
      fout << tgt->GetCMFSupportDirectory() << '\n';
3819
0
    }
3820
0
  }
3821
0
}
3822
3823
void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
3824
0
{
3825
  // Place the labels file in a per-target support directory.
3826
0
  std::string dir = target->GetCMFSupportDirectory();
3827
0
  std::string file = cmStrCat(dir, "/Labels.txt");
3828
0
  std::string json_file = cmStrCat(dir, "/Labels.json");
3829
3830
0
#ifndef CMAKE_BOOTSTRAP
3831
  // Check whether labels are enabled for this target.
3832
0
  cmValue targetLabels = target->GetProperty("LABELS");
3833
0
  cmValue directoryLabels =
3834
0
    target->Target->GetMakefile()->GetProperty("LABELS");
3835
0
  cmValue cmakeDirectoryLabels =
3836
0
    target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
3837
0
  if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
3838
0
    Json::Value lj_root(Json::objectValue);
3839
0
    Json::Value& lj_target = lj_root["target"] = Json::objectValue;
3840
0
    lj_target["name"] = target->GetName();
3841
0
    Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
3842
0
    Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
3843
3844
0
    cmSystemTools::MakeDirectory(dir);
3845
0
    cmGeneratedFileStream fout(file);
3846
3847
0
    cmList labels;
3848
3849
    // List the target-wide labels.  All sources in the target get
3850
    // these labels.
3851
0
    if (targetLabels) {
3852
0
      labels.assign(*targetLabels);
3853
0
      if (!labels.empty()) {
3854
0
        fout << "# Target labels\n";
3855
0
        for (std::string const& l : labels) {
3856
0
          fout << ' ' << l << '\n';
3857
0
          lj_target_labels.append(l);
3858
0
        }
3859
0
      }
3860
0
    }
3861
3862
    // List directory labels
3863
0
    cmList directoryLabelsList;
3864
0
    cmList cmakeDirectoryLabelsList;
3865
3866
0
    if (directoryLabels) {
3867
0
      directoryLabelsList.assign(*directoryLabels);
3868
0
    }
3869
3870
0
    if (cmakeDirectoryLabels) {
3871
0
      cmakeDirectoryLabelsList.assign(*cmakeDirectoryLabels);
3872
0
    }
3873
3874
0
    if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
3875
0
      fout << "# Directory labels\n";
3876
0
    }
3877
3878
0
    for (auto const& li : directoryLabelsList) {
3879
0
      fout << ' ' << li << '\n';
3880
0
      lj_target_labels.append(li);
3881
0
    }
3882
3883
0
    for (auto const& li : cmakeDirectoryLabelsList) {
3884
0
      fout << ' ' << li << '\n';
3885
0
      lj_target_labels.append(li);
3886
0
    }
3887
3888
    // List the source files with any per-source labels.
3889
0
    fout << "# Source files and their labels\n";
3890
0
    std::vector<cmSourceFile*> sources;
3891
0
    std::vector<std::string> const& configs =
3892
0
      target->Target->GetMakefile()->GetGeneratorConfigs(
3893
0
        cmMakefile::IncludeEmptyConfig);
3894
0
    for (std::string const& c : configs) {
3895
0
      target->GetSourceFiles(sources, c);
3896
0
    }
3897
0
    auto const sourcesEnd = cmRemoveDuplicates(sources);
3898
0
    for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
3899
0
      Json::Value& lj_source = lj_sources.append(Json::objectValue);
3900
0
      std::string const& sfp = sf->ResolveFullPath();
3901
0
      fout << sfp << '\n';
3902
0
      lj_source["file"] = sfp;
3903
0
      if (cmValue svalue = sf->GetProperty("LABELS")) {
3904
0
        Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
3905
0
        labels.assign(*svalue);
3906
0
        for (auto const& label : labels) {
3907
0
          fout << ' ' << label << '\n';
3908
0
          lj_source_labels.append(label);
3909
0
        }
3910
0
      }
3911
0
    }
3912
0
    cmGeneratedFileStream json_fout(json_file);
3913
0
    json_fout << lj_root;
3914
0
  } else
3915
0
#endif
3916
0
  {
3917
0
    cmSystemTools::RemoveFile(file);
3918
0
    cmSystemTools::RemoveFile(json_file);
3919
0
  }
3920
0
}
3921
3922
// static
3923
std::string cmGlobalGenerator::EscapeJSON(std::string const& s)
3924
0
{
3925
0
  std::string result;
3926
0
  result.reserve(s.size());
3927
0
  for (char i : s) {
3928
0
    switch (i) {
3929
0
      case '"':
3930
0
      case '\\':
3931
0
        result += '\\';
3932
0
        result += i;
3933
0
        break;
3934
0
      case '\n':
3935
0
        result += "\\n";
3936
0
        break;
3937
0
      case '\t':
3938
0
        result += "\\t";
3939
0
        break;
3940
0
      default:
3941
0
        result += i;
3942
0
    }
3943
0
  }
3944
0
  return result;
3945
0
}
3946
3947
void cmGlobalGenerator::SetFilenameTargetDepends(
3948
  cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
3949
0
{
3950
0
  this->FilenameTargetDepends[sf] = tgts;
3951
0
}
3952
3953
std::set<cmGeneratorTarget const*> const&
3954
cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
3955
0
{
3956
0
  return this->FilenameTargetDepends[sf];
3957
0
}
3958
3959
std::string const& cmGlobalGenerator::GetRealPath(std::string const& dir)
3960
0
{
3961
0
  auto i = this->RealPaths.lower_bound(dir);
3962
0
  if (i == this->RealPaths.end() ||
3963
0
      this->RealPaths.key_comp()(dir, i->first)) {
3964
0
    i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
3965
0
  }
3966
0
  return i->second;
3967
0
}
3968
3969
std::string cmGlobalGenerator::NewDeferId()
3970
0
{
3971
0
  return cmStrCat("__", this->NextDeferId++);
3972
0
}
3973
3974
void cmGlobalGenerator::ProcessEvaluationFiles()
3975
0
{
3976
0
  std::vector<std::string> generatedFiles;
3977
0
  for (auto& localGen : this->LocalGenerators) {
3978
0
    localGen->ProcessEvaluationFiles(generatedFiles);
3979
0
  }
3980
0
}
3981
3982
std::string cmGlobalGenerator::ExpandCFGIntDir(
3983
  std::string const& str, std::string const& /*config*/) const
3984
0
{
3985
0
  return str;
3986
0
}
3987
3988
bool cmGlobalGenerator::GenerateCPackPropertiesFile()
3989
0
{
3990
0
  cmake::InstalledFilesMap const& installedFiles =
3991
0
    this->CMakeInstance->GetInstalledFiles();
3992
3993
0
  auto const& lg = this->LocalGenerators[0];
3994
0
  cmMakefile* mf = lg->GetMakefile();
3995
3996
0
  std::vector<std::string> configs =
3997
0
    mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
3998
0
  std::string config = mf->GetDefaultConfiguration();
3999
4000
0
  std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
4001
0
                              "/CPackProperties.cmake");
4002
4003
0
  if (!cmSystemTools::FileExists(path) && installedFiles.empty()) {
4004
0
    return true;
4005
0
  }
4006
4007
0
  cmGeneratedFileStream file(path);
4008
0
  file << "# CPack properties\n";
4009
4010
0
  for (auto const& i : installedFiles) {
4011
0
    cmInstalledFile const& installedFile = i.second;
4012
4013
0
    cmCPackPropertiesGenerator cpackPropertiesGenerator(
4014
0
      lg.get(), installedFile, configs);
4015
4016
0
    cpackPropertiesGenerator.Generate(file, config, configs);
4017
0
  }
4018
4019
0
  return true;
4020
0
}
4021
4022
cmInstallRuntimeDependencySet*
4023
cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
4024
0
{
4025
0
  auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
4026
0
  auto* retval = set.get();
4027
0
  this->RuntimeDependencySets.push_back(std::move(set));
4028
0
  return retval;
4029
0
}
4030
4031
cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
4032
  std::string const& name)
4033
0
{
4034
0
  auto it = this->RuntimeDependencySetsByName.find(name);
4035
0
  if (it == this->RuntimeDependencySetsByName.end()) {
4036
0
    auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
4037
0
    it =
4038
0
      this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
4039
0
        .first;
4040
0
    this->RuntimeDependencySets.push_back(std::move(set));
4041
0
  }
4042
0
  return it->second;
4043
0
}
4044
4045
cmGlobalGenerator::StripCommandStyle cmGlobalGenerator::GetStripCommandStyle(
4046
  std::string const& strip)
4047
0
{
4048
#ifdef __APPLE__
4049
  auto i = this->StripCommandStyleMap.find(strip);
4050
  if (i == this->StripCommandStyleMap.end()) {
4051
    StripCommandStyle style = StripCommandStyle::Default;
4052
4053
    // Try running strip tool with Apple-specific options.
4054
    std::vector<std::string> cmd{ strip, "-u", "-r" };
4055
    std::string out;
4056
    std::string err;
4057
    int ret;
4058
    if (cmSystemTools::RunSingleCommand(cmd, &out, &err, &ret, nullptr,
4059
                                        cmSystemTools::OUTPUT_NONE) &&
4060
        // Check for Apple-specific output.
4061
        ret != 0 && cmHasLiteralPrefix(err, "fatal error: /") &&
4062
        err.find("/usr/bin/strip: no files specified") != std::string::npos) {
4063
      style = StripCommandStyle::Apple;
4064
    }
4065
    i = this->StripCommandStyleMap.emplace(strip, style).first;
4066
  }
4067
  return i->second;
4068
#else
4069
0
  static_cast<void>(strip);
4070
0
  return StripCommandStyle::Default;
4071
0
#endif
4072
0
}
4073
4074
std::string cmGlobalGenerator::GetEncodedLiteral(std::string const& lit)
4075
0
{
4076
0
  std::string result = lit;
4077
0
  return this->EncodeLiteral(result);
4078
0
}
4079
4080
void cmGlobalGenerator::AddInstallScript(std::string const& file)
4081
0
{
4082
0
  this->InstallScripts.push_back(file);
4083
0
}
4084
4085
void cmGlobalGenerator::AddTestFile(std::string const& file)
4086
0
{
4087
0
  this->TestFiles.push_back(file);
4088
0
}
4089
4090
void cmGlobalGenerator::AddCMakeFilesToRebuild(
4091
  std::vector<std::string>& files) const
4092
0
{
4093
0
  files.insert(files.end(), this->InstallScripts.begin(),
4094
0
               this->InstallScripts.end());
4095
0
  files.insert(files.end(), this->TestFiles.begin(), this->TestFiles.end());
4096
0
}
4097
4098
bool cmGlobalGenerator::ShouldWarnExperimental(cm::string_view featureName,
4099
                                               cm::string_view featureUuid)
4100
0
{
4101
0
  return this->WarnedExperimental
4102
0
    .emplace(cmStrCat(featureName, '-', featureUuid))
4103
0
    .second;
4104
0
}
4105
4106
cm::optional<cmXcFrameworkPlist> cmGlobalGenerator::GetXcFrameworkPListContent(
4107
  std::string const& path) const
4108
0
{
4109
0
  cm::optional<cmXcFrameworkPlist> result;
4110
0
  auto i = this->XcFrameworkPListContentMap.find(path);
4111
0
  if (i != this->XcFrameworkPListContentMap.end()) {
4112
0
    result = i->second;
4113
0
  }
4114
0
  return result;
4115
0
}
4116
4117
void cmGlobalGenerator::SetXcFrameworkPListContent(
4118
  std::string const& path, cmXcFrameworkPlist const& content)
4119
0
{
4120
0
  this->XcFrameworkPListContentMap.emplace(path, content);
4121
0
}