Coverage Report

Created: 2026-10-28 06:38

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