Coverage Report

Created: 2026-07-14 07:09

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