Coverage Report

Created: 2026-06-15 07:03

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