Coverage Report

Created: 2026-09-14 06:43

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