Coverage Report

Created: 2026-04-29 07:01

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