Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmLocalGenerator.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 "cmLocalGenerator.h"
4
5
#include <algorithm>
6
#include <array>
7
#include <cassert>
8
#include <cstdio>
9
#include <cstdlib>
10
#include <initializer_list>
11
#include <iterator>
12
#include <sstream>
13
#include <unordered_set>
14
#include <utility>
15
#include <vector>
16
17
#include <cm/memory>
18
#include <cm/optional>
19
#include <cm/string_view>
20
#include <cmext/algorithm>
21
#include <cmext/string_view>
22
23
#include "cmsys/RegularExpression.hxx"
24
#include "cmsys/String.h"
25
26
#include "cmAlgorithms.h"
27
#include "cmCMakePath.h"
28
#include "cmComputeLinkInformation.h"
29
#include "cmCryptoHash.h"
30
#include "cmCustomCommand.h"
31
#include "cmCustomCommandGenerator.h"
32
#include "cmCustomCommandLines.h"
33
#include "cmCustomCommandTypes.h"
34
#include "cmFileSetMetadata.h"
35
#include "cmGeneratedFileStream.h"
36
#include "cmGeneratorExpression.h"
37
#include "cmGeneratorExpressionEvaluationFile.h"
38
#include "cmGeneratorFileSet.h"
39
#include "cmGeneratorRule.h"
40
#include "cmGeneratorTarget.h"
41
#include "cmGlobalGenerator.h"
42
#include "cmInstallGenerator.h"
43
#include "cmInstallScriptGenerator.h"
44
#include "cmInstallTargetGenerator.h"
45
#include "cmLinkLineComputer.h"
46
#include "cmLinkLineDeviceComputer.h"
47
#include "cmList.h"
48
#include "cmMakefile.h"
49
#include "cmMessageType.h"
50
#include "cmObjectLocation.h"
51
#include "cmRange.h"
52
#include "cmRulePlaceholderExpander.h"
53
#include "cmScriptGenerator.h"
54
#include "cmSourceFile.h"
55
#include "cmSourceFileLocation.h"
56
#include "cmSourceFileLocationKind.h"
57
#include "cmSourceGroup.h"
58
#include "cmStandardLevelResolver.h"
59
#include "cmState.h"
60
#include "cmStateDirectory.h"
61
#include "cmStateTypes.h"
62
#include "cmStringAlgorithms.h"
63
#include "cmSystemTools.h"
64
#include "cmTarget.h"
65
#include "cmTargetTypes.h"
66
#include "cmTestGenerator.h"
67
#include "cmValue.h"
68
#include "cmake.h"
69
70
#if defined(__HAIKU__)
71
#  include <FindDirectory.h>
72
#  include <StorageDefs.h>
73
#endif
74
75
namespace {
76
// List of variables that are replaced when
77
// rules are expanded.  These variables are
78
// replaced in the form <var> with GetSafeDefinition(var).
79
// ${LANG} is replaced in the variable first with all enabled
80
// languages.
81
auto ruleReplaceVars = {
82
  "CMAKE_${LANG}_COMPILER",
83
  "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
84
  "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
85
  "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
86
  "CMAKE_${LANG}_ARCHIVE",
87
  "CMAKE_AR",
88
  "CMAKE_SOURCE_DIR",
89
  "CMAKE_BINARY_DIR",
90
  "CMAKE_CURRENT_SOURCE_DIR",
91
  "CMAKE_CURRENT_BINARY_DIR",
92
  "CMAKE_RANLIB",
93
  "CMAKE_MT",
94
  "CMAKE_TAPI",
95
  "CMAKE_CUDA_HOST_COMPILER",
96
  "CMAKE_CUDA_HOST_LINK_LAUNCHER",
97
  "CMAKE_HIP_HOST_COMPILER",
98
  "CMAKE_HIP_HOST_LINK_LAUNCHER",
99
  "CMAKE_CL_SHOWINCLUDES_PREFIX",
100
};
101
102
// Variables whose placeholders now map to an empty string.
103
// Our platform modules no longer use these, but third-party code might.
104
auto ruleReplaceEmptyVars = {
105
  "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
106
  "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
107
  "CMAKE_${LANG}_LINK_FLAGS",
108
};
109
}
110
111
cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
112
5.92k
  : cmOutputConverter(makefile->GetStateSnapshot())
113
5.92k
  , DirectoryBacktrace(makefile->GetBacktrace())
114
5.92k
{
115
5.92k
  this->GlobalGenerator = gg;
116
117
5.92k
  this->Makefile = makefile;
118
119
5.92k
  this->AliasTargets = makefile->GetAliasTargets();
120
121
5.92k
  this->EmitUniversalBinaryFlags = true;
122
123
5.92k
  this->ComputeObjectMaxPath();
124
125
  // Canonicalize entries of the CPATH environment variable the same
126
  // way detection of CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES does.
127
5.92k
  {
128
5.92k
    std::vector<std::string> cpath;
129
5.92k
    cmSystemTools::GetPath(cpath, "CPATH");
130
5.92k
    for (std::string const& cp : cpath) {
131
0
      if (cmSystemTools::FileIsFullPath(cp)) {
132
0
        this->EnvCPATH.emplace_back(cmSystemTools::CollapseFullPath(cp));
133
0
      }
134
0
    }
135
5.92k
  }
136
137
5.92k
  std::vector<std::string> enabledLanguages =
138
5.92k
    this->GetState()->GetEnabledLanguages();
139
140
5.92k
  if (cmValue sysrootCompile =
141
5.92k
        this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
142
0
    this->CompilerSysroot = *sysrootCompile;
143
5.92k
  } else {
144
5.92k
    this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
145
5.92k
  }
146
147
5.92k
  if (cmValue sysrootLink =
148
5.92k
        this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
149
0
    this->LinkerSysroot = *sysrootLink;
150
5.92k
  } else {
151
5.92k
    this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
152
5.92k
  }
153
154
  // OSX SYSROOT can be required by some tools, like tapi
155
5.92k
  {
156
5.92k
    cmValue osxSysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
157
5.92k
    this->VariableMappings["CMAKE_OSX_SYSROOT"] =
158
5.92k
      osxSysroot.IsEmpty() ? "/" : this->EscapeForShell(*osxSysroot, true);
159
5.92k
  }
160
161
5.92k
  if (cmValue appleArchSysroots =
162
5.92k
        this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
163
0
    std::string const& appleArchs =
164
0
      this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
165
0
    cmList archs(appleArchs);
166
0
    cmList sysroots{ appleArchSysroots, cmList::EmptyElements::Yes };
167
0
    if (archs.size() == sysroots.size()) {
168
0
      for (cmList::size_type i = 0; i < archs.size(); ++i) {
169
0
        this->AppleArchSysroots[archs[i]] = sysroots[i];
170
0
      }
171
0
    } else {
172
0
      std::string const e =
173
0
        cmStrCat("CMAKE_APPLE_ARCH_SYSROOTS:\n  ", *appleArchSysroots,
174
0
                 "\n"
175
0
                 "is not the same length as CMAKE_OSX_ARCHITECTURES:\n  ",
176
0
                 appleArchs);
177
0
      this->IssueMessage(MessageType::FATAL_ERROR, e);
178
0
    }
179
0
  }
180
181
11.8k
  for (std::string const& lang : enabledLanguages) {
182
11.8k
    if (lang == "NONE") {
183
0
      continue;
184
0
    }
185
11.8k
    this->Compilers[cmStrCat("CMAKE_", lang, "_COMPILER")] = lang;
186
187
11.8k
    this->VariableMappings[cmStrCat("CMAKE_", lang, "_COMPILER")] =
188
11.8k
      this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", lang, "_COMPILER"));
189
190
11.8k
    std::string const& compilerArg1 =
191
11.8k
      cmStrCat("CMAKE_", lang, "_COMPILER_ARG1");
192
11.8k
    std::string const& compilerTarget =
193
11.8k
      cmStrCat("CMAKE_", lang, "_COMPILER_TARGET");
194
11.8k
    std::string const& compilerOptionTarget =
195
11.8k
      cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_TARGET");
196
11.8k
    std::string const& compilerExternalToolchain =
197
11.8k
      cmStrCat("CMAKE_", lang, "_COMPILER_EXTERNAL_TOOLCHAIN");
198
11.8k
    std::string const& compilerOptionExternalToolchain =
199
11.8k
      cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN");
200
11.8k
    std::string const& compilerOptionSysroot =
201
11.8k
      cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_SYSROOT");
202
203
11.8k
    this->VariableMappings[compilerArg1] =
204
11.8k
      this->Makefile->GetSafeDefinition(compilerArg1);
205
11.8k
    this->VariableMappings[compilerTarget] =
206
11.8k
      this->Makefile->GetSafeDefinition(compilerTarget);
207
11.8k
    this->VariableMappings[compilerOptionTarget] =
208
11.8k
      this->Makefile->GetSafeDefinition(compilerOptionTarget);
209
11.8k
    this->VariableMappings[compilerExternalToolchain] =
210
11.8k
      this->Makefile->GetSafeDefinition(compilerExternalToolchain);
211
11.8k
    this->VariableMappings[compilerOptionExternalToolchain] =
212
11.8k
      this->Makefile->GetSafeDefinition(compilerOptionExternalToolchain);
213
11.8k
    this->VariableMappings[compilerOptionSysroot] =
214
11.8k
      this->Makefile->GetSafeDefinition(compilerOptionSysroot);
215
216
213k
    for (std::string replaceVar : ruleReplaceVars) {
217
213k
      if (replaceVar.find("${LANG}") != std::string::npos) {
218
59.2k
        cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
219
59.2k
      }
220
221
213k
      this->VariableMappings[replaceVar] =
222
213k
        this->Makefile->GetSafeDefinition(replaceVar);
223
213k
    }
224
225
35.5k
    for (std::string replaceVar : ruleReplaceEmptyVars) {
226
35.5k
      if (replaceVar.find("${LANG}") != std::string::npos) {
227
35.5k
        cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
228
35.5k
      }
229
230
35.5k
      this->VariableMappings[replaceVar] = std::string();
231
35.5k
    }
232
11.8k
  }
233
5.92k
}
234
235
std::unique_ptr<cmRulePlaceholderExpander>
236
cmLocalGenerator::CreateRulePlaceholderExpander(cmBuildStep buildStep) const
237
0
{
238
0
  return cm::make_unique<cmRulePlaceholderExpander>(
239
0
    buildStep, this->Compilers, this->VariableMappings, this->CompilerSysroot,
240
0
    this->LinkerSysroot,
241
0
    this->GetState()->UseWatcomWMake() || this->GetState()->UseBorlandMake()
242
0
      ? cmRulePlaceholderExpander::UseShortPaths::Yes
243
0
      : cmRulePlaceholderExpander::UseShortPaths::No);
244
0
}
245
246
void cmLocalGenerator::AddDirectoryTestPrepDependency(
247
  std::string const& config, DirectoryTestPrepDependency dependency)
248
0
{
249
0
  this->DiscoveryTestPrepDependencies[config].push_back(std::move(dependency));
250
0
}
251
252
bool cmLocalGenerator::GetDirectoryTestPrepTarget(DirectoryTestPrepTarget& out,
253
                                                  std::string const& config)
254
0
{
255
0
  cmValue const directoryTestPrepDependencies =
256
0
    this->GetStateSnapshot().GetDirectory().GetProperty(
257
0
      "CMAKE_TEST_BUILD_DEPENDS");
258
0
  std::string const directoryId =
259
0
    cmCryptoHash(cmCryptoHash::AlgoMD5)
260
0
      .HashString(this->GetCurrentBinaryDirectory())
261
0
      .substr(0, 8);
262
0
  out.Name = cmStrCat("test_prep/directory_", directoryId);
263
0
  out.Comment =
264
0
    cmStrCat("Build extra dependencies for test prep in directory ",
265
0
             this->GetCurrentBinaryDirectory());
266
0
  out.Dependencies.clear();
267
0
  auto const discovery = this->DiscoveryTestPrepDependencies.find(config);
268
0
  if (discovery != this->DiscoveryTestPrepDependencies.end()) {
269
0
    out.Dependencies = discovery->second;
270
0
  }
271
272
0
  cmList buildDepends;
273
0
  if (directoryTestPrepDependencies) {
274
0
    buildDepends.assign(
275
0
      cmList{ *directoryTestPrepDependencies, cmList::EmptyElements::Yes });
276
0
  }
277
0
  cmTestGenerator::BuildDependencies deps;
278
0
  cmTestGenerator::EvaluateBuildDependencies(
279
0
    this, config, this->Makefile->GetBacktrace(), "directory_test_prep", {},
280
0
    std::vector<std::string>(buildDepends.begin(), buildDepends.end()), deps,
281
0
    this->Makefile);
282
0
  for (cmGeneratorTarget* target : deps.Targets) {
283
0
    out.Dependencies.push_back({ target->GetName(), target });
284
0
  }
285
0
  for (cmTestGenerator::BuildDependencies::FileDependency const& file :
286
0
       deps.Files) {
287
0
    out.Dependencies.push_back(
288
0
      { file.Path, nullptr, file.Owner, file.Generated });
289
0
  }
290
0
  return !out.Dependencies.empty();
291
0
}
292
293
5.92k
cmLocalGenerator::~cmLocalGenerator() = default;
294
295
void cmLocalGenerator::IssueMessage(MessageType type, std::string const& text,
296
                                    cmListFileBacktrace const& bt) const
297
0
{
298
0
  this->GetMakefile()->IssueMessage(type, text, bt);
299
0
}
300
301
void cmLocalGenerator::IssueDiagnostic(
302
  cmDiagnosticCategory category, std::string const& text,
303
  cmDiagnosticContext const& context) const
304
0
{
305
0
  this->GetMakefile()->IssueDiagnostic(category, text, context);
306
0
}
307
308
void cmLocalGenerator::IssuePolicyWarning(cmPolicies::PolicyID policy,
309
                                          cm::string_view preface,
310
                                          cm::string_view postface,
311
                                          cmListFileBacktrace const& bt) const
312
0
{
313
0
  this->GetMakefile()->IssuePolicyWarning(policy, preface, postface, bt);
314
0
}
315
316
void cmLocalGenerator::ComputeObjectMaxPath()
317
5.92k
{
318
// Choose a maximum object file name length.
319
#if defined(_WIN32) || defined(__CYGWIN__)
320
  this->ObjectPathMax = 250;
321
#else
322
5.92k
  this->ObjectPathMax = 1000;
323
5.92k
#endif
324
5.92k
  cmValue plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
325
5.92k
  if (cmNonempty(plen)) {
326
0
    unsigned int pmax;
327
0
    if (sscanf(plen->c_str(), "%u", &pmax) == 1) {
328
0
      if (pmax >= 128) {
329
0
        this->ObjectPathMax = pmax;
330
0
      } else {
331
0
        this->IssueDiagnostic(
332
0
          cmDiagnostics::CMD_AUTHOR,
333
0
          cmStrCat("CMAKE_OBJECT_PATH_MAX is set to ", pmax,
334
0
                   ", which is less than the minimum of 128.  "
335
0
                   "The value will be ignored."));
336
0
      }
337
0
    } else {
338
0
      this->IssueDiagnostic(
339
0
        cmDiagnostics::CMD_AUTHOR,
340
0
        cmStrCat("CMAKE_OBJECT_PATH_MAX is set to \"", *plen,
341
0
                 "\", which fails to parse as a positive integer.  "
342
0
                 "The value will be ignored."));
343
0
    }
344
0
  }
345
5.92k
  this->ObjectMaxPathViolations.clear();
346
5.92k
}
347
348
static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs,
349
                                    std::string const& config,
350
                                    std::string const& lang,
351
                                    cmGeneratorTarget const* target)
352
0
{
353
0
  if (!target) {
354
0
    return;
355
0
  }
356
357
0
  std::stable_sort(
358
0
    includeDirs.begin(), includeDirs.end(),
359
0
    [&target, &config, &lang](std::string const& a, std::string const& b) {
360
0
      return !target->IsSystemIncludeDirectory(a, config, lang) &&
361
0
        target->IsSystemIncludeDirectory(b, config, lang);
362
0
    });
363
0
}
364
365
static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs,
366
                                    std::string const& config,
367
                                    std::string const& lang,
368
                                    cmGeneratorTarget const* target)
369
0
{
370
0
  if (!target) {
371
0
    return;
372
0
  }
373
374
0
  std::stable_sort(includeDirs.begin(), includeDirs.end(),
375
0
                   [target, &config, &lang](BT<std::string> const& a,
376
0
                                            BT<std::string> const& b) {
377
0
                     return !target->IsSystemIncludeDirectory(a.Value, config,
378
0
                                                              lang) &&
379
0
                       target->IsSystemIncludeDirectory(b.Value, config, lang);
380
0
                   });
381
0
}
382
383
void cmLocalGenerator::TraceDependencies() const
384
0
{
385
  // Generate the rule files for each target.
386
0
  auto const& targets = this->GetGeneratorTargets();
387
0
  for (auto const& target : targets) {
388
0
    if (!target->IsInBuildSystem()) {
389
0
      continue;
390
0
    }
391
0
    target->TraceDependencies();
392
0
  }
393
0
}
394
395
#ifndef CMAKE_BOOTSTRAP
396
void cmLocalGenerator::ResolveSourceGroupGenex()
397
0
{
398
0
  this->Makefile->ResolveSourceGroupGenex(this);
399
0
}
400
#endif
401
402
void cmLocalGenerator::GenerateTestFiles()
403
0
{
404
0
  if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
405
0
    return;
406
0
  }
407
408
  // Compute the set of configurations.
409
0
  std::vector<std::string> configurationTypes =
410
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
411
0
  std::string config = this->Makefile->GetDefaultConfiguration();
412
413
0
  std::string file =
414
0
    cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(),
415
0
             "/CTestTestfile.cmake");
416
0
  this->GlobalGenerator->AddTestFile(file);
417
418
0
  cmGeneratedFileStream fout(file);
419
420
0
  fout << "# CMake generated Testfile for \n"
421
0
          "# Source directory: "
422
0
       << this->StateSnapshot.GetDirectory().GetCurrentSource()
423
0
       << "\n"
424
0
          "# Build directory: "
425
0
       << this->StateSnapshot.GetDirectory().GetCurrentBinary()
426
0
       << "\n"
427
0
          "# \n"
428
0
          "# This file includes the relevant testing commands "
429
0
          "required for \n"
430
0
          "# testing this directory and lists subdirectories to "
431
0
          "be tested as well.\n";
432
433
0
  std::string resourceSpecFile =
434
0
    this->Makefile->GetSafeDefinition("CTEST_RESOURCE_SPEC_FILE");
435
0
  if (!resourceSpecFile.empty()) {
436
0
    fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n";
437
0
  }
438
0
  std::string resourceErrorAction =
439
0
    this->Makefile->GetSafeDefinition("CTEST_RESOURCE_ERROR_ACTION");
440
0
  if (!resourceErrorAction.empty()) {
441
0
    fout << "set(CTEST_RESOURCE_ERROR_ACTION \"" << resourceErrorAction
442
0
         << "\")\n";
443
0
  }
444
445
0
  auto writeTestIncludeFile = [this, &fout, &configurationTypes,
446
0
                               &config](std::string const& entry) {
447
    // Entries without a generator expression are emitted verbatim,
448
    // preserving CTest-time ${VAR} expansion of the path.
449
0
    if (cmGeneratorExpression::Find(entry) == std::string::npos) {
450
0
      fout << "include(\"" << entry << "\")\n";
451
0
      return;
452
0
    }
453
454
    // Emit one include() per path in an evaluated result.  As for list-valued
455
    // properties, the result is split on ';', and each path is quoted so that
456
    // any '"', '$', or '\' cannot break the include() argument or trigger a
457
    // second-stage CTest ${...} expansion.  An empty result adds no include.
458
0
    auto writeIncludes = [&fout](std::vector<std::string> const& paths,
459
0
                                 char const* indent) {
460
0
      for (std::string const& path : paths) {
461
0
        fout << indent << "include(" << cmScriptGenerator::Quote(path)
462
0
             << ")\n";
463
0
      }
464
0
    };
465
466
0
    if (!this->GlobalGenerator->IsMultiConfig() ||
467
0
        configurationTypes.empty()) {
468
      // Single-config generator, or a multi-config generator with no
469
      // configuration types: evaluate once with the default configuration
470
      // and emit unconditional includes.
471
0
      std::vector<std::string> paths;
472
0
      cmExpandList(cmGeneratorExpression::Evaluate(entry, this, config),
473
0
                   paths);
474
0
      writeIncludes(paths, "");
475
0
      return;
476
0
    }
477
478
    // Multi-config generator: evaluate the entry for every configuration.
479
0
    std::vector<std::string> results;
480
0
    results.reserve(configurationTypes.size());
481
0
    bool allSame = true;
482
0
    for (std::string const& ct : configurationTypes) {
483
0
      results.emplace_back(cmGeneratorExpression::Evaluate(entry, this, ct));
484
0
      if (results.back() != results.front()) {
485
0
        allSame = false;
486
0
      }
487
0
    }
488
489
    // A config-independent result collapses to unconditional includes, so it
490
    // still runs when ctest is invoked without -C.
491
0
    if (allSame) {
492
0
      std::vector<std::string> paths;
493
0
      cmExpandList(results.front(), paths);
494
0
      writeIncludes(paths, "");
495
0
      return;
496
0
    }
497
498
    // Otherwise guard each per-config result to match the config guards used
499
    // for add_test().  A configuration whose result yields no include is
500
    // skipped so no empty guard is emitted.
501
0
    bool first = true;
502
0
    for (size_t i = 0; i < configurationTypes.size(); ++i) {
503
0
      std::vector<std::string> paths;
504
0
      cmExpandList(results[i], paths);
505
0
      if (paths.empty()) {
506
0
        continue;
507
0
      }
508
0
      fout << (first ? "if(" : "elseif(")
509
0
           << cmScriptGenerator::CreateConfigTest("CTEST_CONFIGURATION_TYPE",
510
0
                                                  configurationTypes[i])
511
0
           << ")\n";
512
0
      writeIncludes(paths, "  ");
513
0
      first = false;
514
0
    }
515
0
    if (!first) {
516
0
      fout << "endif()\n";
517
0
    }
518
0
  };
519
520
0
  cmValue testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE");
521
0
  if (testIncludeFile) {
522
0
    writeTestIncludeFile(*testIncludeFile);
523
0
  }
524
525
0
  cmValue testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
526
0
  if (testIncludeFiles) {
527
0
    cmList includesList{ *testIncludeFiles };
528
0
    for (std::string const& i : includesList) {
529
0
      writeTestIncludeFile(i);
530
0
    }
531
0
  }
532
533
  // Ask each test generator to write its code.
534
0
  for (auto const& tester : this->Makefile->GetTestGenerators()) {
535
0
    tester->Generate(fout, config, configurationTypes);
536
0
  }
537
0
  using vec_t = std::vector<cmStateSnapshot>;
538
0
  vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
539
0
  for (cmStateSnapshot const& i : children) {
540
    // TODO: Use add_subdirectory instead?
541
0
    std::string outP = i.GetDirectory().GetCurrentBinary();
542
0
    outP = this->MaybeRelativeToCurBinDir(outP);
543
0
    fout << "subdirs(" << cmScriptGenerator::Quote(outP) << ")\n";
544
0
  }
545
546
  // Add directory labels property
547
0
  cmValue directoryLabels =
548
0
    this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
549
0
  cmValue labels = this->Makefile->GetProperty("LABELS");
550
551
0
  if (labels || directoryLabels) {
552
0
    fout << "set_directory_properties(PROPERTIES LABELS ";
553
0
    if (labels) {
554
0
      fout << cmScriptGenerator::Quote(*labels);
555
0
    }
556
0
    if (labels && directoryLabels) {
557
0
      fout << ";";
558
0
    }
559
0
    if (directoryLabels) {
560
0
      fout << cmScriptGenerator::Quote(*directoryLabels);
561
0
    }
562
0
    fout << ")\n";
563
0
  }
564
0
}
565
566
void cmLocalGenerator::CreateEvaluationFileOutputs()
567
0
{
568
0
  std::vector<std::string> const& configs =
569
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
570
0
  for (std::string const& c : configs) {
571
0
    this->CreateEvaluationFileOutputs(c);
572
0
  }
573
0
}
574
575
void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
576
0
{
577
0
  for (auto const& geef : this->Makefile->GetEvaluationFiles()) {
578
0
    geef->CreateOutputFile(this, config);
579
0
  }
580
0
}
581
582
void cmLocalGenerator::ProcessEvaluationFiles(
583
  std::vector<std::string>& generatedFiles)
584
0
{
585
0
  for (auto const& geef : this->Makefile->GetEvaluationFiles()) {
586
0
    geef->Generate(this);
587
0
    if (cmSystemTools::GetFatalErrorOccurred()) {
588
0
      return;
589
0
    }
590
0
    std::vector<std::string> files = geef->GetFiles();
591
0
    std::sort(files.begin(), files.end());
592
593
0
    std::vector<std::string> intersection;
594
0
    std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
595
0
                          generatedFiles.end(),
596
0
                          std::back_inserter(intersection));
597
0
    if (!intersection.empty()) {
598
0
      cmSystemTools::Error("Files to be generated by multiple different "
599
0
                           "commands: " +
600
0
                           cmWrap('"', intersection, '"', " "));
601
0
      return;
602
0
    }
603
604
0
    cm::append(generatedFiles, files);
605
0
    std::inplace_merge(generatedFiles.begin(),
606
0
                       generatedFiles.end() - files.size(),
607
0
                       generatedFiles.end());
608
0
  }
609
0
}
610
611
void cmLocalGenerator::GenerateInstallRules()
612
0
{
613
  // Compute the install prefix.
614
0
  cmValue installPrefix =
615
0
    this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
616
0
  std::string prefix = *installPrefix;
617
618
#if defined(_WIN32) && !defined(__CYGWIN__)
619
  if (!installPrefix) {
620
    if (!cmSystemTools::GetEnv("SystemDrive", prefix)) {
621
      prefix = "C:";
622
    }
623
    cmValue project_name = this->Makefile->GetDefinition("PROJECT_NAME");
624
    if (cmNonempty(project_name)) {
625
      prefix += "/Program Files/";
626
      prefix += *project_name;
627
    } else {
628
      prefix += "/InstalledCMakeProject";
629
    }
630
  }
631
#elif defined(__HAIKU__)
632
  char dir[B_PATH_NAME_LENGTH];
633
  if (!installPrefix) {
634
    if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
635
        B_OK) {
636
      prefix = dir;
637
    } else {
638
      prefix = "/boot/system";
639
    }
640
  }
641
#else
642
0
  if (!installPrefix) {
643
0
    prefix = "/usr/local";
644
0
  }
645
0
#endif
646
0
  if (cmValue stagingPrefix =
647
0
        this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
648
0
    prefix = *stagingPrefix;
649
0
  }
650
651
  // Compute the set of configurations.
652
0
  std::vector<std::string> configurationTypes =
653
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
654
0
  std::string config = this->Makefile->GetDefaultConfiguration();
655
656
  // Choose a default install configuration.
657
0
  std::string default_config = config;
658
0
  char const* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
659
0
                                  "DEBUG", nullptr };
660
0
  for (char const** c = default_order; *c && default_config.empty(); ++c) {
661
0
    for (std::string const& configurationType : configurationTypes) {
662
0
      if (cmSystemTools::UpperCase(configurationType) == *c) {
663
0
        default_config = configurationType;
664
0
      }
665
0
    }
666
0
  }
667
0
  if (default_config.empty() && !configurationTypes.empty()) {
668
0
    default_config = configurationTypes[0];
669
0
  }
670
671
  // Create the install script file.
672
0
  std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
673
0
  std::string homedir = this->GetState()->GetBinaryDirectory();
674
0
  int toplevel_install = 0;
675
0
  if (file == homedir) {
676
0
    toplevel_install = 1;
677
0
  }
678
0
  file += "/cmake_install.cmake";
679
0
  this->GetGlobalGenerator()->AddInstallScript(file);
680
0
  cmGeneratedFileStream fout(file);
681
682
  // Write the header.
683
  /* clang-format off */
684
0
  fout << "# Install script for directory: "
685
0
       << this->StateSnapshot.GetDirectory().GetCurrentSource()
686
0
       << "\n\n"
687
0
          "# Set the install prefix\n"
688
0
          "if(NOT DEFINED CMAKE_INSTALL_PREFIX)\n"
689
0
          "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")\n"
690
0
          "endif()\n"
691
0
       << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
692
0
       << "\"${CMAKE_INSTALL_PREFIX}\")\n\n";
693
  /* clang-format on */
694
695
  // Write support code for generating per-configuration install rules.
696
  /* clang-format off */
697
0
  fout <<
698
0
    "# Set the install configuration name.\n"
699
0
    "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
700
0
    "  if(BUILD_TYPE)\n"
701
0
    "    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
702
0
    "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
703
0
    "  else()\n"
704
0
    "    set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
705
0
    "  endif()\n"
706
0
    "  message(STATUS \"Install configuration: "
707
0
    "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
708
0
    "endif()\n"
709
0
    "\n";
710
  /* clang-format on */
711
712
  // Write support code for dealing with component-specific installs.
713
  /* clang-format off */
714
0
  fout <<
715
0
    "# Set the component getting installed.\n"
716
0
    "if(NOT CMAKE_INSTALL_COMPONENT)\n"
717
0
    "  if(COMPONENT)\n"
718
0
    "    message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n"
719
0
    "    set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n"
720
0
    "  else()\n"
721
0
    "    set(CMAKE_INSTALL_COMPONENT)\n"
722
0
    "  endif()\n"
723
0
    "endif()\n"
724
0
    "\n";
725
  /* clang-format on */
726
727
  // Copy user-specified install options to the install code.
728
0
  if (cmValue so_no_exe =
729
0
        this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
730
    /* clang-format off */
731
0
    fout <<
732
0
      "# Install shared libraries without execute permission?\n"
733
0
      "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
734
0
      "  set(CMAKE_INSTALL_SO_NO_EXE \"" << *so_no_exe << "\")\n"
735
0
      "endif()\n"
736
0
      "\n";
737
    /* clang-format on */
738
0
  }
739
740
  // Copy cmake cross compile state to install code.
741
0
  if (cmValue crosscompiling =
742
0
        this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) {
743
    /* clang-format off */
744
0
    fout <<
745
0
      "# Is this installation the result of a crosscompile?\n"
746
0
      "if(NOT DEFINED CMAKE_CROSSCOMPILING)\n"
747
0
      "  set(CMAKE_CROSSCOMPILING \"" << *crosscompiling << "\")\n"
748
0
      "endif()\n"
749
0
      "\n";
750
    /* clang-format on */
751
0
  }
752
753
  // Write default directory permissions.
754
0
  if (cmValue defaultDirPermissions = this->Makefile->GetDefinition(
755
0
        "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) {
756
    /* clang-format off */
757
0
    fout <<
758
0
      "# Set default install directory permissions.\n"
759
0
      "if(NOT DEFINED CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)\n"
760
0
      "  set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS \""
761
0
         << *defaultDirPermissions << "\")\n"
762
0
      "endif()\n"
763
0
      "\n";
764
    /* clang-format on */
765
0
  }
766
767
  // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM so that
768
  // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
769
  // has same platform variable as when running cmake
770
0
  if (cmValue platform = this->Makefile->GetDefinition(
771
0
        "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM")) {
772
    /* clang-format off */
773
0
    fout <<
774
0
      "# Set OS and executable format for runtime-dependencies.\n"
775
0
      "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM)\n"
776
0
      "  set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM \""
777
0
         << *platform << "\")\n"
778
0
      "endif()\n"
779
0
      "\n";
780
    /* clang-format on */
781
0
  }
782
783
  // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL so that
784
  // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
785
  // has same tool selected as when running cmake
786
0
  if (cmValue command =
787
0
        this->Makefile->GetDefinition("CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL")) {
788
    /* clang-format off */
789
0
    fout <<
790
0
      "# Set tool for dependency-resolution of runtime-dependencies.\n"
791
0
      "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL)\n"
792
0
      "  set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL \""
793
0
         << *command << "\")\n"
794
0
      "endif()\n"
795
0
      "\n";
796
    /* clang-format on */
797
0
  }
798
799
  // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND so that
800
  // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
801
  // has same path to the tool as when running cmake
802
0
  if (cmValue command = this->Makefile->GetDefinition(
803
0
        "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND")) {
804
    /* clang-format off */
805
0
    fout <<
806
0
      "# Set path to tool for dependency-resolution of runtime-dependencies.\n"
807
0
      "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND)\n"
808
0
      "  set(CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND \""
809
0
         << *command << "\")\n"
810
0
      "endif()\n"
811
0
      "\n";
812
    /* clang-format on */
813
0
  }
814
815
  // Write out CMAKE_OBJDUMP so that installed code that uses
816
  // `file(GET_RUNTIME_DEPENDENCIES)` and hasn't specified
817
  // CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND has consistent
818
  // logic to fallback to CMAKE_OBJDUMP when `objdump` is
819
  // not on the path
820
0
  if (cmValue command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) {
821
    /* clang-format off */
822
0
    fout <<
823
0
      "# Set path to fallback-tool for dependency-resolution.\n"
824
0
      "if(NOT DEFINED CMAKE_OBJDUMP)\n"
825
0
      "  set(CMAKE_OBJDUMP \""
826
0
         << *command << "\")\n"
827
0
      "endif()\n"
828
0
      "\n";
829
    /* clang-format on */
830
0
  }
831
832
0
  this->AddGeneratorSpecificInstallSetup(fout);
833
834
  // Ask each install generator to write its code.
835
0
  cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082);
836
0
  auto const& installers = this->Makefile->GetInstallGenerators();
837
0
  bool haveSubdirectoryInstall = false;
838
0
  bool haveInstallAfterSubdirectory = false;
839
0
  if (status == cmPolicies::WARN) {
840
0
    for (auto const& installer : installers) {
841
0
      installer->CheckCMP0082(haveSubdirectoryInstall,
842
0
                              haveInstallAfterSubdirectory);
843
0
      installer->Generate(fout, config, configurationTypes);
844
0
    }
845
0
  } else {
846
0
    for (auto const& installer : installers) {
847
0
      installer->Generate(fout, config, configurationTypes);
848
0
    }
849
0
  }
850
851
  // Write rules from old-style specification stored in targets.
852
0
  this->GenerateTargetInstallRules(fout, config, configurationTypes);
853
854
  // Include install scripts from subdirectories.
855
0
  switch (status) {
856
0
    case cmPolicies::WARN:
857
0
      if (haveInstallAfterSubdirectory &&
858
0
          this->Makefile->PolicyOptionalWarningEnabled(
859
0
            "CMAKE_POLICY_WARNING_CMP0082")) {
860
0
        this->IssuePolicyWarning(cmPolicies::CMP0082);
861
0
      }
862
0
      CM_FALLTHROUGH;
863
0
    case cmPolicies::OLD: {
864
0
      std::vector<cmStateSnapshot> children =
865
0
        this->Makefile->GetStateSnapshot().GetChildren();
866
0
      if (!children.empty()) {
867
0
        fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
868
0
        fout << "  # Include the install script for each subdirectory.\n";
869
0
        for (cmStateSnapshot const& c : children) {
870
0
          if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
871
0
            std::string odir = c.GetDirectory().GetCurrentBinary();
872
0
            cmSystemTools::ConvertToUnixSlashes(odir);
873
0
            fout << "  include(\"" << odir << "/cmake_install.cmake\")\n";
874
0
          }
875
0
        }
876
0
        fout << "\n";
877
0
        fout << "endif()\n\n";
878
0
      }
879
0
    } break;
880
881
0
    case cmPolicies::NEW:
882
      // NEW behavior is handled in
883
      // cmInstallSubdirectoryGenerator::GenerateScript()
884
0
      break;
885
0
  }
886
887
  /* clang-format off */
888
889
0
    fout <<
890
0
      "string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
891
0
      "       \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n"
892
0
      "if(CMAKE_INSTALL_LOCAL_ONLY)\n"
893
0
      "  file(WRITE \"" <<
894
0
      this->StateSnapshot.GetDirectory().GetCurrentBinary() <<
895
0
      "/install_local_manifest.txt\"\n"
896
0
      "     \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n"
897
0
      "endif()\n";
898
899
0
    if (toplevel_install) {
900
0
      fout <<
901
0
        "if(CMAKE_INSTALL_COMPONENT)\n"
902
0
        "  if(CMAKE_INSTALL_COMPONENT MATCHES \"^[a-zA-Z0-9_.+-]+$\")\n"
903
0
        "    set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
904
0
        "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
905
0
        "  else()\n"
906
0
        "    string(MD5 CMAKE_INST_COMP_HASH \"${CMAKE_INSTALL_COMPONENT}\")\n"
907
0
        "    set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
908
0
        "${CMAKE_INST_COMP_HASH}.txt\")\n"
909
0
        "    unset(CMAKE_INST_COMP_HASH)\n"
910
0
        "  endif()\n"
911
0
        "else()\n"
912
0
        "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
913
0
        "endif()\n"
914
0
        "\n"
915
0
        "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n"
916
0
        "  file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
917
0
        "     \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n"
918
0
        "endif()\n";
919
0
    }
920
  /* clang-format on */
921
0
}
922
923
void cmLocalGenerator::AddGeneratorTarget(
924
  std::unique_ptr<cmGeneratorTarget> gt)
925
35.5k
{
926
35.5k
  cmGeneratorTarget* gt_ptr = gt.get();
927
928
35.5k
  this->GeneratorTargets.push_back(std::move(gt));
929
35.5k
  this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr);
930
35.5k
  this->GlobalGenerator->IndexGeneratorTarget(gt_ptr);
931
35.5k
}
932
933
void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
934
17.7k
{
935
17.7k
  this->ImportedGeneratorTargets.emplace(gt->GetName(), gt);
936
17.7k
  this->GlobalGenerator->IndexGeneratorTarget(gt);
937
17.7k
}
938
939
void cmLocalGenerator::AddOwnedImportedGeneratorTarget(
940
  std::unique_ptr<cmGeneratorTarget> gt)
941
17.7k
{
942
17.7k
  this->OwnedImportedGeneratorTargets.push_back(std::move(gt));
943
17.7k
}
944
945
cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
946
  std::string const& name) const
947
163k
{
948
163k
  auto ti = this->GeneratorTargetSearchIndex.find(name);
949
163k
  if (ti != this->GeneratorTargetSearchIndex.end()) {
950
27.8k
    return ti->second;
951
27.8k
  }
952
135k
  return nullptr;
953
163k
}
954
955
void cmLocalGenerator::AddGeneratorRule(std::unique_ptr<cmGeneratorRule> gr)
956
0
{
957
0
  cmGeneratorRule* gr_ptr = gr.get();
958
959
0
  this->GeneratorRules.push_back(std::move(gr));
960
0
  this->GeneratorRuleSearchIndex.emplace(gr_ptr->GetName(), gr_ptr);
961
0
  this->GlobalGenerator->IndexGeneratorRule(gr_ptr);
962
0
}
963
964
cmGeneratorRule* cmLocalGenerator::FindGeneratorRuleToUse(
965
  std::string const& name) const
966
0
{
967
0
  auto ri = this->GeneratorRuleSearchIndex.find(name);
968
0
  if (ri != this->GeneratorRuleSearchIndex.end()) {
969
0
    return ri->second;
970
0
  }
971
972
0
  return this->GetGlobalGenerator()->FindGeneratorRule(name);
973
0
}
974
975
void cmLocalGenerator::ComputeTargetManifest()
976
0
{
977
  // Collect the set of configuration types.
978
0
  std::vector<std::string> configNames =
979
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
980
981
  // Add our targets to the manifest for each configuration.
982
0
  auto const& targets = this->GetGeneratorTargets();
983
0
  for (auto const& target : targets) {
984
0
    if (!target->IsInBuildSystem()) {
985
0
      continue;
986
0
    }
987
0
    for (std::string const& c : configNames) {
988
0
      target->ComputeTargetManifest(c);
989
0
    }
990
0
  }
991
0
}
992
993
bool cmLocalGenerator::ComputeTargetCompileFeatures()
994
0
{
995
  // Collect the set of configuration types.
996
0
  std::vector<std::string> configNames =
997
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
998
999
0
  using LanguagePair = std::pair<std::string, std::string>;
1000
0
  std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" },
1001
0
                                             { "OBJCXX", "CXX" },
1002
0
                                             { "CUDA", "CXX" },
1003
0
                                             { "HIP", "CXX" },
1004
0
                                             { "SYCL", "CXX" } };
1005
0
  std::set<LanguagePair> inferredEnabledLanguages;
1006
0
  for (auto const& lang : pairedLanguages) {
1007
0
    if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) {
1008
0
      inferredEnabledLanguages.insert(lang);
1009
0
    }
1010
0
  }
1011
1012
  // Process compile features of all targets.
1013
0
  auto const& targets = this->GetGeneratorTargets();
1014
0
  for (auto const& target : targets) {
1015
0
    for (std::string const& c : configNames) {
1016
0
      if (!target->ComputeCompileFeatures(c)) {
1017
0
        return false;
1018
0
      }
1019
0
    }
1020
1021
    // Now that C/C++ _STANDARD values have been computed
1022
    // set the values to ObjC/ObjCXX _STANDARD variables
1023
0
    if (target->CanCompileSources()) {
1024
0
      for (std::string const& c : configNames) {
1025
0
        target->ComputeCompileFeatures(c, inferredEnabledLanguages);
1026
0
      }
1027
0
    }
1028
0
  }
1029
1030
0
  return true;
1031
0
}
1032
1033
bool cmLocalGenerator::IsRootMakefile() const
1034
0
{
1035
0
  return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
1036
0
}
1037
1038
cmState* cmLocalGenerator::GetState() const
1039
11.8k
{
1040
11.8k
  return this->GlobalGenerator->GetCMakeInstance()->GetState();
1041
11.8k
}
1042
1043
cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
1044
54
{
1045
54
  return this->Makefile->GetStateSnapshot();
1046
54
}
1047
1048
std::string cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
1049
                                              std::string const& prop,
1050
                                              std::string const& config)
1051
0
{
1052
0
  cmValue value = this->Makefile->GetProperty(prop);
1053
0
  if (target) {
1054
0
    value = target->GetProperty(prop);
1055
0
  }
1056
0
  if (value) {
1057
0
    return cmGeneratorExpression::Evaluate(*value, this, config, target);
1058
0
  }
1059
0
  return "";
1060
0
}
1061
1062
std::string cmLocalGenerator::ConvertToIncludeReference(
1063
  std::string const& path, OutputFormat format)
1064
0
{
1065
0
  return this->ConvertToOutputForExisting(path, format);
1066
0
}
1067
1068
std::string cmLocalGenerator::GetIncludeFlags(
1069
  std::vector<std::string> const& includeDirs, cmGeneratorTarget* target,
1070
  std::string const& lang, std::string const& config, bool forResponseFile)
1071
0
{
1072
0
  if (lang.empty()) {
1073
0
    return "";
1074
0
  }
1075
1076
0
  std::vector<std::string> includes = includeDirs;
1077
0
  MoveSystemIncludesToEnd(includes, config, lang, target);
1078
1079
0
  OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
1080
0
  std::ostringstream includeFlags;
1081
1082
0
  std::string const& includeFlag =
1083
0
    this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
1084
0
  bool quotePaths = false;
1085
0
  if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
1086
0
    quotePaths = true;
1087
0
  }
1088
0
  std::string sep = " ";
1089
0
  bool repeatFlag = true;
1090
  // should the include flag be repeated like ie. -IA -IB
1091
0
  if (cmValue incSep = this->Makefile->GetDefinition(
1092
0
        cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang))) {
1093
    // if there is a separator then the flag is not repeated but is only
1094
    // given once i.e.  -classpath a:b:c
1095
0
    sep = *incSep;
1096
0
    repeatFlag = false;
1097
0
  }
1098
1099
  // Support special system include flag if it is available and the
1100
  // normal flag is repeated for each directory.
1101
0
  cmValue sysIncludeFlag = nullptr;
1102
0
  cmValue sysIncludeFlagWarning = nullptr;
1103
0
  if (repeatFlag) {
1104
0
    sysIncludeFlag = this->Makefile->GetDefinition(
1105
0
      cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
1106
0
    sysIncludeFlagWarning = this->Makefile->GetDefinition(
1107
0
      cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang, "_WARNING"));
1108
0
  }
1109
1110
0
  cmValue fwSearchFlag = this->Makefile->GetDefinition(
1111
0
    cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG"));
1112
0
  cmValue sysFwSearchFlag = this->Makefile->GetDefinition(
1113
0
    cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
1114
1115
0
  bool flagUsed = false;
1116
0
  bool sysIncludeFlagUsed = false;
1117
0
  std::set<std::string> emitted;
1118
#ifdef __APPLE__
1119
  emitted.insert("/System/Library/Frameworks");
1120
#endif
1121
0
  for (std::string const& i : includes) {
1122
0
    if (cmNonempty(fwSearchFlag) && this->Makefile->IsOn("APPLE") &&
1123
0
        cmSystemTools::IsPathToFramework(i)) {
1124
0
      std::string const frameworkDir = cmSystemTools::GetFilenamePath(i);
1125
0
      if (emitted.insert(frameworkDir).second) {
1126
0
        if (sysFwSearchFlag && target &&
1127
0
            target->IsSystemIncludeDirectory(frameworkDir, config, lang)) {
1128
0
          includeFlags << *sysFwSearchFlag;
1129
0
        } else {
1130
0
          includeFlags << *fwSearchFlag;
1131
0
        }
1132
0
        includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
1133
0
                     << " ";
1134
0
      }
1135
0
      continue;
1136
0
    }
1137
1138
0
    if (!flagUsed || repeatFlag) {
1139
0
      if (sysIncludeFlag && target &&
1140
0
          target->IsSystemIncludeDirectory(i, config, lang)) {
1141
0
        includeFlags << *sysIncludeFlag;
1142
0
        sysIncludeFlagUsed = true;
1143
0
      } else {
1144
0
        includeFlags << includeFlag;
1145
0
      }
1146
0
      flagUsed = true;
1147
0
    }
1148
0
    std::string includePath = this->ConvertToIncludeReference(i, shellFormat);
1149
0
    if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
1150
0
      includeFlags << "\"";
1151
0
    }
1152
0
    includeFlags << includePath;
1153
0
    if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
1154
0
      includeFlags << "\"";
1155
0
    }
1156
0
    includeFlags << sep;
1157
0
  }
1158
0
  if (sysIncludeFlagUsed && sysIncludeFlagWarning) {
1159
0
    includeFlags << *sysIncludeFlagWarning;
1160
0
  }
1161
0
  std::string flags = includeFlags.str();
1162
  // remove trailing separators
1163
0
  if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) {
1164
0
    flags.back() = ' ';
1165
0
  }
1166
0
  return cmTrimWhitespace(flags);
1167
0
}
1168
1169
void cmLocalGenerator::AddCompileOptions(std::string& flags,
1170
                                         cmGeneratorTarget* target,
1171
                                         std::string const& lang,
1172
                                         std::string const& config)
1173
0
{
1174
0
  std::vector<BT<std::string>> tmpFlags;
1175
0
  this->AddCompileOptions(tmpFlags, target, lang, config);
1176
0
  this->AppendFlags(flags, tmpFlags);
1177
0
}
1178
1179
void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
1180
                                         cmGeneratorTarget* target,
1181
                                         std::string const& lang,
1182
                                         std::string const& config)
1183
0
{
1184
0
  if (lang == "SYCL") {
1185
0
    cmValue separable = target->GetProperty("SYCL_SEPARABLE_COMPILATION");
1186
0
    char const* mode = separable.IsOn() ? "ON" : "OFF";
1187
0
    cmValue options = this->Makefile->GetDefinition(
1188
0
      cmStrCat("CMAKE_SYCL_COMPILE_OPTIONS_SEPARABLE_COMPILATION_", mode));
1189
0
    if (!options && separable) {
1190
0
      this->IssueMessage(
1191
0
        MessageType::FATAL_ERROR,
1192
0
        cmStrCat("Target \"", target->GetName(),
1193
0
                 "\" requests SYCL_SEPARABLE_COMPILATION=", mode,
1194
0
                 ", but the SYCL compiler configuration does not support "
1195
0
                 "this mode."));
1196
0
      return;
1197
0
    }
1198
0
    std::string separableFlags;
1199
0
    if (options) {
1200
0
      this->AppendCompileOptions(separableFlags, *options);
1201
0
    }
1202
0
    if (!separableFlags.empty()) {
1203
0
      flags.emplace_back(std::move(separableFlags));
1204
0
    }
1205
0
  }
1206
1207
0
  std::string langFlagRegexVar = cmStrCat("CMAKE_", lang, "_FLAG_REGEX");
1208
1209
0
  if (cmValue langFlagRegexStr =
1210
0
        this->Makefile->GetDefinition(langFlagRegexVar)) {
1211
    // Filter flags acceptable to this language.
1212
0
    if (cmValue targetFlags = target->GetProperty("COMPILE_FLAGS")) {
1213
0
      std::vector<std::string> opts;
1214
0
      cmSystemTools::ParseWindowsCommandLine(targetFlags->c_str(), opts);
1215
      // Re-escape these flags since COMPILE_FLAGS were already parsed
1216
      // as a command line above.
1217
0
      std::string compileOpts;
1218
0
      this->AppendCompileOptions(compileOpts, opts, langFlagRegexStr->c_str());
1219
0
      if (!compileOpts.empty()) {
1220
0
        flags.emplace_back(std::move(compileOpts));
1221
0
      }
1222
0
    }
1223
0
    std::vector<BT<std::string>> targetCompileOpts =
1224
0
      target->GetCompileOptions(config, lang);
1225
    // COMPILE_OPTIONS are escaped.
1226
0
    this->AppendCompileOptions(flags, targetCompileOpts,
1227
0
                               langFlagRegexStr->c_str());
1228
0
  } else {
1229
    // Use all flags.
1230
0
    if (cmValue targetFlags = target->GetProperty("COMPILE_FLAGS")) {
1231
      // COMPILE_FLAGS are not escaped for historical reasons.
1232
0
      std::string compileFlags;
1233
0
      this->AppendFlags(compileFlags, *targetFlags);
1234
0
      if (!compileFlags.empty()) {
1235
0
        flags.emplace_back(std::move(compileFlags));
1236
0
      }
1237
0
    }
1238
0
    std::vector<BT<std::string>> targetCompileOpts =
1239
0
      target->GetCompileOptions(config, lang);
1240
    // COMPILE_OPTIONS are escaped.
1241
0
    this->AppendCompileOptions(flags, targetCompileOpts);
1242
0
  }
1243
1244
0
  cmStandardLevelResolver standardResolver(this->Makefile);
1245
0
  for (auto const& it : target->GetMaxLanguageStandards()) {
1246
0
    cmValue standard = target->GetLanguageStandard(it.first, config);
1247
0
    if (!standard) {
1248
0
      continue;
1249
0
    }
1250
0
    if (standardResolver.IsLaterStandard(it.first, *standard, it.second)) {
1251
0
      this->IssueMessage(
1252
0
        MessageType::FATAL_ERROR,
1253
0
        cmStrCat("The COMPILE_FEATURES property of target \"",
1254
0
                 target->GetName(),
1255
0
                 "\" was evaluated when computing the link "
1256
0
                 "implementation, and the \"",
1257
0
                 cmStandardLevelResolver::GetStandardPropertyName(it.first),
1258
0
                 "\" was \"", it.second,
1259
0
                 "\" for that computation.  Computing the "
1260
0
                 "COMPILE_FEATURES based on the link implementation resulted "
1261
0
                 "in a higher \"",
1262
0
                 cmStandardLevelResolver::GetStandardPropertyName(it.first),
1263
0
                 "\" \"", *standard,
1264
0
                 "\".  "
1265
0
                 "This is not permitted. The COMPILE_FEATURES may not both "
1266
0
                 "depend on "
1267
0
                 "and be depended on by the link implementation.\n"));
1268
0
      return;
1269
0
    }
1270
0
  }
1271
1272
  // Add Warning as errors flags
1273
0
  if (!this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) {
1274
0
    cmValue const wError = target->GetProperty("COMPILE_WARNING_AS_ERROR");
1275
0
    cmValue const wErrorOpts = this->Makefile->GetDefinition(
1276
0
      cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_WARNING_AS_ERROR"));
1277
0
    if (wError.IsOn() && wErrorOpts.IsSet()) {
1278
0
      std::string wErrorFlags;
1279
0
      this->AppendCompileOptions(wErrorFlags, *wErrorOpts);
1280
0
      if (!wErrorFlags.empty()) {
1281
0
        flags.emplace_back(std::move(wErrorFlags));
1282
0
      }
1283
0
    }
1284
0
  }
1285
1286
  // Add compile flag for the MSVC compiler only.
1287
0
  cmMakefile* mf = this->GetMakefile();
1288
0
  if (cmValue jmc =
1289
0
        mf->GetDefinition(cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_JMC"))) {
1290
1291
    // Handle Just My Code debugging flags, /JMC.
1292
    // If the target is a Managed C++ one, /JMC is not compatible.
1293
0
    if (target->GetManagedType(config) !=
1294
0
        cmGeneratorTarget::ManagedType::Managed) {
1295
      // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
1296
      // to ON
1297
0
      if (cmValue jmcExprGen =
1298
0
            target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
1299
0
        std::string isJMCEnabled =
1300
0
          cmGeneratorExpression::Evaluate(*jmcExprGen, this, config);
1301
0
        if (cmIsOn(isJMCEnabled)) {
1302
0
          cmList optList{ *jmc };
1303
0
          std::string jmcFlags;
1304
0
          this->AppendCompileOptions(jmcFlags, optList);
1305
0
          if (!jmcFlags.empty()) {
1306
0
            flags.emplace_back(std::move(jmcFlags));
1307
0
          }
1308
0
        }
1309
0
      }
1310
0
    }
1311
0
  }
1312
0
}
1313
1314
cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
1315
  std::string const& target, cmCustomCommandType type,
1316
  std::unique_ptr<cmCustomCommand> cc, cmObjectLibraryCommands objLibCommands)
1317
0
{
1318
0
  cmTarget* t = this->Makefile->GetCustomCommandTarget(
1319
0
    target, objLibCommands, this->DirectoryBacktrace);
1320
0
  if (!t) {
1321
0
    return nullptr;
1322
0
  }
1323
1324
0
  cc->SetBacktrace(this->DirectoryBacktrace);
1325
1326
0
  detail::AddCustomCommandToTarget(*this, cmCommandOrigin::Generator, t, type,
1327
0
                                   std::move(cc));
1328
1329
0
  return t;
1330
0
}
1331
1332
cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
1333
  std::unique_ptr<cmCustomCommand> cc, bool replace)
1334
0
{
1335
  // Make sure there is at least one output.
1336
0
  if (cc->GetOutputs().empty()) {
1337
0
    cmSystemTools::Error("Attempt to add a custom rule with no output!");
1338
0
    return nullptr;
1339
0
  }
1340
1341
0
  cc->SetBacktrace(this->DirectoryBacktrace);
1342
0
  return detail::AddCustomCommandToOutput(*this, cmCommandOrigin::Generator,
1343
0
                                          std::move(cc), replace);
1344
0
}
1345
1346
cmTarget* cmLocalGenerator::AddUtilityCommand(
1347
  std::string const& utilityName, bool excludeFromAll,
1348
  std::unique_ptr<cmCustomCommand> cc)
1349
0
{
1350
0
  cmTarget* target =
1351
0
    this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll);
1352
0
  target->SetIsGeneratorProvided(true);
1353
1354
0
  if (cc->GetCommandLines().empty() && cc->GetDepends().empty()) {
1355
0
    return target;
1356
0
  }
1357
1358
0
  cc->SetBacktrace(this->DirectoryBacktrace);
1359
0
  detail::AddUtilityCommand(*this, cmCommandOrigin::Generator, target,
1360
0
                            std::move(cc));
1361
1362
0
  return target;
1363
0
}
1364
1365
std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
1366
  cmGeneratorTarget const* target, std::string const& lang,
1367
  std::string const& config, bool stripImplicitDirs,
1368
  bool appendAllImplicitDirs) const
1369
0
{
1370
0
  std::vector<BT<std::string>> result;
1371
  // Do not repeat an include path.
1372
0
  std::set<std::string> emitted;
1373
1374
0
  auto emitDir = [&result, &emitted](std::string const& dir) {
1375
0
    if (emitted.insert(dir).second) {
1376
0
      result.emplace_back(dir);
1377
0
    }
1378
0
  };
1379
1380
0
  auto emitBT = [&result, &emitted](BT<std::string> const& dir) {
1381
0
    if (emitted.insert(dir.Value).second) {
1382
0
      result.emplace_back(dir);
1383
0
    }
1384
0
  };
1385
1386
  // When automatic include directories are requested for a build then
1387
  // include the source and binary directories at the beginning of the
1388
  // include path to approximate include file behavior for an
1389
  // in-source build.  This does not account for the case of a source
1390
  // file in a subdirectory of the current source directory but we
1391
  // cannot fix this because not all native build tools support
1392
  // per-source-file include paths.
1393
0
  if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR")) {
1394
    // Current binary directory
1395
0
    emitDir(this->StateSnapshot.GetDirectory().GetCurrentBinary());
1396
    // Current source directory
1397
0
    emitDir(this->StateSnapshot.GetDirectory().GetCurrentSource());
1398
0
  }
1399
1400
0
  if (!target) {
1401
0
    return result;
1402
0
  }
1403
1404
  // Standard include directories to be added unconditionally at the end.
1405
  // These are intended to simulate additional implicit include directories.
1406
0
  cmList userStandardDirs;
1407
0
  {
1408
0
    std::string const value = this->Makefile->GetSafeDefinition(
1409
0
      cmStrCat("CMAKE_", lang, "_STANDARD_INCLUDE_DIRECTORIES"));
1410
0
    userStandardDirs.assign(value);
1411
0
    for (std::string& usd : userStandardDirs) {
1412
0
      cmSystemTools::ConvertToUnixSlashes(usd);
1413
0
    }
1414
0
  }
1415
1416
  // Implicit include directories
1417
0
  std::vector<std::string> implicitDirs;
1418
0
  std::set<std::string> implicitSet;
1419
  // Include directories to be excluded as if they were implicit.
1420
0
  std::set<std::string> implicitExclude;
1421
0
  {
1422
    // Raw list of implicit include directories
1423
    // Start with "standard" directories that we unconditionally add below.
1424
0
    std::vector<std::string> impDirVec = userStandardDirs;
1425
1426
    // Load implicit include directories for this language.
1427
    // We ignore this for Fortran because:
1428
    // * There are no standard library headers to avoid overriding.
1429
    // * Compilers like gfortran do not search their own implicit include
1430
    //   directories for modules ('.mod' files).
1431
0
    if (lang != "Fortran") {
1432
0
      size_t const impDirVecOldSize = impDirVec.size();
1433
0
      cmList::append(impDirVec,
1434
0
                     this->Makefile->GetDefinition(cmStrCat(
1435
0
                       "CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES")));
1436
      // FIXME: Use cmRange with 'advance()' when it supports non-const.
1437
0
      for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) {
1438
0
        cmSystemTools::ConvertToUnixSlashes(impDirVec[i]);
1439
0
      }
1440
1441
      // The CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES are computed using
1442
      // try_compile in CMAKE_DETERMINE_COMPILER_ABI, but the implicit include
1443
      // directories are not known during that try_compile.  This can be a
1444
      // problem when the HIP runtime include path is /usr/include because the
1445
      // runtime include path is always added to the userDirs and the compiler
1446
      // includes standard library headers via "__clang_hip_runtime_wrapper.h".
1447
0
      if (lang == "HIP" && impDirVec.size() == impDirVecOldSize &&
1448
0
          !cm::contains(impDirVec, "/usr/include")) {
1449
0
        implicitExclude.emplace("/usr/include");
1450
0
      }
1451
0
    }
1452
1453
    // The Platform/UnixPaths module used to hard-code /usr/include for C, CXX,
1454
    // and CUDA in CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES, but those
1455
    // variables are now computed.  On macOS the /usr/include directory is
1456
    // inside the platform SDK so the computed value does not contain it
1457
    // directly.  In this case adding -I/usr/include can hide SDK headers so we
1458
    // must still exclude it.
1459
0
    if ((lang == "C" || lang == "CXX" || lang == "CUDA") &&
1460
0
        !cm::contains(impDirVec, "/usr/include") &&
1461
0
        std::find_if(impDirVec.begin(), impDirVec.end(),
1462
0
                     [](std::string const& d) {
1463
0
                       return cmHasLiteralSuffix(d, "/usr/include");
1464
0
                     }) != impDirVec.end()) {
1465
      // Only exclude this hard coded path for backwards compatibility.
1466
0
      implicitExclude.emplace("/usr/include");
1467
0
    }
1468
1469
0
    for (std::string const& i : impDirVec) {
1470
0
      if (implicitSet.insert(this->GlobalGenerator->GetRealPath(i)).second) {
1471
0
        implicitDirs.emplace_back(i);
1472
0
      }
1473
0
    }
1474
0
  }
1475
1476
0
  bool const isCorCxx = (lang == "C" || lang == "CXX" || lang == "SYCL");
1477
1478
  // Resolve symlinks in CPATH for comparison with resolved include paths.
1479
  // We do this here instead of when EnvCPATH is populated in case symlinks
1480
  // on disk have changed in the meantime.
1481
0
  std::set<std::string> resolvedEnvCPATH;
1482
0
  if (isCorCxx) {
1483
0
    for (std::string const& i : this->EnvCPATH) {
1484
0
      resolvedEnvCPATH.emplace(this->GlobalGenerator->GetRealPath(i));
1485
0
    }
1486
0
  }
1487
1488
  // Checks if this is not an excluded (implicit) include directory.
1489
0
  auto notExcluded = [this, &implicitSet, &implicitExclude, &resolvedEnvCPATH,
1490
0
                      isCorCxx](std::string const& dir) -> bool {
1491
0
    std::string const& real_dir = this->GlobalGenerator->GetRealPath(dir);
1492
0
    return
1493
      // Do not exclude directories that are not in any excluded set.
1494
0
      !(cm::contains(implicitSet, real_dir) ||
1495
0
        cm::contains(implicitExclude, dir))
1496
      // Do not exclude entries of the CPATH environment variable even though
1497
      // they are implicitly searched by the compiler.  They are meant to be
1498
      // user-specified directories that can be re-ordered or converted to
1499
      // -isystem without breaking real compiler builtin headers.
1500
0
      || (isCorCxx && cm::contains(resolvedEnvCPATH, real_dir));
1501
0
  };
1502
1503
  // Get the target-specific include directories.
1504
0
  std::vector<BT<std::string>> userDirs =
1505
0
    target->GetIncludeDirectories(config, lang);
1506
1507
  // Support putting all the in-project include directories first if
1508
  // it is requested by the project.
1509
0
  if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) {
1510
0
    std::string const& topSourceDir = this->GetState()->GetSourceDirectory();
1511
0
    std::string const& topBinaryDir = this->GetState()->GetBinaryDirectory();
1512
0
    for (BT<std::string> const& udr : userDirs) {
1513
      // Emit this directory only if it is a subdirectory of the
1514
      // top-level source or binary tree.
1515
0
      if (cmSystemTools::ComparePath(udr.Value, topSourceDir) ||
1516
0
          cmSystemTools::ComparePath(udr.Value, topBinaryDir) ||
1517
0
          cmSystemTools::IsSubDirectory(udr.Value, topSourceDir) ||
1518
0
          cmSystemTools::IsSubDirectory(udr.Value, topBinaryDir)) {
1519
0
        if (notExcluded(udr.Value)) {
1520
0
          emitBT(udr);
1521
0
        }
1522
0
      }
1523
0
    }
1524
0
  }
1525
1526
  // Emit remaining non implicit user directories.
1527
0
  for (BT<std::string> const& udr : userDirs) {
1528
0
    if (notExcluded(udr.Value)) {
1529
0
      emitBT(udr);
1530
0
    }
1531
0
  }
1532
1533
  // Sort result
1534
0
  MoveSystemIncludesToEnd(result, config, lang, target);
1535
1536
  // Append standard include directories for this language.
1537
0
  userDirs.reserve(userDirs.size() + userStandardDirs.size());
1538
0
  for (std::string& usd : userStandardDirs) {
1539
0
    emitDir(usd);
1540
0
    userDirs.emplace_back(std::move(usd));
1541
0
  }
1542
1543
  // Append compiler implicit include directories
1544
0
  if (!stripImplicitDirs) {
1545
    // Append implicit directories that were requested by the user only
1546
0
    for (BT<std::string> const& udr : userDirs) {
1547
0
      if (cm::contains(implicitSet,
1548
0
                       this->GlobalGenerator->GetRealPath(udr.Value))) {
1549
0
        emitBT(udr);
1550
0
      }
1551
0
    }
1552
    // Append remaining implicit directories (on demand)
1553
0
    if (appendAllImplicitDirs) {
1554
0
      for (std::string& imd : implicitDirs) {
1555
0
        emitDir(imd);
1556
0
      }
1557
0
    }
1558
0
  }
1559
1560
0
  return result;
1561
0
}
1562
1563
void cmLocalGenerator::GetIncludeDirectoriesImplicit(
1564
  std::vector<std::string>& dirs, cmGeneratorTarget const* target,
1565
  std::string const& lang, std::string const& config, bool stripImplicitDirs,
1566
  bool appendAllImplicitDirs) const
1567
0
{
1568
0
  std::vector<BT<std::string>> tmp = this->GetIncludeDirectoriesImplicit(
1569
0
    target, lang, config, stripImplicitDirs, appendAllImplicitDirs);
1570
0
  dirs.reserve(dirs.size() + tmp.size());
1571
0
  for (BT<std::string>& v : tmp) {
1572
0
    dirs.emplace_back(std::move(v.Value));
1573
0
  }
1574
0
}
1575
1576
std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectories(
1577
  cmGeneratorTarget const* target, std::string const& lang,
1578
  std::string const& config) const
1579
0
{
1580
0
  return this->GetIncludeDirectoriesImplicit(target, lang, config);
1581
0
}
1582
1583
void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
1584
                                             cmGeneratorTarget const* target,
1585
                                             std::string const& lang,
1586
                                             std::string const& config) const
1587
0
{
1588
0
  this->GetIncludeDirectoriesImplicit(dirs, target, lang, config);
1589
0
}
1590
1591
void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
1592
                                             std::string const& config,
1593
                                             std::string const& linkLanguage,
1594
                                             cmGeneratorTarget* target)
1595
0
{
1596
0
  std::vector<BT<std::string>> tmpFlags =
1597
0
    this->GetStaticLibraryFlags(config, linkLanguage, target);
1598
0
  this->AppendFlags(flags, tmpFlags);
1599
0
}
1600
1601
std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
1602
  std::string const& config, std::string const& linkLanguage,
1603
  cmGeneratorTarget* target)
1604
0
{
1605
0
  std::vector<BT<std::string>> flags;
1606
0
  if (linkLanguage != "Swift" && !this->IsSplitSwiftBuild()) {
1607
0
    std::string staticLibFlags;
1608
0
    this->AddConfigVariableFlags(staticLibFlags, "CMAKE_STATIC_LINKER_FLAGS",
1609
0
                                 config);
1610
0
    if (!staticLibFlags.empty()) {
1611
0
      flags.emplace_back(std::move(staticLibFlags));
1612
0
    }
1613
0
  }
1614
1615
0
  std::string staticLibFlags;
1616
0
  std::string const configUpper = cmSystemTools::UpperCase(config);
1617
0
  this->AppendFlags(staticLibFlags,
1618
0
                    target->GetSafeProperty("STATIC_LIBRARY_FLAGS"));
1619
0
  if (!configUpper.empty()) {
1620
0
    std::string name = "STATIC_LIBRARY_FLAGS_" + configUpper;
1621
0
    this->AppendFlags(staticLibFlags, target->GetSafeProperty(name));
1622
0
  }
1623
1624
0
  if (!staticLibFlags.empty()) {
1625
0
    flags.emplace_back(std::move(staticLibFlags));
1626
0
  }
1627
1628
0
  std::vector<BT<std::string>> staticLibOpts =
1629
0
    target->GetStaticLibraryLinkOptions(config, linkLanguage);
1630
  // STATIC_LIBRARY_OPTIONS are escaped.
1631
0
  this->AppendCompileOptions(flags, staticLibOpts);
1632
1633
0
  return flags;
1634
0
}
1635
1636
void cmLocalGenerator::GetDeviceLinkFlags(
1637
  cmLinkLineDeviceComputer& linkLineComputer, std::string const& config,
1638
  std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath,
1639
  std::string& linkPath, cmGeneratorTarget* target)
1640
0
{
1641
0
  cmGeneratorTarget::DeviceLinkSetter setter(*target);
1642
1643
0
  cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
1644
1645
0
  auto linklang = linkLineComputer.GetLinkerLanguage(target, config);
1646
0
  auto ipoEnabled = target->IsIPOEnabled(linklang, config);
1647
0
  if (!ipoEnabled && pcli) {
1648
0
    ipoEnabled = linkLineComputer.ComputeRequiresDeviceLinkingIPOFlag(*pcli);
1649
0
  }
1650
0
  if (ipoEnabled) {
1651
0
    if (cmValue cudaIPOFlags = this->Makefile->GetDefinition(
1652
0
          cmStrCat("CMAKE_", linklang, "_DEVICE_LINK_OPTIONS_IPO"))) {
1653
0
      linkFlags += *cudaIPOFlags;
1654
0
    }
1655
0
  }
1656
1657
0
  if (pcli) {
1658
    // Compute the required device link libraries when
1659
    // resolving gpu lang device symbols
1660
0
    this->OutputLinkLibraries(pcli, &linkLineComputer, linkLibs, frameworkPath,
1661
0
                              linkPath);
1662
0
  }
1663
1664
0
  this->AddVisibilityPresetFlags(linkFlags, target, linklang);
1665
0
  this->GetGlobalGenerator()->EncodeLiteral(linkFlags);
1666
1667
0
  std::vector<std::string> linkOpts;
1668
0
  target->GetLinkOptions(linkOpts, config, linklang);
1669
0
  this->SetLinkScriptShell(this->GetGlobalGenerator()->GetUseLinkScript());
1670
  // LINK_OPTIONS are escaped.
1671
0
  this->AppendCompileOptions(linkFlags, linkOpts);
1672
0
  this->SetLinkScriptShell(false);
1673
0
}
1674
1675
void cmLocalGenerator::GetTargetFlags(
1676
  cmLinkLineComputer* linkLineComputer, std::string const& config,
1677
  std::string& linkLibs, std::string& flags, std::string& linkFlags,
1678
  std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target)
1679
0
{
1680
0
  std::vector<BT<std::string>> linkFlagsList;
1681
0
  std::vector<BT<std::string>> linkPathList;
1682
0
  std::vector<BT<std::string>> linkLibsList;
1683
0
  this->GetTargetFlags(linkLineComputer, config, linkLibsList, flags,
1684
0
                       linkFlagsList, frameworkPath, linkPathList, target);
1685
0
  this->AppendFlags(linkFlags, linkFlagsList);
1686
0
  this->AppendFlags(linkPath, linkPathList);
1687
0
  this->AppendFlags(linkLibs, linkLibsList);
1688
0
}
1689
1690
void cmLocalGenerator::GetTargetFlags(
1691
  cmLinkLineComputer* linkLineComputer, std::string const& config,
1692
  std::vector<BT<std::string>>& linkLibs, std::string& flags,
1693
  std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath,
1694
  std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target)
1695
0
{
1696
0
  std::string const configUpper = cmSystemTools::UpperCase(config);
1697
0
  cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
1698
1699
0
  std::string const linkLanguage =
1700
0
    linkLineComputer->GetLinkerLanguage(target, config);
1701
1702
0
  {
1703
0
    std::string createFlags;
1704
0
    this->AppendTargetCreationLinkFlags(createFlags, target, linkLanguage);
1705
0
    if (!createFlags.empty()) {
1706
0
      linkFlags.emplace_back(std::move(createFlags));
1707
0
    }
1708
0
  }
1709
1710
0
  switch (target->GetType()) {
1711
0
    case cm::TargetType::STATIC_LIBRARY:
1712
0
      linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target);
1713
0
      break;
1714
0
    case cm::TargetType::MODULE_LIBRARY:
1715
0
      CM_FALLTHROUGH;
1716
0
    case cm::TargetType::SHARED_LIBRARY: {
1717
0
      if (this->IsSplitSwiftBuild() || linkLanguage != "Swift") {
1718
0
        std::string libFlags;
1719
0
        this->AddTargetTypeLinkerFlags(libFlags, target, linkLanguage, config);
1720
0
        if (!libFlags.empty()) {
1721
0
          linkFlags.emplace_back(std::move(libFlags));
1722
0
        }
1723
0
      }
1724
1725
0
      std::string langLinkFlags;
1726
0
      this->AddPerLanguageLinkFlags(langLinkFlags, target, linkLanguage,
1727
0
                                    config);
1728
0
      if (!langLinkFlags.empty()) {
1729
0
        linkFlags.emplace_back(std::move(langLinkFlags));
1730
0
      }
1731
1732
0
      std::string sharedLibFlags;
1733
0
      this->AddTargetPropertyLinkFlags(sharedLibFlags, target, config);
1734
0
      if (!sharedLibFlags.empty()) {
1735
0
        this->GetGlobalGenerator()->EncodeLiteral(sharedLibFlags);
1736
0
        linkFlags.emplace_back(std::move(sharedLibFlags));
1737
0
      }
1738
1739
0
      std::vector<BT<std::string>> linkOpts =
1740
0
        target->GetLinkOptions(config, linkLanguage);
1741
0
      this->SetLinkScriptShell(this->GetGlobalGenerator()->GetUseLinkScript());
1742
      // LINK_OPTIONS are escaped.
1743
0
      this->AppendCompileOptions(linkFlags, linkOpts);
1744
0
      this->SetLinkScriptShell(false);
1745
1746
0
      if (pcli) {
1747
0
        this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
1748
0
                                  frameworkPath, linkPath);
1749
0
      }
1750
0
    } break;
1751
0
    case cm::TargetType::EXECUTABLE: {
1752
0
      if (linkLanguage != "Swift" ||
1753
0
          (this->IsSplitSwiftBuild() &&
1754
0
           target->GetPolicyStatusCMP0214() == cmPolicies::NEW)) {
1755
0
        std::string exeFlags;
1756
0
        this->AddTargetTypeLinkerFlags(exeFlags, target, linkLanguage, config);
1757
0
        if (!exeFlags.empty()) {
1758
0
          linkFlags.emplace_back(std::move(exeFlags));
1759
0
        }
1760
0
      }
1761
1762
0
      std::string langLinkFlags;
1763
0
      this->AddPerLanguageLinkFlags(langLinkFlags, target, linkLanguage,
1764
0
                                    config);
1765
0
      if (!langLinkFlags.empty()) {
1766
0
        linkFlags.emplace_back(std::move(langLinkFlags));
1767
0
      }
1768
1769
0
      {
1770
0
        auto exeType = cmStrCat(
1771
0
          "CMAKE_", linkLanguage, "_CREATE_",
1772
0
          (target->IsWin32Executable(config) ? "WIN32" : "CONSOLE"), "_EXE");
1773
0
        std::string exeFlags;
1774
0
        this->AppendFlags(exeFlags, this->Makefile->GetDefinition(exeType),
1775
0
                          exeType, target, cmBuildStep::Link, linkLanguage);
1776
0
        if (!exeFlags.empty()) {
1777
0
          linkFlags.emplace_back(std::move(exeFlags));
1778
0
        }
1779
0
      }
1780
1781
0
      std::string exeFlags;
1782
0
      if (target->IsExecutableWithExports()) {
1783
0
        exeFlags += this->Makefile->GetSafeDefinition(
1784
0
          cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG"));
1785
0
        exeFlags += " ";
1786
0
      }
1787
1788
0
      this->AddLanguageFlagsForLinking(flags, target, linkLanguage, config);
1789
0
      if (pcli) {
1790
0
        this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
1791
0
                                  frameworkPath, linkPath);
1792
0
      }
1793
1794
0
      if (this->Makefile->IsOn("BUILD_SHARED_LIBS")) {
1795
0
        std::string sFlagVar =
1796
0
          cmStrCat("CMAKE_SHARED_BUILD_", linkLanguage, "_FLAGS");
1797
0
        exeFlags += this->Makefile->GetSafeDefinition(sFlagVar);
1798
0
        exeFlags += " ";
1799
0
      }
1800
1801
0
      std::string exeExportFlags =
1802
0
        this->GetExeExportFlags(linkLanguage, *target);
1803
0
      if (!exeExportFlags.empty()) {
1804
0
        exeFlags += exeExportFlags;
1805
0
        exeFlags += " ";
1806
0
      }
1807
1808
0
      this->AddTargetPropertyLinkFlags(exeFlags, target, config);
1809
1810
0
      if (!exeFlags.empty()) {
1811
0
        this->GetGlobalGenerator()->EncodeLiteral(exeFlags);
1812
0
        linkFlags.emplace_back(std::move(exeFlags));
1813
0
      }
1814
1815
0
      std::vector<BT<std::string>> linkOpts =
1816
0
        target->GetLinkOptions(config, linkLanguage);
1817
0
      this->SetLinkScriptShell(this->GetGlobalGenerator()->GetUseLinkScript());
1818
      // LINK_OPTIONS are escaped.
1819
0
      this->AppendCompileOptions(linkFlags, linkOpts);
1820
0
      this->SetLinkScriptShell(false);
1821
0
    } break;
1822
0
    default:
1823
0
      break;
1824
0
  }
1825
1826
0
  std::string extraLinkFlags;
1827
0
  this->AppendLinkerTypeFlags(extraLinkFlags, target, config, linkLanguage);
1828
0
  this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config,
1829
0
                                             linkLanguage);
1830
0
  this->AppendWarningAsErrorLinkerFlags(extraLinkFlags, target, linkLanguage);
1831
0
  this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage);
1832
0
  this->AppendModuleDefinitionFlag(extraLinkFlags, target, linkLineComputer,
1833
0
                                   config, linkLanguage);
1834
1835
0
  if (!extraLinkFlags.empty()) {
1836
0
    this->GetGlobalGenerator()->EncodeLiteral(extraLinkFlags);
1837
0
    linkFlags.emplace_back(std::move(extraLinkFlags));
1838
0
  }
1839
0
}
1840
1841
void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
1842
                                             std::string const& config,
1843
                                             std::string const& lang,
1844
                                             std::string& flags,
1845
                                             std::string const& arch)
1846
0
{
1847
0
  std::vector<BT<std::string>> tmpFlags =
1848
0
    this->GetTargetCompileFlags(target, config, lang, arch);
1849
0
  this->AppendFlags(flags, tmpFlags);
1850
0
}
1851
1852
std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags(
1853
  cmGeneratorTarget* target, std::string const& config,
1854
  std::string const& lang, std::string const& arch)
1855
0
{
1856
0
  std::vector<BT<std::string>> flags;
1857
0
  std::string compileFlags;
1858
1859
0
  cmMakefile* mf = this->GetMakefile();
1860
1861
  // Add language-specific flags.
1862
0
  this->AddLanguageFlags(compileFlags, target, cmBuildStep::Compile, lang,
1863
0
                         config);
1864
1865
0
  if (target->IsIPOEnabled(lang, config)) {
1866
0
    this->AppendFeatureOptions(compileFlags, lang, "IPO");
1867
0
  }
1868
1869
0
  this->AddArchitectureFlags(compileFlags, target, lang, config, arch);
1870
1871
0
  if (lang == "Fortran") {
1872
0
    this->AppendFlags(compileFlags,
1873
0
                      this->GetTargetFortranFlags(target, config));
1874
0
  } else if (lang == "Swift") {
1875
    // Only set the compile mode if CMP0157 is set
1876
0
    if (cm::optional<cmSwiftCompileMode> swiftCompileMode =
1877
0
          this->GetSwiftCompileMode(target, config)) {
1878
0
      std::string swiftCompileModeFlag;
1879
0
      switch (*swiftCompileMode) {
1880
0
        case cmSwiftCompileMode::Incremental: {
1881
0
          swiftCompileModeFlag = "-incremental";
1882
0
          if (cmValue flag =
1883
0
                mf->GetDefinition("CMAKE_Swift_COMPILE_OPTIONS_INCREMENTAL")) {
1884
0
            swiftCompileModeFlag = *flag;
1885
0
          }
1886
0
          break;
1887
0
        }
1888
0
        case cmSwiftCompileMode::Wholemodule: {
1889
0
          swiftCompileModeFlag = "-wmo";
1890
0
          if (cmValue flag =
1891
0
                mf->GetDefinition("CMAKE_Swift_COMPILE_OPTIONS_WMO")) {
1892
0
            swiftCompileModeFlag = *flag;
1893
0
          }
1894
0
          break;
1895
0
        }
1896
0
        case cmSwiftCompileMode::Singlefile:
1897
0
          break;
1898
0
        case cmSwiftCompileMode::Unknown: {
1899
0
          this->IssueDiagnostic(
1900
0
            cmDiagnostics::CMD_AUTHOR,
1901
0
            cmStrCat("Unknown Swift_COMPILATION_MODE on target '",
1902
0
                     target->GetName(), '\''));
1903
0
        }
1904
0
      }
1905
0
      this->AppendFlags(compileFlags, swiftCompileModeFlag);
1906
0
    }
1907
0
  }
1908
1909
0
  this->AddFeatureFlags(compileFlags, target, lang, config);
1910
0
  this->AddVisibilityPresetFlags(compileFlags, target, lang);
1911
0
  this->AddColorDiagnosticsFlags(compileFlags, lang);
1912
0
  this->AppendFlags(compileFlags, mf->GetDefineFlags());
1913
0
  this->AppendFlags(compileFlags,
1914
0
                    this->GetFrameworkFlags(lang, config, target));
1915
0
  this->AppendFlags(compileFlags,
1916
0
                    this->GetXcFrameworkFlags(lang, config, target));
1917
1918
0
  if (!compileFlags.empty()) {
1919
0
    flags.emplace_back(std::move(compileFlags));
1920
0
  }
1921
0
  this->AddCompileOptions(flags, target, lang, config);
1922
0
  return flags;
1923
0
}
1924
1925
std::string cmLocalGenerator::GetFrameworkFlags(std::string const& lang,
1926
                                                std::string const& config,
1927
                                                cmGeneratorTarget* target)
1928
0
{
1929
0
  cmLocalGenerator* lg = target->GetLocalGenerator();
1930
0
  cmMakefile* mf = lg->GetMakefile();
1931
1932
0
  if (!target->IsApple()) {
1933
0
    return std::string();
1934
0
  }
1935
1936
0
  cmValue fwSearchFlag =
1937
0
    mf->GetDefinition(cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG"));
1938
0
  cmValue sysFwSearchFlag = mf->GetDefinition(
1939
0
    cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
1940
1941
0
  if (!fwSearchFlag && !sysFwSearchFlag) {
1942
0
    return std::string{};
1943
0
  }
1944
1945
0
  std::set<std::string> emitted;
1946
#ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */
1947
  emitted.insert("/System/Library/Frameworks");
1948
#endif
1949
0
  std::vector<std::string> includes;
1950
1951
0
  lg->GetIncludeDirectories(includes, target, "C", config);
1952
  // check all include directories for frameworks as this
1953
  // will already have added a -F for the framework
1954
0
  for (std::string const& include : includes) {
1955
0
    if (lg->GetGlobalGenerator()->NameResolvesToFramework(include)) {
1956
0
      std::string frameworkDir = cmStrCat(include, "/../");
1957
0
      frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
1958
0
      emitted.insert(frameworkDir);
1959
0
    }
1960
0
  }
1961
1962
0
  std::string flags;
1963
0
  if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) {
1964
0
    std::vector<std::string> const& frameworks = cli->GetFrameworkPaths();
1965
0
    for (std::string const& framework : frameworks) {
1966
0
      if (emitted.insert(framework).second) {
1967
0
        if (sysFwSearchFlag &&
1968
0
            target->IsSystemIncludeDirectory(framework, config, lang)) {
1969
0
          flags += *sysFwSearchFlag;
1970
0
        } else {
1971
0
          flags += *fwSearchFlag;
1972
0
        }
1973
0
        flags +=
1974
0
          lg->ConvertToOutputFormat(framework, cmOutputConverter::SHELL);
1975
0
        flags += " ";
1976
0
      }
1977
0
    }
1978
0
  }
1979
0
  return flags;
1980
0
}
1981
1982
std::string cmLocalGenerator::GetXcFrameworkFlags(std::string const& lang,
1983
                                                  std::string const& config,
1984
                                                  cmGeneratorTarget* target)
1985
0
{
1986
0
  cmLocalGenerator* lg = target->GetLocalGenerator();
1987
0
  cmMakefile* mf = lg->GetMakefile();
1988
1989
0
  if (!target->IsApple()) {
1990
0
    return std::string();
1991
0
  }
1992
1993
0
  cmValue includeSearchFlag =
1994
0
    mf->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
1995
0
  cmValue sysIncludeSearchFlag =
1996
0
    mf->GetDefinition(cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
1997
1998
0
  if (!includeSearchFlag && !sysIncludeSearchFlag) {
1999
0
    return std::string{};
2000
0
  }
2001
2002
0
  std::string flags;
2003
0
  if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) {
2004
0
    std::vector<std::string> const& paths = cli->GetXcFrameworkHeaderPaths();
2005
0
    for (std::string const& path : paths) {
2006
0
      if (sysIncludeSearchFlag &&
2007
0
          target->IsSystemIncludeDirectory(path, config, lang)) {
2008
0
        flags += *sysIncludeSearchFlag;
2009
0
      } else {
2010
0
        flags += *includeSearchFlag;
2011
0
      }
2012
0
      flags += lg->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
2013
0
      flags += " ";
2014
0
    }
2015
0
  }
2016
0
  return flags;
2017
0
}
2018
2019
void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target,
2020
                                        std::string const& config,
2021
                                        std::string const& lang,
2022
                                        std::set<std::string>& defines) const
2023
0
{
2024
0
  std::set<BT<std::string>> tmp = this->GetTargetDefines(target, config, lang);
2025
0
  for (BT<std::string> const& v : tmp) {
2026
0
    defines.emplace(v.Value);
2027
0
  }
2028
0
}
2029
2030
std::set<BT<std::string>> cmLocalGenerator::GetTargetDefines(
2031
  cmGeneratorTarget const* target, std::string const& config,
2032
  std::string const& lang) const
2033
0
{
2034
0
  std::set<BT<std::string>> defines;
2035
2036
  // Add the export symbol definition for shared library objects.
2037
0
  if (std::string const* exportMacro = target->GetExportMacro()) {
2038
0
    this->AppendDefines(defines, *exportMacro);
2039
0
  }
2040
0
  for (auto const& sharedLibCompileDef :
2041
0
       target->GetSharedLibraryCompileDefs(config)) {
2042
0
    this->AppendDefines(defines, sharedLibCompileDef);
2043
0
  }
2044
2045
  // Add preprocessor definitions for this target and configuration.
2046
0
  std::vector<BT<std::string>> targetDefines =
2047
0
    target->GetCompileDefinitions(config, lang);
2048
0
  this->AppendDefines(defines, targetDefines);
2049
2050
0
  return defines;
2051
0
}
2052
2053
std::string cmLocalGenerator::GetTargetFortranFlags(
2054
  cmGeneratorTarget const* /*unused*/, std::string const& /*unused*/)
2055
0
{
2056
  // Implemented by specific generators that override this.
2057
0
  return std::string();
2058
0
}
2059
2060
/**
2061
 * Output the linking rules on a command line.  For executables,
2062
 * targetLibrary should be a NULL pointer.  For libraries, it should point
2063
 * to the name of the library.  This will not link a library against itself.
2064
 */
2065
void cmLocalGenerator::OutputLinkLibraries(
2066
  cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
2067
  std::string& linkLibraries, std::string& frameworkPath,
2068
  std::string& linkPath)
2069
0
{
2070
0
  std::vector<BT<std::string>> linkLibrariesList;
2071
0
  std::vector<BT<std::string>> linkPathList;
2072
0
  this->OutputLinkLibraries(pcli, linkLineComputer, linkLibrariesList,
2073
0
                            frameworkPath, linkPathList);
2074
0
  pcli->AppendValues(linkLibraries, linkLibrariesList);
2075
0
  pcli->AppendValues(linkPath, linkPathList);
2076
0
}
2077
2078
void cmLocalGenerator::OutputLinkLibraries(
2079
  cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
2080
  std::vector<BT<std::string>>& linkLibraries, std::string& frameworkPath,
2081
  std::vector<BT<std::string>>& linkPath)
2082
0
{
2083
0
  cmComputeLinkInformation& cli = *pcli;
2084
2085
0
  std::string linkLanguage = cli.GetLinkLanguage();
2086
2087
0
  std::string libPathFlag;
2088
0
  if (cmValue value = this->Makefile->GetDefinition(
2089
0
        cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_LIBRARY_PATH_FLAG"))) {
2090
0
    libPathFlag = *value;
2091
0
  } else {
2092
0
    libPathFlag =
2093
0
      this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
2094
0
  }
2095
2096
0
  std::string libPathTerminator;
2097
0
  if (cmValue value = this->Makefile->GetDefinition(cmStrCat(
2098
0
        "CMAKE_", cli.GetLinkLanguage(), "_LIBRARY_PATH_TERMINATOR"))) {
2099
0
    libPathTerminator = *value;
2100
0
  } else {
2101
0
    libPathTerminator =
2102
0
      this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
2103
0
  }
2104
2105
  // Add standard link directories for this language
2106
0
  std::string stdLinkDirString = this->Makefile->GetSafeDefinition(
2107
0
    cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_STANDARD_LINK_DIRECTORIES"));
2108
2109
  // Add standard libraries for this language.
2110
0
  std::string stdLibString = this->Makefile->GetSafeDefinition(
2111
0
    cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_STANDARD_LIBRARIES"));
2112
2113
  // Append the framework search path flags.
2114
0
  cmValue fwSearchFlag = this->Makefile->GetDefinition(
2115
0
    cmStrCat("CMAKE_", linkLanguage, "_FRAMEWORK_SEARCH_FLAG"));
2116
2117
0
  frameworkPath = linkLineComputer->ComputeFrameworkPath(cli, fwSearchFlag);
2118
0
  linkLineComputer->ComputeLinkPath(cli, libPathFlag, libPathTerminator,
2119
0
                                    stdLinkDirString, linkPath);
2120
0
  linkLineComputer->ComputeLinkLibraries(cli, stdLibString, linkLibraries);
2121
0
}
2122
2123
std::string cmLocalGenerator::GetExeExportFlags(
2124
  std::string const& linkLanguage, cmGeneratorTarget& tgt) const
2125
0
{
2126
0
  std::string linkFlags;
2127
2128
  // Flags to export symbols from an executable.
2129
0
  if (tgt.GetType() == cm::TargetType::EXECUTABLE &&
2130
0
      this->StateSnapshot.GetState()->GetGlobalPropertyAsBool(
2131
0
        "TARGET_SUPPORTS_SHARED_LIBS")) {
2132
    // Only add the flags if ENABLE_EXPORTS is on,
2133
    // except on AIX where we compute symbol exports.
2134
0
    if (!tgt.IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS")) {
2135
0
      linkFlags = this->Makefile->GetSafeDefinition(
2136
0
        cmStrCat("CMAKE_SHARED_LIBRARY_LINK_", linkLanguage, "_FLAGS"));
2137
0
    }
2138
0
  }
2139
0
  return linkFlags;
2140
0
}
2141
2142
bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame(
2143
  std::vector<std::string> const& archs, cmValue sysroot)
2144
0
{
2145
0
  if (!sysroot) {
2146
0
    return false;
2147
0
  }
2148
2149
0
  return std::all_of(archs.begin(), archs.end(),
2150
0
                     [this, sysroot](std::string const& arch) -> bool {
2151
0
                       std::string const& archSysroot =
2152
0
                         this->AppleArchSysroots[arch];
2153
0
                       return cmIsOff(archSysroot) || *sysroot == archSysroot;
2154
0
                     });
2155
0
}
2156
2157
void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
2158
                                            cmGeneratorTarget const* target,
2159
                                            std::string const& lang,
2160
                                            std::string const& config,
2161
                                            std::string const& filterArch)
2162
0
{
2163
  // Only add Apple specific flags on Apple platforms
2164
0
  if (target->IsApple() && this->EmitUniversalBinaryFlags) {
2165
0
    std::vector<std::string> archs = target->GetAppleArchs(config, lang);
2166
0
    if (!archs.empty() &&
2167
0
        (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX" ||
2168
0
         lang == "ASM" || lang == "SYCL")) {
2169
0
      for (std::string const& arch : archs) {
2170
0
        if (filterArch.empty() || filterArch == arch) {
2171
0
          flags += " -arch ";
2172
0
          flags += arch;
2173
0
        }
2174
0
      }
2175
0
    }
2176
2177
0
    cmValue sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
2178
0
    if (sysroot.IsEmpty() &&
2179
0
        this->Makefile->IsOn(
2180
0
          cmStrCat("CMAKE_", lang, "_COMPILER_APPLE_SYSROOT_REQUIRED"))) {
2181
0
      sysroot = this->Makefile->GetDefinition("_CMAKE_OSX_SYSROOT_PATH");
2182
0
    }
2183
0
    if (sysroot && *sysroot == "/") {
2184
0
      sysroot = nullptr;
2185
0
    }
2186
0
    std::string sysrootFlagVar = cmStrCat("CMAKE_", lang, "_SYSROOT_FLAG");
2187
0
    cmValue sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
2188
0
    if (cmNonempty(sysrootFlag)) {
2189
0
      if (!this->AppleArchSysroots.empty() &&
2190
0
          !this->AllAppleArchSysrootsAreTheSame(archs, sysroot)) {
2191
0
        for (std::string const& arch : archs) {
2192
0
          std::string const& archSysroot = this->AppleArchSysroots[arch];
2193
0
          if (cmIsOff(archSysroot)) {
2194
0
            continue;
2195
0
          }
2196
0
          if (filterArch.empty() || filterArch == arch) {
2197
0
            flags = cmStrCat(std::move(flags), " -Xarch_", arch, ' ');
2198
            // Combine sysroot flag and path to work with -Xarch
2199
0
            std::string arch_sysroot = *sysrootFlag + archSysroot;
2200
0
            flags += this->ConvertToOutputFormat(arch_sysroot, SHELL);
2201
0
          }
2202
0
        }
2203
0
      } else if (cmNonempty(sysroot)) {
2204
0
        flags += " ";
2205
0
        flags += *sysrootFlag;
2206
0
        flags += " ";
2207
0
        flags += this->ConvertToOutputFormat(*sysroot, SHELL);
2208
0
      }
2209
0
    }
2210
2211
0
    cmValue deploymentTarget =
2212
0
      this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
2213
0
    if (cmNonempty(deploymentTarget)) {
2214
0
      std::string deploymentTargetFlagVar =
2215
0
        cmStrCat("CMAKE_", lang, "_OSX_DEPLOYMENT_TARGET_FLAG");
2216
0
      cmValue deploymentTargetFlag =
2217
0
        this->Makefile->GetDefinition(deploymentTargetFlagVar);
2218
0
      if (cmNonempty(deploymentTargetFlag) &&
2219
          // CMAKE_<LANG>_COMPILER_TARGET overrides a --target= for
2220
          // CMAKE_OSX_DEPLOYMENT_TARGET, e.g., for visionOS.
2221
0
          (!cmHasLiteralPrefix(*deploymentTarget, "--target=") ||
2222
0
           this->Makefile
2223
0
             ->GetDefinition(cmStrCat("CMAKE_", lang, "_COMPILER_TARGET"))
2224
0
             .IsEmpty())) {
2225
0
        std::string flag = *deploymentTargetFlag;
2226
2227
        // Add the deployment target architecture to the flag, if needed.
2228
0
        static std::string const kARCH = "<ARCH>";
2229
0
        std::string::size_type archPos = flag.find(kARCH);
2230
0
        if (archPos != std::string::npos) {
2231
          // This placeholder is meant for visionOS, so default to arm64
2232
          // unless only non-arm64 archs are given.
2233
0
          std::string const arch =
2234
0
            (archs.empty() || cm::contains(archs, "arm64")) ? "arm64"
2235
0
                                                            : archs[0];
2236
          // Replace the placeholder with its value.
2237
0
          flag = cmStrCat(flag.substr(0, archPos), arch,
2238
0
                          flag.substr(archPos + kARCH.size()));
2239
0
        }
2240
2241
        // Add the deployment target version to the flag.
2242
0
        static std::string const kVERSION_MIN = "<VERSION_MIN>";
2243
0
        std::string::size_type verPos = flag.find(kVERSION_MIN);
2244
0
        if (verPos != std::string::npos) {
2245
          // Replace the placeholder with its value.
2246
0
          flag = cmStrCat(flag.substr(0, verPos), *deploymentTarget,
2247
0
                          flag.substr(verPos + kVERSION_MIN.size()));
2248
0
        } else {
2249
          // There is no placeholder, so append the value.
2250
0
          flag = cmStrCat(std::move(flag), *deploymentTarget);
2251
0
        }
2252
2253
0
        flags += " ";
2254
0
        flags += flag;
2255
0
      }
2256
0
    }
2257
0
  }
2258
0
}
2259
2260
void cmLocalGenerator::AddLanguageFlags(std::string& flags,
2261
                                        cmGeneratorTarget const* target,
2262
                                        cmBuildStep compileOrLink,
2263
                                        std::string const& lang,
2264
                                        std::string const& config)
2265
0
{
2266
0
  if (target->IsSYCLAppendMode(lang)) {
2267
0
    this->AddConfigVariableFlags(flags, "CMAKE_CXX_FLAGS", config);
2268
    // Defaults initialized from the same source need only be applied once,
2269
    // otherwise retain both strings verbatim.
2270
0
    auto const appendSYCLFlags = [this, &flags](std::string const& suffix) {
2271
0
      auto const& syclFlags =
2272
0
        this->Makefile->GetDefinition(cmStrCat("CMAKE_SYCL_FLAGS", suffix));
2273
0
      if (syclFlags !=
2274
0
          this->Makefile->GetDefinition(cmStrCat("CMAKE_CXX_FLAGS", suffix))) {
2275
0
        this->AppendFlags(flags, syclFlags);
2276
0
      }
2277
0
    };
2278
0
    appendSYCLFlags("");
2279
0
    if (!config.empty()) {
2280
0
      appendSYCLFlags(cmStrCat('_', cmSystemTools::UpperCase(config)));
2281
0
    }
2282
0
  } else {
2283
0
    this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"),
2284
0
                                 config);
2285
0
  }
2286
2287
  // Add the language standard flag for compiling, and sometimes linking.
2288
0
  if (compileOrLink == cmBuildStep::Compile ||
2289
0
      (compileOrLink == cmBuildStep::Link &&
2290
       // Some toolchains require use of the language standard flag
2291
       // when linking in order to use the matching standard library.
2292
       // FIXME: If CMake gains an abstraction for standard library
2293
       // selection, this will have to be reconciled with it.
2294
0
       this->Makefile->IsOn(
2295
0
         cmStrCat("CMAKE_", lang, "_LINK_WITH_STANDARD_COMPILE_OPTION")))) {
2296
0
    cmStandardLevelResolver standardResolver(this->Makefile);
2297
0
    std::string const& optionFlagDef =
2298
0
      standardResolver.GetCompileOptionDef(target, lang, config);
2299
0
    if (!optionFlagDef.empty()) {
2300
0
      cmValue opt =
2301
0
        target->Target->GetMakefile()->GetDefinition(optionFlagDef);
2302
0
      if (opt) {
2303
0
        cmList optList{ *opt };
2304
0
        for (std::string const& i : optList) {
2305
0
          this->AppendFlagEscape(flags, i);
2306
0
        }
2307
0
      }
2308
0
    }
2309
0
  }
2310
2311
0
  std::string compilerId = this->Makefile->GetSafeDefinition(
2312
0
    cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
2313
2314
0
  std::string compilerSimulateId = this->Makefile->GetSafeDefinition(
2315
0
    cmStrCat("CMAKE_", lang, "_SIMULATE_ID"));
2316
2317
0
  bool const compilerTargetsMsvcABI =
2318
0
    (compilerId == "MSVC" || compilerSimulateId == "MSVC");
2319
0
  bool const compilerTargetsWatcomABI =
2320
0
    (compilerId == "OpenWatcom" || compilerSimulateId == "OpenWatcom");
2321
2322
0
  if (lang == "Swift") {
2323
0
    target->AddSwiftTargetFlags(flags);
2324
0
  } else if (lang == "CUDA") {
2325
0
    target->AddCUDAArchitectureFlags(compileOrLink, config, flags);
2326
0
    target->AddCUDAToolkitFlags(flags);
2327
0
  } else if (lang == "SYCL") {
2328
0
    target->AddSYCLDeviceTargetFlags(compileOrLink, config, flags);
2329
0
  } else if (lang == "ISPC") {
2330
0
    target->AddISPCTargetFlags(flags);
2331
0
  } else if (lang == "RC" &&
2332
0
             this->Makefile->GetSafeDefinition("CMAKE_RC_COMPILER")
2333
0
                 .find("llvm-rc") != std::string::npos) {
2334
0
    compilerId = this->Makefile->GetSafeDefinition("CMAKE_C_COMPILER_ID");
2335
0
    if (!compilerId.empty()) {
2336
0
      compilerSimulateId =
2337
0
        this->Makefile->GetSafeDefinition("CMAKE_C_SIMULATE_ID");
2338
0
    } else {
2339
0
      compilerId = this->Makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_ID");
2340
0
      compilerSimulateId =
2341
0
        this->Makefile->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID");
2342
0
    }
2343
0
  } else if (lang == "HIP") {
2344
0
    target->AddHIPArchitectureFlags(compileOrLink, config, flags);
2345
0
  } else if (lang == "Rust") {
2346
0
    target->AddRustTargetFlags(flags);
2347
0
  }
2348
2349
  // Add VFS Overlay for Clang compilers
2350
0
  if (compilerId == "Clang" || compilerId == "DPClang") {
2351
0
    if (cmValue vfsOverlay =
2352
0
          this->Makefile->GetDefinition("CMAKE_CLANG_VFS_OVERLAY")) {
2353
0
      if (compilerSimulateId == "MSVC") {
2354
0
        this->AppendCompileOptions(
2355
0
          flags,
2356
0
          std::vector<std::string>{ "-Xclang", "-ivfsoverlay", "-Xclang",
2357
0
                                    *vfsOverlay });
2358
0
      } else {
2359
0
        this->AppendCompileOptions(
2360
0
          flags, std::vector<std::string>{ "-ivfsoverlay", *vfsOverlay });
2361
0
      }
2362
0
    }
2363
0
  }
2364
  // Add MSVC runtime library flags.  This is activated by the presence
2365
  // of a default selection whether or not it is overridden by a property.
2366
0
  cmValue msvcRuntimeLibraryDefault =
2367
0
    this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
2368
0
  if (cmNonempty(msvcRuntimeLibraryDefault)) {
2369
0
    cmValue msvcRuntimeLibraryValue =
2370
0
      target->GetProperty("MSVC_RUNTIME_LIBRARY");
2371
0
    if (!msvcRuntimeLibraryValue) {
2372
0
      msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
2373
0
    }
2374
0
    std::string const msvcRuntimeLibrary = cmGeneratorExpression::Evaluate(
2375
0
      *msvcRuntimeLibraryValue, this, config, target);
2376
0
    if (!msvcRuntimeLibrary.empty()) {
2377
0
      if (cmValue msvcRuntimeLibraryOptions = this->Makefile->GetDefinition(
2378
0
            cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_",
2379
0
                     msvcRuntimeLibrary))) {
2380
0
        this->AppendCompileOptions(flags, *msvcRuntimeLibraryOptions);
2381
0
      } else if (compilerTargetsMsvcABI &&
2382
0
                 !cmSystemTools::GetErrorOccurredFlag()) {
2383
        // The compiler uses the MSVC ABI so it needs a known runtime library.
2384
0
        this->IssueMessage(
2385
0
          MessageType::FATAL_ERROR,
2386
0
          cmStrCat("MSVC_RUNTIME_LIBRARY value '", msvcRuntimeLibrary,
2387
0
                   "' not known for this ", lang, " compiler."));
2388
0
      }
2389
0
    }
2390
0
  }
2391
2392
  // Add Watcom runtime library flags.  This is activated by the presence
2393
  // of a default selection whether or not it is overridden by a property.
2394
0
  cmValue watcomRuntimeLibraryDefault =
2395
0
    this->Makefile->GetDefinition("CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT");
2396
0
  if (cmNonempty(watcomRuntimeLibraryDefault)) {
2397
0
    cmValue watcomRuntimeLibraryValue =
2398
0
      target->GetProperty("WATCOM_RUNTIME_LIBRARY");
2399
0
    if (!watcomRuntimeLibraryValue) {
2400
0
      watcomRuntimeLibraryValue = watcomRuntimeLibraryDefault;
2401
0
    }
2402
0
    std::string const watcomRuntimeLibrary = cmGeneratorExpression::Evaluate(
2403
0
      *watcomRuntimeLibraryValue, this, config, target);
2404
0
    if (!watcomRuntimeLibrary.empty()) {
2405
0
      if (cmValue watcomRuntimeLibraryOptions =
2406
0
            this->Makefile->GetDefinition(cmStrCat(
2407
0
              "CMAKE_", lang, "_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_",
2408
0
              watcomRuntimeLibrary))) {
2409
0
        this->AppendCompileOptions(flags, *watcomRuntimeLibraryOptions);
2410
0
      } else if (compilerTargetsWatcomABI &&
2411
0
                 !cmSystemTools::GetErrorOccurredFlag()) {
2412
        // The compiler uses the Watcom ABI so it needs a known runtime
2413
        // library.
2414
0
        this->IssueMessage(
2415
0
          MessageType::FATAL_ERROR,
2416
0
          cmStrCat("WATCOM_RUNTIME_LIBRARY value '", watcomRuntimeLibrary,
2417
0
                   "' not known for this ", lang, " compiler."));
2418
0
      }
2419
0
    }
2420
0
  }
2421
2422
  // Add MSVC runtime checks flags. This is activated by the presence
2423
  // of a default selection whether or not it is overridden by a property.
2424
0
  cmValue msvcRuntimeChecksDefault =
2425
0
    this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT");
2426
0
  if (cmNonempty(msvcRuntimeChecksDefault)) {
2427
0
    cmValue msvcRuntimeChecksValue =
2428
0
      target->GetProperty("MSVC_RUNTIME_CHECKS");
2429
0
    if (!msvcRuntimeChecksValue) {
2430
0
      msvcRuntimeChecksValue = msvcRuntimeChecksDefault;
2431
0
    }
2432
0
    cmList msvcRuntimeChecksList = cmGeneratorExpression::Evaluate(
2433
0
      *msvcRuntimeChecksValue, this, config, target);
2434
0
    msvcRuntimeChecksList.remove_duplicates();
2435
2436
    // RTC1/RTCsu VS GUI workaround
2437
0
    std::string const stackFrameErrorCheck = "StackFrameErrorCheck";
2438
0
    std::string const unitinitializedVariable = "UninitializedVariable";
2439
0
    std::string const rtcSU = "RTCsu";
2440
0
    if ((cm::contains(msvcRuntimeChecksList, stackFrameErrorCheck) &&
2441
0
         cm::contains(msvcRuntimeChecksList, unitinitializedVariable)) ||
2442
0
        cm::contains(msvcRuntimeChecksList, rtcSU)) {
2443
0
      msvcRuntimeChecksList.remove_items(
2444
0
        { stackFrameErrorCheck, unitinitializedVariable, rtcSU });
2445
0
      msvcRuntimeChecksList.append(rtcSU);
2446
0
    }
2447
2448
0
    for (std::string const& msvcRuntimeChecks : msvcRuntimeChecksList) {
2449
0
      if (cmValue msvcRuntimeChecksOptions =
2450
0
            this->Makefile->GetDefinition(cmStrCat(
2451
0
              "CMAKE_", lang,
2452
0
              "_COMPILE_OPTIONS_MSVC_RUNTIME_CHECKS_" + msvcRuntimeChecks))) {
2453
0
        this->AppendCompileOptions(flags, *msvcRuntimeChecksOptions);
2454
0
      } else if (compilerTargetsMsvcABI &&
2455
0
                 !cmSystemTools::GetErrorOccurredFlag()) {
2456
        // The compiler uses the MSVC ABI so it needs a known runtime checks.
2457
0
        this->IssueMessage(MessageType::FATAL_ERROR,
2458
0
                           cmStrCat("MSVC_RUNTIME_CHECKS value '",
2459
0
                                    msvcRuntimeChecks, "' not known for this ",
2460
0
                                    lang, " compiler."));
2461
0
      }
2462
0
    }
2463
0
  }
2464
2465
  // Add MSVC debug information format flags if CMP0141 is NEW.
2466
0
  if (cm::optional<std::string> msvcDebugInformationFormat =
2467
0
        this->GetMSVCDebugFormatName(config, target)) {
2468
0
    if (!msvcDebugInformationFormat->empty()) {
2469
0
      if (cmValue msvcDebugInformationFormatOptions =
2470
0
            this->Makefile->GetDefinition(
2471
0
              cmStrCat("CMAKE_", lang,
2472
0
                       "_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_",
2473
0
                       *msvcDebugInformationFormat))) {
2474
0
        this->AppendCompileOptions(flags, *msvcDebugInformationFormatOptions);
2475
0
      } else if (compilerTargetsMsvcABI &&
2476
0
                 !cmSystemTools::GetErrorOccurredFlag()) {
2477
        // The compiler uses the MSVC ABI so it needs a known runtime library.
2478
0
        this->IssueMessage(MessageType::FATAL_ERROR,
2479
0
                           cmStrCat("MSVC_DEBUG_INFORMATION_FORMAT value '",
2480
0
                                    *msvcDebugInformationFormat,
2481
0
                                    "' not known for this ", lang,
2482
0
                                    " compiler."));
2483
0
      }
2484
0
    }
2485
0
  }
2486
0
}
2487
2488
void cmLocalGenerator::AddLanguageFlagsForLinking(
2489
  std::string& flags, cmGeneratorTarget const* target, std::string const& lang,
2490
  std::string const& config)
2491
0
{
2492
0
  this->AddLanguageFlags(flags, target, cmBuildStep::Link, lang, config);
2493
2494
0
  if (lang == "SYCL" && !target->IsDeviceLink() &&
2495
0
      this->Makefile->IsOn("CMAKE_SYCL_COMPILER_HAS_DEVICE_LINK_PHASE")) {
2496
0
    if (auto* linkInfo = target->GetLinkInformation(config)) {
2497
0
      if (requireDeviceLinking(*linkInfo->GetTarget(), *this, config, lang)) {
2498
0
        this->AppendFlags(flags, "-fno-sycl");
2499
0
      }
2500
0
    }
2501
0
  }
2502
2503
0
  if (target->IsIPOEnabled(lang, config)) {
2504
0
    this->AppendFeatureOptions(flags, lang, "IPO");
2505
0
  }
2506
0
}
2507
2508
cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
2509
  std::string const& name) const
2510
172k
{
2511
172k
  auto imported = this->ImportedGeneratorTargets.find(name);
2512
172k
  if (imported != this->ImportedGeneratorTargets.end()) {
2513
6.85k
    return imported->second;
2514
6.85k
  }
2515
2516
  // find local alias to imported target
2517
165k
  auto aliased = this->AliasTargets.find(name);
2518
165k
  if (aliased != this->AliasTargets.end()) {
2519
2.67k
    imported = this->ImportedGeneratorTargets.find(aliased->second);
2520
2.67k
    if (imported != this->ImportedGeneratorTargets.end()) {
2521
2.57k
      return imported->second;
2522
2.57k
    }
2523
2.67k
  }
2524
2525
163k
  if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) {
2526
27.8k
    return t;
2527
27.8k
  }
2528
2529
135k
  return this->GetGlobalGenerator()->FindGeneratorTarget(name);
2530
163k
}
2531
2532
bool cmLocalGenerator::GetRealDependency(std::string const& inName,
2533
                                         std::string const& config,
2534
                                         std::string& dep,
2535
                                         cmPolicies::PolicyStatus cmp0212)
2536
0
{
2537
  // Older CMake code may specify the dependency using the target
2538
  // output file rather than the target name.  Such code would have
2539
  // been written before there was support for target properties that
2540
  // modify the name so stripping down to just the file name should
2541
  // produce the target name in this case.
2542
0
  std::string name = cmSystemTools::GetFilenameName(inName);
2543
2544
  // If the input name is the empty string, there is no real
2545
  // dependency. Short-circuit the other checks:
2546
0
  if (name.empty()) {
2547
0
    return false;
2548
0
  }
2549
2550
  // Look for a CMake target with the given name.
2551
0
  cmGeneratorTarget* target = this->FindGeneratorTargetToUse(name);
2552
0
  if (!target && cmHasSuffix(name, ".exe"_s) && cmp0212 != cmPolicies::NEW) {
2553
    // If it doesn't exist, try to strip the `.exe` suffix per CMP0212.
2554
0
    std::string strippedName =
2555
0
      cmSystemTools::GetFilenameWithoutLastExtension(name);
2556
0
    if (cmGeneratorTarget* strippedTarget =
2557
0
          this->FindGeneratorTargetToUse(strippedName)) {
2558
0
      name = strippedName;
2559
0
      target = strippedTarget;
2560
0
    }
2561
0
  }
2562
2563
0
  if (target) {
2564
    // make sure it is not just a coincidence that the target name
2565
    // found is part of the inName
2566
0
    if (cmSystemTools::FileIsFullPath(inName)) {
2567
0
      std::string tLocation;
2568
0
      if (target->GetType() >= cm::TargetType::EXECUTABLE &&
2569
0
          target->GetType() <= cm::TargetType::MODULE_LIBRARY) {
2570
0
        tLocation = target->GetLocation(config);
2571
0
        tLocation = cmSystemTools::GetFilenamePath(tLocation);
2572
0
        tLocation = cmSystemTools::CollapseFullPath(tLocation);
2573
0
      }
2574
0
      std::string depLocation =
2575
0
        cmSystemTools::GetFilenamePath(std::string(inName));
2576
0
      depLocation = cmSystemTools::CollapseFullPath(depLocation);
2577
0
      if (depLocation != tLocation) {
2578
        // it is a full path to a depend that has the same name
2579
        // as a target but is in a different location so do not use
2580
        // the target as the depend
2581
0
        dep = inName;
2582
0
        return true;
2583
0
      }
2584
0
    }
2585
0
    switch (target->GetType()) {
2586
0
      case cm::TargetType::EXECUTABLE:
2587
0
      case cm::TargetType::STATIC_LIBRARY:
2588
0
      case cm::TargetType::SHARED_LIBRARY:
2589
0
      case cm::TargetType::MODULE_LIBRARY:
2590
0
      case cm::TargetType::UNKNOWN_LIBRARY:
2591
0
        dep = target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
2592
0
                                  /*realname=*/true);
2593
0
        return true;
2594
0
      case cm::TargetType::OBJECT_LIBRARY:
2595
        // An object library has no single file on which to depend.
2596
        // This was listed to get the target-level dependency.
2597
0
      case cm::TargetType::INTERFACE_LIBRARY:
2598
        // An interface library has no file on which to depend.
2599
        // This was listed to get the target-level dependency.
2600
0
      case cm::TargetType::UTILITY:
2601
0
      case cm::TargetType::GLOBAL_TARGET:
2602
        // A utility target has no file on which to depend.  This was listed
2603
        // only to get the target-level dependency.
2604
0
        return false;
2605
0
    }
2606
0
  }
2607
2608
  // The name was not that of a CMake target.  It must name a file.
2609
0
  dep = this->GetRealFileDependency(inName);
2610
0
  return true;
2611
0
}
2612
2613
std::string cmLocalGenerator::GetRealFileDependency(
2614
  std::string const& name) const
2615
0
{
2616
0
  if (cmSystemTools::FileIsFullPath(name)) {
2617
    // This is a full path.  Return it as given.
2618
0
    return name;
2619
0
  }
2620
2621
  // Check for a source file in this directory that matches the
2622
  // dependency.
2623
0
  if (cmSourceFile* sf = this->Makefile->GetSource(name)) {
2624
0
    return sf->ResolveFullPath();
2625
0
  }
2626
2627
  // Treat the name as relative to the source directory in which it
2628
  // was given.
2629
0
  std::string dep = cmStrCat(this->GetCurrentSourceDirectory(), '/', name);
2630
2631
  // If the in-source path does not exist, assume it instead lives in the
2632
  // binary directory.
2633
0
  if (!cmSystemTools::FileExists(dep)) {
2634
0
    dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', name);
2635
0
  }
2636
2637
0
  return cmSystemTools::CollapseFullPath(dep);
2638
0
}
2639
2640
static void AddVisibilityCompileOption(std::string& flags,
2641
                                       cmGeneratorTarget const* target,
2642
                                       cmLocalGenerator* lg,
2643
                                       std::string const& lang)
2644
0
{
2645
0
  std::string compileOption =
2646
0
    cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY");
2647
0
  cmValue opt = lg->GetMakefile()->GetDefinition(compileOption);
2648
0
  if (!opt) {
2649
0
    return;
2650
0
  }
2651
0
  std::string flagDefine = lang + "_VISIBILITY_PRESET";
2652
2653
0
  cmValue prop = target->GetProperty(flagDefine);
2654
0
  if (!prop) {
2655
0
    return;
2656
0
  }
2657
0
  if ((*prop != "hidden") && (*prop != "default") && (*prop != "protected") &&
2658
0
      (*prop != "internal")) {
2659
0
    cmSystemTools::Error(
2660
0
      cmStrCat("Target ", target->GetName(), " uses unsupported value \"",
2661
0
               *prop, "\" for ", flagDefine,
2662
0
               ". The supported values are: default, hidden, protected, and "
2663
0
               "internal."));
2664
0
    return;
2665
0
  }
2666
0
  std::string option = *opt + *prop;
2667
0
  lg->AppendFlags(flags, option);
2668
0
}
2669
2670
static void AddInlineVisibilityCompileOption(std::string& flags,
2671
                                             cmGeneratorTarget const* target,
2672
                                             cmLocalGenerator* lg,
2673
                                             std::string const& lang)
2674
0
{
2675
0
  std::string compileOption =
2676
0
    cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN");
2677
0
  cmValue opt = lg->GetMakefile()->GetDefinition(compileOption);
2678
0
  if (!opt) {
2679
0
    return;
2680
0
  }
2681
2682
0
  bool prop = target->GetPropertyAsBool("VISIBILITY_INLINES_HIDDEN");
2683
0
  if (!prop) {
2684
0
    return;
2685
0
  }
2686
0
  lg->AppendFlags(flags, *opt);
2687
0
}
2688
2689
void cmLocalGenerator::AddVisibilityPresetFlags(
2690
  std::string& flags, cmGeneratorTarget const* target, std::string const& lang)
2691
0
{
2692
0
  if (lang.empty()) {
2693
0
    return;
2694
0
  }
2695
2696
0
  AddVisibilityCompileOption(flags, target, this, lang);
2697
2698
0
  if (lang == "CXX" || lang == "OBJCXX" || lang == "SYCL") {
2699
0
    AddInlineVisibilityCompileOption(flags, target, this, lang);
2700
0
  }
2701
0
}
2702
2703
void cmLocalGenerator::AddFeatureFlags(std::string& flags,
2704
                                       cmGeneratorTarget const* target,
2705
                                       std::string const& lang,
2706
                                       std::string const& config)
2707
0
{
2708
0
  cm::TargetType const targetType = target->GetType();
2709
2710
0
  bool shared = ((targetType == cm::TargetType::SHARED_LIBRARY) ||
2711
0
                 (targetType == cm::TargetType::MODULE_LIBRARY));
2712
2713
0
  if (target->GetLinkInterfaceDependentBoolProperty(
2714
0
        "POSITION_INDEPENDENT_CODE", config)) {
2715
0
    this->AddPositionIndependentFlags(flags, lang, targetType);
2716
0
  }
2717
0
  if (shared) {
2718
0
    this->AppendFeatureOptions(flags, lang, "DLL");
2719
0
  }
2720
0
}
2721
2722
void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags,
2723
                                                   std::string const& lang,
2724
                                                   cm::TargetType targetType)
2725
0
{
2726
0
  std::string picFlags;
2727
2728
0
  if (targetType == cm::TargetType::EXECUTABLE) {
2729
0
    picFlags = this->Makefile->GetSafeDefinition(
2730
0
      cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIE"));
2731
0
  }
2732
0
  if (picFlags.empty()) {
2733
0
    picFlags = this->Makefile->GetSafeDefinition(
2734
0
      cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIC"));
2735
0
  }
2736
0
  if (!picFlags.empty()) {
2737
0
    cmList options{ picFlags };
2738
0
    for (std::string const& o : options) {
2739
0
      this->AppendFlagEscape(flags, o);
2740
0
    }
2741
0
  }
2742
0
}
2743
2744
void cmLocalGenerator::AddColorDiagnosticsFlags(std::string& flags,
2745
                                                std::string const& lang)
2746
0
{
2747
0
  cmValue diag = this->Makefile->GetDefinition("CMAKE_COLOR_DIAGNOSTICS");
2748
0
  if (diag.IsSet()) {
2749
0
    std::string colorFlagName;
2750
0
    if (diag.IsOn()) {
2751
0
      colorFlagName =
2752
0
        cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS");
2753
0
    } else {
2754
0
      colorFlagName =
2755
0
        cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF");
2756
0
    }
2757
2758
0
    cmList options{ this->Makefile->GetDefinition(colorFlagName) };
2759
2760
0
    for (auto const& option : options) {
2761
0
      this->AppendFlagEscape(flags, option);
2762
0
    }
2763
0
  }
2764
0
}
2765
2766
void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
2767
                                              std::string const& var,
2768
                                              std::string const& config)
2769
0
{
2770
  // Add the flags from the variable itself.
2771
0
  this->AppendFlags(flags, this->Makefile->GetSafeDefinition(var));
2772
  // Add the flags from the build-type specific variable.
2773
0
  if (!config.empty()) {
2774
0
    std::string const flagsVar =
2775
0
      cmStrCat(var, '_', cmSystemTools::UpperCase(config));
2776
0
    this->AppendFlags(flags, this->Makefile->GetSafeDefinition(flagsVar));
2777
0
  }
2778
0
}
2779
void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
2780
                                              std::string const& var,
2781
                                              cmGeneratorTarget const* target,
2782
                                              cmBuildStep compileOrLink,
2783
                                              std::string const& lang,
2784
                                              std::string const& config)
2785
0
{
2786
0
  std::string newFlags;
2787
0
  this->AddConfigVariableFlags(newFlags, var, config);
2788
0
  if (!newFlags.empty()) {
2789
0
    this->AppendFlags(flags, newFlags, var, target, compileOrLink, lang);
2790
0
  }
2791
0
}
2792
2793
void cmLocalGenerator::AppendFlags(std::string& flags,
2794
                                   std::string const& newFlags) const
2795
0
{
2796
0
  bool allSpaces =
2797
0
    std::all_of(newFlags.begin(), newFlags.end(), cmsysString_isspace);
2798
2799
0
  if (!newFlags.empty() && !allSpaces) {
2800
0
    if (!flags.empty()) {
2801
0
      flags += ' ';
2802
0
    }
2803
0
    flags += newFlags;
2804
0
  }
2805
0
}
2806
2807
void cmLocalGenerator::AppendFlags(
2808
  std::string& flags, std::vector<BT<std::string>> const& newFlags) const
2809
0
{
2810
0
  for (BT<std::string> const& flag : newFlags) {
2811
0
    this->AppendFlags(flags, flag.Value);
2812
0
  }
2813
0
}
2814
2815
void cmLocalGenerator::AppendFlagEscape(std::string& flags,
2816
                                        std::string const& rawFlag) const
2817
0
{
2818
0
  this->AppendFlags(
2819
0
    flags,
2820
0
    this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
2821
0
}
2822
2823
void cmLocalGenerator::AppendLinkFlagsWithParsing(
2824
  std::string& flags, std::string const& newFlags,
2825
  cmGeneratorTarget const* target, std::string const& language)
2826
0
{
2827
0
  std::vector<std::string> options;
2828
0
  cmSystemTools::ParseUnixCommandLine(newFlags.c_str(), options);
2829
0
  this->SetLinkScriptShell(this->GlobalGenerator->GetUseLinkScript());
2830
0
  std::vector<BT<std::string>> optionsWithBT{ options.size() };
2831
0
  std::transform(options.cbegin(), options.cend(), optionsWithBT.begin(),
2832
0
                 [](std::string const& item) -> BT<std::string> {
2833
0
                   return BT<std::string>{ item };
2834
0
                 });
2835
0
  target->ResolveLinkerWrapper(optionsWithBT, language);
2836
0
  for (auto const& item : optionsWithBT) {
2837
0
    this->AppendFlagEscape(flags, item.Value);
2838
0
  }
2839
0
  this->SetLinkScriptShell(false);
2840
0
}
2841
2842
void cmLocalGenerator::AppendFlags(std::string& flags,
2843
                                   std::string const& newFlags,
2844
                                   std::string const& name,
2845
                                   cmGeneratorTarget const* target,
2846
                                   cmBuildStep compileOrLink,
2847
                                   std::string const& language)
2848
0
{
2849
0
  switch (target->GetPolicyStatusCMP0181()) {
2850
0
    case cmPolicies::WARN:
2851
0
      if (!this->Makefile->GetCMakeInstance()->GetIsInTryCompile() &&
2852
0
          this->Makefile->PolicyOptionalWarningEnabled(
2853
0
            "CMAKE_POLICY_WARNING_CMP0181")) {
2854
0
        this->Makefile->IssuePolicyWarning(
2855
0
          cmPolicies::CMP0181, {},
2856
0
          cmStrCat("Since the policy is not set, the contents of variable '"_s,
2857
0
                   name, "' will be used as is."_s),
2858
0
          target->GetBacktrace());
2859
0
      }
2860
0
      CM_FALLTHROUGH;
2861
0
    case cmPolicies::OLD:
2862
0
      this->AppendFlags(
2863
0
        flags, this->GetGlobalGenerator()->GetEncodedLiteral(newFlags));
2864
0
      break;
2865
0
    case cmPolicies::NEW:
2866
0
      if (compileOrLink == cmBuildStep::Link) {
2867
0
        this->AppendLinkFlagsWithParsing(flags, newFlags, target, language);
2868
0
      } else {
2869
0
        this->AppendFlags(flags, newFlags);
2870
0
      }
2871
0
  }
2872
0
}
2873
2874
void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
2875
0
{
2876
0
  std::vector<std::string> enabledLanguages =
2877
0
    this->GetState()->GetEnabledLanguages();
2878
0
  if (std::find(enabledLanguages.begin(), enabledLanguages.end(), "ISPC") ==
2879
0
      enabledLanguages.end()) {
2880
0
    return;
2881
0
  }
2882
2883
0
  cmValue ispcHeaderSuffixProp = target->GetProperty("ISPC_HEADER_SUFFIX");
2884
0
  assert(ispcHeaderSuffixProp);
2885
2886
0
  std::vector<std::string> ispcArchSuffixes =
2887
0
    detail::ComputeISPCObjectSuffixes(target);
2888
0
  bool const extra_objects = (ispcArchSuffixes.size() > 1);
2889
2890
0
  std::vector<std::string> configsList =
2891
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2892
0
  for (std::string const& config : configsList) {
2893
2894
0
    std::string rootObjectDir = target->GetObjectDirectory(config);
2895
0
    std::string headerDir = rootObjectDir;
2896
0
    if (cmValue prop = target->GetProperty("ISPC_HEADER_DIRECTORY")) {
2897
0
      headerDir = cmSystemTools::CollapseFullPath(
2898
0
        cmStrCat(this->GetBinaryDirectory(), '/', *prop));
2899
0
    }
2900
2901
0
    std::vector<cmSourceFile*> sources;
2902
0
    target->GetSourceFiles(sources, config);
2903
2904
    // build up the list of ispc headers and extra objects that this target is
2905
    // generating
2906
0
    for (cmSourceFile const* sf : sources) {
2907
      // Generate this object file's rule file.
2908
0
      std::string const lang = target->GetSourceFileLanguage(sf, config);
2909
0
      if (lang == "ISPC") {
2910
0
        std::string const& objectName = target->GetObjectName(sf);
2911
2912
        // Drop both ".obj" and the source file extension
2913
0
        std::string ispcSource =
2914
0
          cmSystemTools::GetFilenameWithoutLastExtension(objectName);
2915
0
        ispcSource =
2916
0
          cmSystemTools::GetFilenameWithoutLastExtension(ispcSource);
2917
2918
0
        auto headerPath =
2919
0
          cmStrCat(headerDir, '/', ispcSource, *ispcHeaderSuffixProp);
2920
0
        target->AddISPCGeneratedHeader(headerPath, config);
2921
0
        if (extra_objects) {
2922
0
          std::vector<std::pair<cmSourceFile const*, std::string>> objs;
2923
0
          for (auto& obj : detail::ComputeISPCExtraObjects(
2924
0
                 objectName, rootObjectDir, ispcArchSuffixes)) {
2925
0
            objs.push_back({ sf, std::move(obj) });
2926
0
          }
2927
0
          target->AddISPCGeneratedObject(std::move(objs), config);
2928
0
        }
2929
0
      }
2930
0
    }
2931
0
  }
2932
0
}
2933
2934
void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
2935
0
{
2936
0
  std::vector<std::string> configsList =
2937
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2938
2939
0
  for (std::string const& config : configsList) {
2940
    // FIXME: Refactor collection of sources to not evaluate object
2941
    // libraries.
2942
0
    std::vector<cmSourceFile*> sources;
2943
0
    target->GetSourceFiles(sources, config);
2944
2945
0
    std::string const configUpper = cmSystemTools::UpperCase(config);
2946
0
    static std::array<std::string, 4> const langs = { { "C", "CXX", "OBJC",
2947
0
                                                        "OBJCXX" } };
2948
2949
0
    std::set<std::string> pchLangSet;
2950
0
    if (this->GetGlobalGenerator()->IsXcode()) {
2951
0
      for (std::string const& lang : langs) {
2952
0
        std::string const pchHeader = target->GetPchHeader(config, lang, "");
2953
0
        if (!pchHeader.empty()) {
2954
0
          pchLangSet.emplace(lang);
2955
0
        }
2956
0
      }
2957
0
    }
2958
2959
0
    for (std::string const& lang : langs) {
2960
0
      auto langSources = std::count_if(
2961
0
        sources.begin(), sources.end(),
2962
0
        [&target, &config, &lang](cmSourceFile* sf) {
2963
0
          auto const* const fileSet = target->GetFileSetForSource(config, sf);
2964
0
          return lang == target->GetSourceFileLanguage(sf, config) &&
2965
0
            !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) ||
2966
0
              sf->GetProperty("SKIP_PRECOMPILE_HEADERS"));
2967
0
        });
2968
0
      if (langSources == 0) {
2969
0
        continue;
2970
0
      }
2971
2972
0
      std::vector<std::string> pchArchs = target->GetPchArchs(config, lang);
2973
0
      if (pchArchs.size() > 1) {
2974
0
        std::string useMultiArchPch;
2975
0
        for (std::string const& arch : pchArchs) {
2976
0
          std::string const pchHeader =
2977
0
            target->GetPchHeader(config, lang, arch);
2978
0
          if (!pchHeader.empty()) {
2979
0
            useMultiArchPch = cmStrCat(std::move(useMultiArchPch), ";-Xarch_",
2980
0
                                       arch, ";-include", pchHeader);
2981
0
          }
2982
0
        }
2983
2984
0
        if (!useMultiArchPch.empty()) {
2985
2986
0
          target->Target->AppendProperty(
2987
0
            cmStrCat(lang, "_COMPILE_OPTIONS_USE_PCH"),
2988
0
            cmStrCat("$<$<CONFIG:", config, ">:", useMultiArchPch, '>'));
2989
0
        }
2990
0
      }
2991
2992
0
      for (std::string const& arch : pchArchs) {
2993
0
        std::string const pchSource = target->GetPchSource(config, lang, arch);
2994
0
        std::string const pchHeader = target->GetPchHeader(config, lang, arch);
2995
2996
0
        if (pchSource.empty() || pchHeader.empty()) {
2997
0
          if (this->GetGlobalGenerator()->IsXcode() && !pchLangSet.empty()) {
2998
0
            for (auto* sf : sources) {
2999
0
              auto const sourceLanguage =
3000
0
                target->GetSourceFileLanguage(sf, config);
3001
0
              if (!sourceLanguage.empty() &&
3002
0
                  pchLangSet.find(sourceLanguage) == pchLangSet.end()) {
3003
0
                sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
3004
0
              }
3005
0
            }
3006
0
          }
3007
0
          continue;
3008
0
        }
3009
3010
0
        cmValue pchExtension =
3011
0
          this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
3012
3013
0
        if (pchExtension.IsEmpty()) {
3014
0
          continue;
3015
0
        }
3016
3017
0
        auto* reuseTarget = target->GetPchReuseTarget();
3018
0
        bool const haveReuseTarget = reuseTarget && reuseTarget != target;
3019
3020
0
        auto* pch_sf = this->Makefile->GetOrCreateSource(
3021
0
          pchSource, false, cmSourceFileLocationKind::Known);
3022
0
        pch_sf->SetSpecialSourceType(
3023
0
          cmSourceFile::SpecialSourceType::PchSource);
3024
        // PCH sources should never be scanned as they cannot contain C++
3025
        // module references.
3026
0
        pch_sf->SetProperty("CXX_SCAN_FOR_MODULES", "0");
3027
3028
0
        if (!this->GetGlobalGenerator()->IsXcode()) {
3029
0
          if (!haveReuseTarget) {
3030
0
            target->AddSource(pchSource, true);
3031
0
          }
3032
3033
0
          std::string const pchFile = target->GetPchFile(config, lang, arch);
3034
3035
          // Exclude the pch files from linking
3036
0
          if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
3037
0
            if (!haveReuseTarget) {
3038
0
              pch_sf->AppendProperty(
3039
0
                "OBJECT_OUTPUTS",
3040
0
                cmStrCat("$<$<CONFIG:", config, ">:", pchFile, '>'));
3041
0
            } else {
3042
0
              if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
3043
3044
0
                std::string const compilerId =
3045
0
                  this->Makefile->GetSafeDefinition(
3046
0
                    cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
3047
3048
0
                std::string const compilerVersion =
3049
0
                  this->Makefile->GetSafeDefinition(
3050
0
                    cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"));
3051
3052
0
                std::string const langFlags =
3053
0
                  this->Makefile->GetSafeDefinition(
3054
0
                    cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper));
3055
3056
0
                bool editAndContinueDebugInfo = false;
3057
0
                bool programDatabaseDebugInfo = false;
3058
0
                cm::optional<std::string> msvcDebugInformationFormat =
3059
0
                  this->GetMSVCDebugFormatName(config, target);
3060
0
                if (msvcDebugInformationFormat &&
3061
0
                    !msvcDebugInformationFormat->empty()) {
3062
0
                  editAndContinueDebugInfo =
3063
0
                    *msvcDebugInformationFormat == "EditAndContinue";
3064
0
                  programDatabaseDebugInfo =
3065
0
                    *msvcDebugInformationFormat == "ProgramDatabase";
3066
0
                } else {
3067
0
                  editAndContinueDebugInfo =
3068
0
                    langFlags.find("/ZI") != std::string::npos ||
3069
0
                    langFlags.find("-ZI") != std::string::npos;
3070
0
                  programDatabaseDebugInfo =
3071
0
                    langFlags.find("/Zi") != std::string::npos ||
3072
0
                    langFlags.find("-Zi") != std::string::npos;
3073
0
                }
3074
3075
0
                if (editAndContinueDebugInfo) {
3076
0
                  this->CopyPchCompilePdb(config, lang, target, reuseTarget,
3077
0
                                          { ".pdb", ".idb" });
3078
0
                } else if (programDatabaseDebugInfo) {
3079
0
                  this->CopyPchCompilePdb(config, lang, target, reuseTarget,
3080
0
                                          { ".pdb" });
3081
0
                }
3082
0
              }
3083
3084
              // Link to the pch object file
3085
0
              std::string pchSourceObj;
3086
              // Fastbuild will propagate pch.obj for us, no need to link to it
3087
              // explicitly.
3088
0
              if (!this->GetGlobalGenerator()->IsFastbuild()) {
3089
0
                pchSourceObj =
3090
0
                  reuseTarget->GetPchFileObject(config, lang, arch);
3091
0
              }
3092
3093
0
              if (target->GetType() != cm::TargetType::OBJECT_LIBRARY) {
3094
0
                std::string linkerProperty = "LINK_FLAGS_";
3095
0
                if (target->GetType() == cm::TargetType::STATIC_LIBRARY) {
3096
0
                  linkerProperty = "STATIC_LIBRARY_FLAGS_";
3097
0
                }
3098
0
                target->Target->AppendProperty(
3099
0
                  cmStrCat(linkerProperty, configUpper),
3100
0
                  cmStrCat(' ',
3101
0
                           this->ConvertToOutputFormat(pchSourceObj, SHELL)),
3102
0
                  cm::nullopt, true);
3103
0
              } else if (reuseTarget->GetType() ==
3104
0
                         cm::TargetType::OBJECT_LIBRARY) {
3105
0
                target->Target->AppendProperty(
3106
0
                  "INTERFACE_LINK_LIBRARIES",
3107
0
                  cmStrCat("$<$<CONFIG:", config,
3108
0
                           ">:$<LINK_ONLY:", pchSourceObj, ">>"));
3109
0
              }
3110
0
            }
3111
0
          } else {
3112
0
            pch_sf->SetProperty("PCH_EXTENSION", pchExtension);
3113
0
          }
3114
3115
          // Add pchHeader to source files, which will
3116
          // be grouped as "Precompile Header File"
3117
0
          auto* pchHeader_sf = this->Makefile->GetOrCreateSource(
3118
0
            pchHeader, false, cmSourceFileLocationKind::Known);
3119
0
          pchHeader_sf->SetSpecialSourceType(
3120
0
            cmSourceFile::SpecialSourceType::PchHeader);
3121
0
          std::string err;
3122
0
          pchHeader_sf->ResolveFullPath(&err);
3123
0
          if (!err.empty()) {
3124
0
            this->IssueMessage(
3125
0
              MessageType::FATAL_ERROR,
3126
0
              cmStrCat("Unable to resolve full path of PCH-header '",
3127
0
                       pchHeader, "' assigned to target ", target->GetName(),
3128
0
                       ", although its path is supposed to be known!"));
3129
0
          }
3130
0
          target->AddSource(pchHeader);
3131
0
        }
3132
0
      }
3133
0
    }
3134
0
  }
3135
0
}
3136
3137
void cmLocalGenerator::CopyPchCompilePdb(
3138
  std::string const& config, std::string const& language,
3139
  cmGeneratorTarget* target, cmGeneratorTarget* reuseTarget,
3140
  std::vector<std::string> const& extensions)
3141
0
{
3142
0
  std::string const copy_script = cmStrCat(target->GetSupportDirectory(),
3143
0
                                           "/copy_idb_pdb_", config, ".cmake");
3144
0
  cmGeneratedFileStream file(copy_script);
3145
0
  file.SetCopyIfDifferent(true);
3146
3147
0
  file << "# CMake generated file\n";
3148
3149
0
  file << "# The compiler generated pdb file needs to be written to disk\n"
3150
0
       << "# by mspdbsrv. The foreach retry loop is needed to make sure\n"
3151
0
       << "# the pdb file is ready to be copied.\n\n";
3152
3153
0
  auto configGenex = [&](cm::string_view expr) -> std::string {
3154
0
    if (this->GetGlobalGenerator()->IsMultiConfig()) {
3155
0
      return cmStrCat("$<$<CONFIG:", config, ">:", expr, '>');
3156
0
    }
3157
0
    return std::string(expr);
3158
0
  };
3159
3160
0
  std::vector<std::string> byproducts;
3161
0
  auto replaceExtension = [](std::string const& path,
3162
0
                             std::string const& ext) -> std::string {
3163
0
    auto const dir = cmSystemTools::GetFilenamePath(path);
3164
0
    auto const base = cmSystemTools::GetFilenameWithoutLastExtension(path);
3165
0
    if (dir.empty()) {
3166
0
      return cmStrCat(base, ext);
3167
0
    }
3168
0
    return cmStrCat(dir, '/', base, ext);
3169
0
  };
3170
0
  for (auto const& extension : extensions) {
3171
0
    std::string const from_file =
3172
0
      replaceExtension(reuseTarget->GetCompilePDBPath(config), extension);
3173
0
    std::string const to_dir = target->GetCompilePDBDirectory(config);
3174
0
    std::string const to_file =
3175
0
      replaceExtension(reuseTarget->GetCompilePDBName(config), extension);
3176
0
    std::string const dest_file = cmStrCat(to_dir, '/', to_file);
3177
3178
0
    file << "foreach(retry RANGE 1 30)\n";
3179
0
    file << "  if (EXISTS \"" << from_file << "\" AND (NOT EXISTS \""
3180
0
         << dest_file << "\" OR NOT \"" << dest_file << "\" IS_NEWER_THAN \""
3181
0
         << from_file << "\"))\n";
3182
0
    file << "    file(MAKE_DIRECTORY \"" << to_dir << "\")\n";
3183
0
    file << "    execute_process(COMMAND ${CMAKE_COMMAND} -E copy";
3184
0
    file << " \"" << from_file << "\"" << " \"" << to_dir
3185
0
         << "\" RESULT_VARIABLE result " << " ERROR_QUIET)\n";
3186
0
    file << "    if (NOT result EQUAL 0)\n"
3187
0
         << "      execute_process(COMMAND ${CMAKE_COMMAND}"
3188
0
         << " -E sleep 1)\n"
3189
0
         << "    else()\n";
3190
0
    file << "      break()\n"
3191
0
         << "    endif()\n";
3192
0
    file << "  elseif(NOT EXISTS \"" << from_file << "\")\n"
3193
0
         << "    execute_process(COMMAND ${CMAKE_COMMAND}" << " -E sleep 1)\n"
3194
0
         << "  endif()\n";
3195
0
    file << "endforeach()\n";
3196
0
    byproducts.push_back(configGenex(dest_file));
3197
0
  }
3198
3199
  // Multiple targets reusing the same PCH may share a compiler PDB
3200
  // directory, in which case they copy to the same destination.  Use a
3201
  // per-target stamp file as the rule output to avoid duplicate rules.
3202
0
  std::string const stamp_file = cmStrCat(target->GetSupportDirectory(),
3203
0
                                          "/copy_idb_pdb_", config, ".stamp");
3204
0
  file << "file(TOUCH \"" << stamp_file << "\")\n";
3205
3206
0
  cmCustomCommandLines commandLines =
3207
0
    cmMakeSingleCommandLine({ configGenex(cmSystemTools::GetCMakeCommand()),
3208
0
                              configGenex("-P"), configGenex(copy_script) });
3209
3210
0
  auto const comment =
3211
0
    cmStrCat("Copying PDB for PCH reuse from ", reuseTarget->GetName(),
3212
0
             " for ", target->GetName());
3213
0
  ;
3214
3215
0
  auto cc = cm::make_unique<cmCustomCommand>();
3216
0
  cc->SetCommandLines(commandLines);
3217
0
  cc->SetComment(comment);
3218
0
  cc->SetStdPipesUTF8(true);
3219
0
  cc->AppendDepends(
3220
0
    { reuseTarget->GetPchFile(config, language), copy_script });
3221
  // Fastbuild needs to know that this custom command actually depends on a
3222
  // target that produces PCH, so it can sort by dependencies correctly.
3223
0
  if (this->GetGlobalGenerator()->IsFastbuild()) {
3224
0
    cc->AppendDepends({ reuseTarget->GetName() });
3225
0
  }
3226
3227
0
  if (this->GetGlobalGenerator()->IsVisualStudio()) {
3228
0
    cc->SetByproducts(byproducts);
3229
0
    this->AddCustomCommandToTarget(
3230
0
      target->GetName(), cmCustomCommandType::PRE_BUILD, std::move(cc),
3231
0
      cmObjectLibraryCommands::Accept);
3232
0
  } else {
3233
0
    cc->SetOutputs(configGenex(stamp_file));
3234
0
    cmSourceFile* copy_rule = this->AddCustomCommandToOutput(std::move(cc));
3235
0
    if (copy_rule) {
3236
0
      copy_rule->SetProperty("CXX_SCAN_FOR_MODULES", "0");
3237
0
      auto* pch_pdb_sf = target->AddSource(copy_rule->ResolveFullPath());
3238
0
      pch_pdb_sf->SetSpecialSourceType(
3239
0
        cmSourceFile::SpecialSourceType::PchPdbReuseSource);
3240
0
    }
3241
0
  }
3242
0
}
3243
3244
cm::optional<std::string> cmLocalGenerator::GetMSVCDebugFormatName(
3245
  std::string const& config, cmGeneratorTarget const* target)
3246
0
{
3247
  // MSVC debug information format selection is activated by the presence
3248
  // of a default whether or not it is overridden by a property.
3249
0
  cm::optional<std::string> msvcDebugInformationFormat;
3250
0
  cmValue msvcDebugInformationFormatDefault = this->Makefile->GetDefinition(
3251
0
    "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT");
3252
0
  if (cmNonempty(msvcDebugInformationFormatDefault)) {
3253
0
    cmValue msvcDebugInformationFormatValue =
3254
0
      target->GetProperty("MSVC_DEBUG_INFORMATION_FORMAT");
3255
0
    if (!msvcDebugInformationFormatValue) {
3256
0
      msvcDebugInformationFormatValue = msvcDebugInformationFormatDefault;
3257
0
    }
3258
0
    msvcDebugInformationFormat = cmGeneratorExpression::Evaluate(
3259
0
      *msvcDebugInformationFormatValue, this, config, target);
3260
0
  }
3261
0
  return msvcDebugInformationFormat;
3262
0
}
3263
3264
cm::optional<cmSwiftCompileMode> cmLocalGenerator::GetSwiftCompileMode(
3265
  cmGeneratorTarget const* target, std::string const& config)
3266
0
{
3267
0
  cmMakefile const* mf = this->GetMakefile();
3268
0
  cmValue const swiftCompileModeDefault =
3269
0
    mf->GetDefinition("CMAKE_Swift_COMPILATION_MODE_DEFAULT");
3270
0
  if (!cmNonempty(swiftCompileModeDefault)) {
3271
0
    return {};
3272
0
  }
3273
0
  cmValue swiftCompileMode = target->GetProperty("Swift_COMPILATION_MODE");
3274
0
  if (!swiftCompileMode) {
3275
0
    swiftCompileMode = swiftCompileModeDefault;
3276
0
  }
3277
3278
0
  std::string const expandedCompileMode =
3279
0
    cmGeneratorExpression::Evaluate(*swiftCompileMode, this, config, target);
3280
0
  if (expandedCompileMode == "wholemodule") {
3281
0
    return cmSwiftCompileMode::Wholemodule;
3282
0
  }
3283
0
  if (expandedCompileMode == "singlefile") {
3284
0
    return cmSwiftCompileMode::Singlefile;
3285
0
  }
3286
0
  if (expandedCompileMode == "incremental") {
3287
0
    return cmSwiftCompileMode::Incremental;
3288
0
  }
3289
0
  return cmSwiftCompileMode::Unknown;
3290
0
}
3291
3292
bool cmLocalGenerator::IsSplitSwiftBuild() const
3293
0
{
3294
0
  return cmNonempty(this->GetMakefile()->GetDefinition(
3295
0
    "CMAKE_Swift_COMPILATION_MODE_DEFAULT"));
3296
0
}
3297
3298
namespace {
3299
3300
inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf,
3301
                                 std::string const& filename)
3302
0
{
3303
0
  target->AddSourceFileToUnityBatch(sf->ResolveFullPath());
3304
0
  sf->SetProperty("UNITY_SOURCE_FILE", filename);
3305
0
}
3306
}
3307
3308
cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource(
3309
  cmGeneratorTarget* target, std::vector<std::string> const& configs,
3310
  cmRange<std::vector<UnityBatchedSource>::const_iterator> sources,
3311
  cmValue beforeInclude, cmValue afterInclude, std::string filename,
3312
  std::string const& unityFileDirectory, UnityPathMode pathMode) const
3313
0
{
3314
0
  cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
3315
0
  cmGeneratedFileStream file(
3316
0
    filename, false, target->GetGlobalGenerator()->GetMakefileEncoding());
3317
0
  file.SetCopyIfDifferent(true);
3318
0
  file << "/* generated by CMake */\n\n";
3319
3320
0
  bool perConfig = false;
3321
0
  for (UnityBatchedSource const& ubs : sources) {
3322
0
    cm::optional<std::string> cond;
3323
0
    if (ubs.Configs.size() != configs.size()) {
3324
0
      perConfig = true;
3325
0
      cond = std::string();
3326
0
      cm::string_view sep;
3327
0
      for (size_t ci : ubs.Configs) {
3328
0
        cond = cmStrCat(*cond, sep, "defined(CMAKE_UNITY_CONFIG_",
3329
0
                        cmSystemTools::UpperCase(configs[ci]), ')');
3330
0
        sep = " || "_s;
3331
0
      }
3332
0
    }
3333
0
    RegisterUnitySources(target, ubs.Source, filename);
3334
0
    WriteUnitySourceInclude(file, cond, ubs.Source->ResolveFullPath(),
3335
0
                            beforeInclude, afterInclude, uniqueIdName,
3336
0
                            pathMode, unityFileDirectory);
3337
0
  }
3338
3339
0
  return UnitySource(std::move(filename), perConfig);
3340
0
}
3341
3342
void cmLocalGenerator::WriteUnitySourceInclude(
3343
  std::ostream& unity_file, cm::optional<std::string> const& cond,
3344
  std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude,
3345
  cmValue uniqueIdName, UnityPathMode pathMode,
3346
  std::string const& unityFileDirectory) const
3347
0
{
3348
0
  if (cond) {
3349
0
    unity_file << "#if " << *cond << "\n";
3350
0
  }
3351
3352
0
  std::string pathToHash;
3353
0
  std::string relocatableIncludePath;
3354
0
  auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
3355
0
    return (cmSystemTools::ComparePath(a, b) ||
3356
0
            cmSystemTools::IsSubDirectory(a, b));
3357
0
  };
3358
0
  auto const path = cmSystemTools::GetFilenamePath(sf_full_path);
3359
0
  if (PathEqOrSubDir(path, this->GetBinaryDirectory())) {
3360
0
    relocatableIncludePath =
3361
0
      cmSystemTools::RelativePath(unityFileDirectory, sf_full_path);
3362
0
    pathToHash = "BLD_" +
3363
0
      cmSystemTools::RelativePath(this->GetBinaryDirectory(), sf_full_path);
3364
0
  } else if (PathEqOrSubDir(path, this->GetSourceDirectory())) {
3365
0
    relocatableIncludePath =
3366
0
      cmSystemTools::RelativePath(this->GetSourceDirectory(), sf_full_path);
3367
0
    pathToHash = "SRC_" + relocatableIncludePath;
3368
0
  } else {
3369
0
    relocatableIncludePath = sf_full_path;
3370
0
    pathToHash = "ABS_" + sf_full_path;
3371
0
  }
3372
3373
0
  if (cmNonempty(uniqueIdName)) {
3374
0
    cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
3375
0
    unity_file << "/* " << pathToHash << " */\n"
3376
0
               << "#undef " << *uniqueIdName << "\n"
3377
0
               << "#define " << *uniqueIdName << " unity_"
3378
0
               << hasher.HashString(pathToHash) << "\n";
3379
0
  }
3380
3381
0
  if (beforeInclude) {
3382
0
    unity_file << *beforeInclude << "\n";
3383
0
  }
3384
3385
  // clang-tidy-17 has new include checks that needs NOLINT too.
3386
0
  unity_file
3387
0
    << "/* NOLINTNEXTLINE(bugprone-suspicious-include,misc-include-cleaner) "
3388
0
       "*/\n";
3389
0
  if (pathMode == UnityPathMode::Relative) {
3390
0
    unity_file << "#include \"" << relocatableIncludePath << "\"\n";
3391
0
  } else {
3392
0
    unity_file << "#include \"" << sf_full_path << "\"\n";
3393
0
  }
3394
3395
0
  if (afterInclude) {
3396
0
    unity_file << *afterInclude << "\n";
3397
0
  }
3398
0
  if (cond) {
3399
0
    unity_file << "#endif\n";
3400
0
  }
3401
0
  unity_file << "\n";
3402
0
}
3403
3404
namespace {
3405
std::string unity_file_extension(std::string const& lang)
3406
0
{
3407
0
  std::string extension;
3408
0
  if (lang == "C") {
3409
0
    extension = "_c.c";
3410
0
  } else if (lang == "CXX") {
3411
0
    extension = "_cxx.cxx";
3412
0
  } else if (lang == "CUDA") {
3413
0
    extension = "_cu.cu";
3414
0
  } else if (lang == "OBJC") {
3415
0
    extension = "_m.m";
3416
0
  } else if (lang == "OBJCXX") {
3417
0
    extension = "_mm.mm";
3418
0
  }
3419
0
  return extension;
3420
0
}
3421
3422
char const* unity_file_prefix(cmGeneratorTarget* target)
3423
0
{
3424
0
  if (cmValue val = target->GetProperty("UNITY_BUILD_FILENAME_PREFIX")) {
3425
0
    return val->c_str();
3426
0
  }
3427
0
  return "unity_";
3428
0
}
3429
}
3430
3431
std::vector<cmLocalGenerator::UnitySource>
3432
cmLocalGenerator::AddUnityFilesModeAuto(
3433
  cmGeneratorTarget* target, std::string const& lang,
3434
  std::vector<std::string> const& configs,
3435
  std::vector<UnityBatchedSource> const& filtered_sources,
3436
  cmValue beforeInclude, cmValue afterInclude,
3437
  std::string const& filename_base, UnityPathMode pathMode, size_t batchSize)
3438
0
{
3439
0
  if (batchSize == 0) {
3440
0
    batchSize = filtered_sources.size();
3441
0
  }
3442
0
  char const* filename_prefix = unity_file_prefix(target);
3443
0
  std::vector<UnitySource> unity_files;
3444
0
  for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0;
3445
0
       itemsLeft > 0; itemsLeft -= chunk, ++batch) {
3446
3447
0
    chunk = std::min(itemsLeft, batchSize);
3448
3449
0
    std::string filename = cmStrCat(filename_base, filename_prefix, batch,
3450
0
                                    unity_file_extension(lang));
3451
0
    auto const begin = filtered_sources.begin() + batch * batchSize;
3452
0
    auto const end = begin + chunk;
3453
0
    unity_files.emplace_back(this->WriteUnitySource(
3454
0
      target, configs, cmMakeRange(begin, end), beforeInclude, afterInclude,
3455
0
      std::move(filename), filename_base, pathMode));
3456
0
  }
3457
0
  return unity_files;
3458
0
}
3459
3460
std::vector<cmLocalGenerator::UnitySource>
3461
cmLocalGenerator::AddUnityFilesModeGroup(
3462
  cmGeneratorTarget* target, std::string const& lang,
3463
  std::vector<std::string> const& configs,
3464
  std::vector<UnityBatchedSource> const& filtered_sources,
3465
  cmValue beforeInclude, cmValue afterInclude,
3466
  std::string const& filename_base, UnityPathMode pathMode)
3467
0
{
3468
0
  std::vector<UnitySource> unity_files;
3469
3470
  // sources organized by group name. Drop any source
3471
  // without a group
3472
0
  std::unordered_map<std::string, std::vector<UnityBatchedSource>>
3473
0
    explicit_mapping;
3474
0
  for (UnityBatchedSource const& ubs : filtered_sources) {
3475
0
    if (cmValue value = ubs.Source->GetProperty("UNITY_GROUP")) {
3476
0
      auto i = explicit_mapping.find(*value);
3477
0
      if (i == explicit_mapping.end()) {
3478
0
        std::vector<UnityBatchedSource> sources{ ubs };
3479
0
        explicit_mapping.emplace(*value, std::move(sources));
3480
0
      } else {
3481
0
        i->second.emplace_back(ubs);
3482
0
      }
3483
0
    }
3484
0
  }
3485
3486
0
  char const* filename_prefix = unity_file_prefix(target);
3487
0
  for (auto const& item : explicit_mapping) {
3488
0
    auto const& name = item.first;
3489
0
    std::string filename = cmStrCat(filename_base, filename_prefix, name,
3490
0
                                    unity_file_extension(lang));
3491
0
    unity_files.emplace_back(this->WriteUnitySource(
3492
0
      target, configs, cmMakeRange(item.second), beforeInclude, afterInclude,
3493
0
      std::move(filename), filename_base, pathMode));
3494
0
  }
3495
3496
0
  return unity_files;
3497
0
}
3498
3499
void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
3500
0
{
3501
  // cmFastbuildNormalTargetGenerator handles unity build.
3502
0
  if (this->GetGlobalGenerator()->IsFastbuild() ||
3503
0
      !target->GetPropertyAsBool("UNITY_BUILD")) {
3504
0
    return;
3505
0
  }
3506
3507
0
  std::vector<UnityBatchedSource> unitySources;
3508
3509
0
  std::vector<std::string> configs =
3510
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
3511
3512
0
  std::map<cmSourceFile const*, size_t> index;
3513
3514
0
  for (size_t ci = 0; ci < configs.size(); ++ci) {
3515
    // FIXME: Refactor collection of sources to not evaluate object libraries.
3516
    // Their final set of object files might be transformed by unity builds.
3517
0
    std::vector<cmSourceFile*> sources;
3518
0
    target->GetSourceFiles(sources, configs[ci]);
3519
0
    for (cmSourceFile* sf : sources) {
3520
0
      cmGeneratorFileSet const* fileSet =
3521
0
        target->GetFileSetForSource(configs[ci], sf);
3522
0
      if (fileSet &&
3523
0
          !cm::FileSetMetadata::GetAttributes(fileSet->GetType())
3524
0
             .contains(cm::FileSetMetadata::FileSetAttributes::UnityBuild)) {
3525
0
        continue;
3526
0
      }
3527
0
      if (target->GetSourceFileLanguage(sf, configs[ci]) !=
3528
0
          sf->GetOrDetermineLanguage()) {
3529
0
        continue;
3530
0
      }
3531
      // Files which need C++ scanning cannot participate in unity builds as
3532
      // there is a single place in TUs that may perform module-dependency bits
3533
      // and a unity source cannot `#include` them in-order and represent a
3534
      // valid TU.
3535
0
      if (sf->GetLanguage() == "CXX"_s &&
3536
0
          target->NeedDyndepForSource("CXX", configs[ci], sf)) {
3537
0
        continue;
3538
0
      }
3539
3540
0
      auto mi = index.find(sf);
3541
0
      if (mi == index.end()) {
3542
0
        unitySources.emplace_back(sf);
3543
0
        std::map<cmSourceFile const*, size_t>::value_type entry(
3544
0
          sf, unitySources.size() - 1);
3545
0
        mi = index.insert(entry).first;
3546
0
      }
3547
0
      unitySources[mi->second].Configs.emplace_back(ci);
3548
0
    }
3549
0
  }
3550
3551
0
  std::string filename_base =
3552
0
    cmStrCat(target->GetCMFSupportDirectory(), "/Unity/");
3553
3554
0
  cmValue batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
3555
0
  size_t const unityBatchSize = batchSizeString
3556
0
    ? static_cast<size_t>(std::atoi(batchSizeString->c_str()))
3557
0
    : 0;
3558
3559
0
  cmValue beforeInclude =
3560
0
    target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
3561
0
  cmValue afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
3562
0
  cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE");
3563
0
  UnityPathMode pathMode = target->GetPropertyAsBool("UNITY_BUILD_RELOCATABLE")
3564
0
    ? UnityPathMode::Relative
3565
0
    : UnityPathMode::Absolute;
3566
3567
0
  for (std::string lang : { "C", "CXX", "OBJC", "OBJCXX", "CUDA" }) {
3568
0
    std::vector<UnityBatchedSource> filtered_sources;
3569
0
    std::copy_if(
3570
0
      unitySources.begin(), unitySources.end(),
3571
0
      std::back_inserter(filtered_sources),
3572
0
      [&](UnityBatchedSource const& ubs) -> bool {
3573
0
        cmSourceFile* sf = ubs.Source;
3574
0
        if (sf->GetLanguage() != lang) {
3575
0
          return false;
3576
0
        }
3577
0
        for (auto idx : ubs.Configs) {
3578
0
          cmGeneratorFileSet const* fileSet =
3579
0
            target->GetFileSetForSource(configs[idx], sf);
3580
0
          if (fileSet &&
3581
0
              (fileSet->GetProperty("SKIP_UNITY_BUILD_INCLUSION").IsOn() ||
3582
0
               fileSet->GetProperty(fileSet->BelongsTo(target)
3583
0
                                      ? "COMPILE_OPTIONS"
3584
0
                                      : "INTERFACE_COMPILE_OPTIONS") ||
3585
0
               fileSet->GetProperty(fileSet->BelongsTo(target)
3586
0
                                      ? "COMPILE_DEFINITIONS"
3587
0
                                      : "INTERFACE_COMPILE_DEFINITIONS") ||
3588
0
               fileSet->GetProperty(fileSet->BelongsTo(target)
3589
0
                                      ? "INCLUDE_DIRECTORIES"
3590
0
                                      : "INTERFACE_INCLUDE_DIRECTORIES"))) {
3591
0
            return false;
3592
0
          }
3593
0
        }
3594
0
        return !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") &&
3595
0
          !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
3596
0
          !sf->GetProperty("COMPILE_OPTIONS") &&
3597
0
          !sf->GetProperty("COMPILE_DEFINITIONS") &&
3598
0
          !sf->GetProperty("COMPILE_FLAGS") &&
3599
0
          !sf->GetProperty("INCLUDE_DIRECTORIES");
3600
0
      });
3601
3602
0
    std::vector<UnitySource> unity_files;
3603
0
    if (!unityMode || *unityMode == "BATCH") {
3604
0
      unity_files = AddUnityFilesModeAuto(
3605
0
        target, lang, configs, filtered_sources, beforeInclude, afterInclude,
3606
0
        filename_base, pathMode, unityBatchSize);
3607
0
    } else if (unityMode && *unityMode == "GROUP") {
3608
0
      unity_files = AddUnityFilesModeGroup(
3609
0
        target, lang, configs, filtered_sources, beforeInclude, afterInclude,
3610
0
        filename_base, pathMode);
3611
0
    } else {
3612
      // unity mode is set to an unsupported value
3613
0
      std::string e(cmStrCat("Invalid UNITY_BUILD_MODE value of ", *unityMode,
3614
0
                             " assigned to target ", target->GetName(),
3615
0
                             ". Acceptable values are BATCH and GROUP."));
3616
0
      this->IssueMessage(MessageType::FATAL_ERROR, e);
3617
0
    }
3618
3619
0
    for (UnitySource const& file : unity_files) {
3620
0
      auto* unity = this->GetMakefile()->GetOrCreateSource(file.Path);
3621
0
      unity->SetSpecialSourceType(
3622
0
        cmSourceFile::SpecialSourceType::UnitySource);
3623
0
      target->AddSource(file.Path, true);
3624
0
      unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON");
3625
0
      unity->SetProperty("UNITY_SOURCE_FILE", file.Path);
3626
0
      unity->SetProperty("CXX_SCAN_FOR_MODULES", "0");
3627
0
      if (file.PerConfig) {
3628
0
        unity->SetProperty("COMPILE_DEFINITIONS",
3629
0
                           "CMAKE_UNITY_CONFIG_$<UPPER_CASE:$<CONFIG>>");
3630
0
      }
3631
3632
0
      if (pathMode == UnityPathMode::Relative) {
3633
0
        unity->AppendProperty("INCLUDE_DIRECTORIES",
3634
0
                              this->GetSourceDirectory(), false);
3635
0
      }
3636
0
    }
3637
0
  }
3638
0
}
3639
3640
void cmLocalGenerator::AddPerLanguageLinkFlags(std::string& flags,
3641
                                               cmGeneratorTarget const* target,
3642
                                               std::string const& lang,
3643
                                               std::string const& config)
3644
0
{
3645
0
  switch (target->GetType()) {
3646
0
    case cm::TargetType::MODULE_LIBRARY:
3647
0
    case cm::TargetType::SHARED_LIBRARY:
3648
0
    case cm::TargetType::EXECUTABLE:
3649
0
      break;
3650
0
    default:
3651
0
      return;
3652
0
  }
3653
3654
0
  std::string langLinkFlags =
3655
0
    this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", lang, "_LINK_FLAGS"));
3656
3657
0
  switch (target->GetPolicyStatusCMP0210()) {
3658
0
    case cmPolicies::WARN:
3659
      // WARN only when CMAKE_<LANG>_LINK_FLAGS is set, and when the current
3660
      // target is not an executable, and CMAKE_<LANG>_LINK_FLAGS is not equal
3661
      // to CMAKE_EXECUTABLE_CREATE_<LANG>_FLAGS. This warns users trying to
3662
      // use the NEW behavior on old projects (since CMake will be ignoring
3663
      // their wishes), while also exempting cases when the latter variable
3664
      // (substituted for the former spelling under the NEW behavior) is being
3665
      // used legitimately by CMake.
3666
      // Additionally, WARN at most once per language, instead of on every
3667
      // target.
3668
0
      if (!langLinkFlags.empty() &&
3669
0
          target->GetType() != cm::TargetType::EXECUTABLE &&
3670
0
          langLinkFlags !=
3671
0
            this->Makefile->GetSafeDefinition(
3672
0
              cmStrCat("CMAKE_EXECUTABLE_CREATE_", lang, "_FLAGS")) &&
3673
0
          this->GlobalGenerator->ShouldWarnCMP0210(lang)) {
3674
0
        this->IssuePolicyWarning(
3675
0
          cmPolicies::CMP0210, {},
3676
0
          cmStrCat("For compatibility with older versions of CMake, CMAKE_"_s,
3677
0
                   lang,
3678
0
                   "_LINK_FLAGS will be ignored for all non-EXECUTABLE "
3679
0
                   "targets which use these flags."_s));
3680
0
      }
3681
0
      CM_FALLTHROUGH;
3682
0
    case cmPolicies::OLD:
3683
      // OLD behavior is to do nothing here, since the use of
3684
      // CMAKE_<LANG>_LINK_FLAGS for EXECUTABLEs is handled elsewhere.
3685
0
      break;
3686
0
    case cmPolicies::NEW:
3687
      // NEW behavior is to support per-language link flags for all target
3688
      // types.
3689
0
      this->AppendLinkFlagsWithParsing(flags, langLinkFlags, target, lang);
3690
0
      if (!config.empty()) {
3691
0
        std::string lankLinkFlagsConfig =
3692
0
          this->Makefile->GetSafeDefinition(cmStrCat(
3693
0
            "CMAKE_", lang, "_LINK_FLAGS_", cmSystemTools::UpperCase(config)));
3694
0
        this->AppendLinkFlagsWithParsing(flags, lankLinkFlagsConfig, target,
3695
0
                                         lang);
3696
0
      }
3697
0
      break;
3698
0
  }
3699
0
}
3700
3701
void cmLocalGenerator::AppendTargetCreationLinkFlags(
3702
  std::string& flags, cmGeneratorTarget const* target,
3703
  std::string const& linkLanguage)
3704
0
{
3705
0
  std::string createFlagsVar;
3706
0
  cmValue createFlagsVal;
3707
0
  switch (target->GetType()) {
3708
0
    case cm::TargetType::STATIC_LIBRARY:
3709
0
      break;
3710
0
    case cm::TargetType::MODULE_LIBRARY:
3711
0
      createFlagsVar =
3712
0
        cmStrCat("CMAKE_SHARED_MODULE_CREATE_", linkLanguage, "_FLAGS");
3713
0
      createFlagsVal = this->Makefile->GetDefinition(createFlagsVar);
3714
      // On some platforms we use shared library creation flags for modules.
3715
0
      CM_FALLTHROUGH;
3716
0
    case cm::TargetType::SHARED_LIBRARY:
3717
0
      if (!createFlagsVal) {
3718
0
        createFlagsVar =
3719
0
          cmStrCat("CMAKE_SHARED_LIBRARY_CREATE_", linkLanguage, "_FLAGS");
3720
0
        createFlagsVal = this->Makefile->GetDefinition(createFlagsVar);
3721
0
      }
3722
0
      break;
3723
0
    case cm::TargetType::EXECUTABLE:
3724
0
      createFlagsVar = target->GetPolicyStatusCMP0210() == cmPolicies::NEW
3725
0
        ? cmStrCat("CMAKE_EXECUTABLE_CREATE_", linkLanguage, "_FLAGS")
3726
0
        : cmStrCat("CMAKE_", linkLanguage, "_LINK_FLAGS");
3727
0
      createFlagsVal = this->Makefile->GetDefinition(createFlagsVar);
3728
0
      break;
3729
0
    default:
3730
0
      break;
3731
0
  }
3732
0
  if (createFlagsVal) {
3733
0
    this->AppendFlags(flags, *createFlagsVal, createFlagsVar, target,
3734
0
                      cmBuildStep::Link, linkLanguage);
3735
0
  }
3736
0
}
3737
3738
void cmLocalGenerator::AppendLinkerTypeFlags(std::string& flags,
3739
                                             cmGeneratorTarget* target,
3740
                                             std::string const& config,
3741
                                             std::string const& linkLanguage)
3742
0
{
3743
0
  switch (target->GetType()) {
3744
0
    case cm::TargetType::EXECUTABLE:
3745
0
    case cm::TargetType::SHARED_LIBRARY:
3746
0
    case cm::TargetType::MODULE_LIBRARY:
3747
0
      break;
3748
0
    default:
3749
0
      return;
3750
0
  }
3751
3752
0
  auto linkMode =
3753
0
    cmStrCat("CMAKE_", linkLanguage, target->IsDeviceLink() ? "_DEVICE_" : "_",
3754
0
             "LINK_MODE");
3755
0
  auto mode = this->Makefile->GetDefinition(linkMode);
3756
0
  if (mode && mode != "DRIVER"_s) {
3757
0
    return;
3758
0
  }
3759
3760
0
  auto linkerType = target->GetLinkerTypeProperty(linkLanguage, config);
3761
0
  if (linkerType.empty()) {
3762
0
    linkerType = "DEFAULT";
3763
0
  }
3764
0
  auto usingLinker =
3765
0
    cmStrCat("CMAKE_", linkLanguage, "_USING_",
3766
0
             target->IsDeviceLink() ? "DEVICE_" : "", "LINKER_", linkerType);
3767
0
  auto linkerTypeFlags = this->Makefile->GetDefinition(usingLinker);
3768
0
  if (linkerTypeFlags) {
3769
0
    if (!linkerTypeFlags.IsEmpty()) {
3770
0
      auto linkerFlags = cmExpandListWithBacktrace(linkerTypeFlags);
3771
0
      target->ResolveLinkerWrapper(linkerFlags, linkLanguage);
3772
0
      this->AppendFlags(flags, linkerFlags);
3773
0
    }
3774
0
  } else if (linkerType != "DEFAULT"_s) {
3775
0
    auto isCMakeLinkerType = [](std::string const& type) -> bool {
3776
0
      return std::all_of(type.cbegin(), type.cend(), cmsysString_isupper);
3777
0
    };
3778
0
    if (isCMakeLinkerType(linkerType)) {
3779
0
      this->IssueMessage(
3780
0
        MessageType::FATAL_ERROR,
3781
0
        cmStrCat("LINKER_TYPE '", linkerType,
3782
0
                 "' is unknown or not supported by this toolchain."));
3783
0
    } else {
3784
0
      this->IssueMessage(
3785
0
        MessageType::FATAL_ERROR,
3786
0
        cmStrCat("LINKER_TYPE '", linkerType,
3787
0
                 "' is unknown. Did you forget to define the '", usingLinker,
3788
0
                 "' variable?"));
3789
0
    }
3790
0
  }
3791
0
}
3792
3793
void cmLocalGenerator::AddTargetTypeLinkerFlags(
3794
  std::string& flags, cmGeneratorTarget const* target, std::string const& lang,
3795
  std::string const& config)
3796
0
{
3797
0
  std::string linkerFlagsVar;
3798
0
  switch (target->GetType()) {
3799
0
    case cm::TargetType::EXECUTABLE:
3800
0
      linkerFlagsVar = "CMAKE_EXE_LINKER_FLAGS";
3801
0
      break;
3802
0
    case cm::TargetType::SHARED_LIBRARY:
3803
0
      linkerFlagsVar = "CMAKE_SHARED_LINKER_FLAGS";
3804
0
      break;
3805
0
    case cm::TargetType::MODULE_LIBRARY:
3806
0
      linkerFlagsVar = "CMAKE_MODULE_LINKER_FLAGS";
3807
0
      break;
3808
0
    default:
3809
0
      return;
3810
0
  }
3811
0
  this->AddConfigVariableFlags(flags, linkerFlagsVar, target,
3812
0
                               cmBuildStep::Link, lang, config);
3813
0
}
3814
3815
void cmLocalGenerator::AddTargetPropertyLinkFlags(
3816
  std::string& flags, cmGeneratorTarget const* target,
3817
  std::string const& config)
3818
0
{
3819
0
  cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
3820
0
  if (targetLinkFlags) {
3821
0
    this->AppendFlags(flags, *targetLinkFlags);
3822
0
  }
3823
0
  if (!config.empty()) {
3824
0
    cmValue targetLinkFlagsConfig = target->GetProperty(
3825
0
      cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(config)));
3826
0
    if (targetLinkFlagsConfig) {
3827
0
      this->AppendFlags(flags, *targetLinkFlagsConfig);
3828
0
    }
3829
0
  }
3830
0
}
3831
3832
void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
3833
                                            cmGeneratorTarget* target,
3834
                                            std::string const& config,
3835
                                            std::string const& lang)
3836
0
{
3837
0
  if (!target->IsIPOEnabled(lang, config)) {
3838
0
    return;
3839
0
  }
3840
3841
0
  switch (target->GetType()) {
3842
0
    case cm::TargetType::EXECUTABLE:
3843
0
    case cm::TargetType::SHARED_LIBRARY:
3844
0
    case cm::TargetType::MODULE_LIBRARY:
3845
0
      break;
3846
0
    default:
3847
0
      return;
3848
0
  }
3849
3850
0
  std::string const name = cmStrCat("CMAKE_", lang, "_LINK_OPTIONS_IPO");
3851
0
  cmValue rawFlagsList = this->Makefile->GetDefinition(name);
3852
0
  if (!rawFlagsList) {
3853
0
    return;
3854
0
  }
3855
3856
0
  cmList flagsList{ *rawFlagsList };
3857
0
  for (std::string const& o : flagsList) {
3858
0
    this->AppendFlagEscape(flags, o);
3859
0
  }
3860
0
}
3861
3862
void cmLocalGenerator::AppendPositionIndependentLinkerFlags(
3863
  std::string& flags, cmGeneratorTarget* target, std::string const& config,
3864
  std::string const& lang)
3865
0
{
3866
  // For now, only EXECUTABLE is concerned
3867
0
  if (target->GetType() != cm::TargetType::EXECUTABLE) {
3868
0
    return;
3869
0
  }
3870
3871
0
  char const* PICValue = target->GetLinkPIEProperty(config);
3872
0
  if (!PICValue && lang != "Rust") {
3873
    // POSITION_INDEPENDENT_CODE is not set, note that for Rust we do not
3874
    // return as the compiler tends to enable PIE all the time, which is the
3875
    // opposite of what C & C++ compilers do. So instead of letting the rust
3876
    // compiler decide on its own whether PIE should be enabled, we explicit
3877
    // set it.
3878
0
    return;
3879
0
  }
3880
3881
0
  std::string const mode = cmIsOn(PICValue) ? "PIE" : "NO_PIE";
3882
3883
0
  std::string supported =
3884
0
    cmStrCat("CMAKE_", lang, "_LINK_", mode, "_SUPPORTED");
3885
0
  if (this->Makefile->GetDefinition(supported).IsOff()) {
3886
0
    return;
3887
0
  }
3888
3889
0
  std::string name = cmStrCat("CMAKE_", lang, "_LINK_OPTIONS_", mode);
3890
3891
0
  auto pieFlags = this->Makefile->GetSafeDefinition(name);
3892
0
  if (pieFlags.empty()) {
3893
0
    return;
3894
0
  }
3895
3896
0
  cmList flagsList{ pieFlags };
3897
0
  for (auto const& flag : flagsList) {
3898
0
    this->AppendFlagEscape(flags, flag);
3899
0
  }
3900
0
}
3901
3902
void cmLocalGenerator::AppendWarningAsErrorLinkerFlags(
3903
  std::string& flags, cmGeneratorTarget* target, std::string const& lang)
3904
0
{
3905
0
  if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) {
3906
0
    return;
3907
0
  }
3908
3909
0
  switch (target->GetType()) {
3910
0
    case cm::TargetType::EXECUTABLE:
3911
0
    case cm::TargetType::SHARED_LIBRARY:
3912
0
    case cm::TargetType::MODULE_LIBRARY:
3913
0
      break;
3914
0
    default:
3915
0
      return;
3916
0
  }
3917
3918
0
  auto const wError = target->GetProperty("LINK_WARNING_AS_ERROR");
3919
0
  if (wError.IsOff()) {
3920
0
    return;
3921
0
  }
3922
0
  cmList wErrorOptions;
3923
0
  if (wError.IsOn()) {
3924
0
    wErrorOptions = { "DRIVER", "LINKER" };
3925
0
  } else {
3926
0
    wErrorOptions = wError;
3927
0
    std::sort(wErrorOptions.begin(), wErrorOptions.end());
3928
0
    wErrorOptions.erase(
3929
0
      std::unique(wErrorOptions.begin(), wErrorOptions.end()),
3930
0
      wErrorOptions.end());
3931
0
  }
3932
3933
0
  auto linkModeIsDriver =
3934
0
    this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_LINK_MODE")) ==
3935
0
    "DRIVER"_s;
3936
0
  std::string errorMessage;
3937
0
  for (auto const& option : wErrorOptions) {
3938
0
    if (option != "DRIVER"_s && option != "LINKER"_s) {
3939
0
      errorMessage = cmStrCat(std::move(errorMessage), "  ", option, '\n');
3940
0
      continue;
3941
0
    }
3942
3943
0
    if (option == "DRIVER"_s && !linkModeIsDriver) {
3944
0
      continue;
3945
0
    }
3946
3947
0
    auto const wErrorOpts = this->Makefile->GetDefinition(cmStrCat(
3948
0
      "CMAKE_", lang, '_', (option == "DRIVER"_s ? "COMPILE" : "LINK"),
3949
0
      "_OPTIONS_WARNING_AS_ERROR"));
3950
0
    if (wErrorOpts.IsSet()) {
3951
0
      auto items =
3952
0
        cmExpandListWithBacktrace(wErrorOpts, target->GetBacktrace());
3953
0
      if (option == "LINKER"_s) {
3954
0
        target->ResolveLinkerWrapper(items, lang);
3955
0
      }
3956
0
      for (auto const& item : items) {
3957
0
        this->AppendFlagEscape(flags, item.Value);
3958
0
      }
3959
0
    }
3960
0
  }
3961
0
  if (!errorMessage.empty()) {
3962
0
    this->Makefile->GetCMakeInstance()->IssueMessage(
3963
0
      MessageType::FATAL_ERROR,
3964
0
      cmStrCat(
3965
0
        "Erroneous value(s) for 'LINK_WARNING_AS_ERROR' property of target '",
3966
0
        target->GetName(), "':\n", errorMessage));
3967
0
  }
3968
0
}
3969
3970
void cmLocalGenerator::AppendDependencyInfoLinkerFlags(
3971
  std::string& flags, cmGeneratorTarget* target, std::string const& config,
3972
  std::string const& linkLanguage)
3973
0
{
3974
0
  if (!this->GetGlobalGenerator()->SupportsLinkerDependencyFile() ||
3975
0
      !target->HasLinkDependencyFile(config)) {
3976
0
    return;
3977
0
  }
3978
3979
0
  auto depFlag = *this->Makefile->GetDefinition(
3980
0
    cmStrCat("CMAKE_", linkLanguage, "_LINKER_DEPFILE_FLAGS"));
3981
0
  if (depFlag.empty()) {
3982
0
    return;
3983
0
  }
3984
3985
0
  auto depFile = this->ConvertToOutputFormat(
3986
0
    this->MaybeRelativeToWorkDir(this->GetLinkDependencyFile(target, config)),
3987
0
    cmOutputConverter::SHELL);
3988
0
  auto rulePlaceholderExpander = this->CreateRulePlaceholderExpander();
3989
0
  cmRulePlaceholderExpander::RuleVariables linkDepsVariables;
3990
0
  linkDepsVariables.DependencyFile = depFile.c_str();
3991
0
  rulePlaceholderExpander->ExpandRuleVariables(this, depFlag,
3992
0
                                               linkDepsVariables);
3993
0
  auto depFlags = cmExpandListWithBacktrace(depFlag);
3994
0
  target->ResolveLinkerWrapper(depFlags, linkLanguage);
3995
3996
0
  this->AppendFlags(flags, depFlags);
3997
0
}
3998
3999
std::string cmLocalGenerator::GetLinkDependencyFile(
4000
  cmGeneratorTarget* /*target*/, std::string const& /*config*/) const
4001
0
{
4002
0
  return "link.d";
4003
0
}
4004
4005
void cmLocalGenerator::AppendModuleDefinitionFlag(
4006
  std::string& flags, cmGeneratorTarget const* target,
4007
  cmLinkLineComputer* linkLineComputer, std::string const& config,
4008
  std::string const& lang)
4009
0
{
4010
0
  cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
4011
0
    target->GetModuleDefinitionInfo(config);
4012
0
  if (!mdi || mdi->DefFile.empty()) {
4013
0
    return;
4014
0
  }
4015
4016
0
  cmValue defFileFlag = this->Makefile->GetDefinition(
4017
0
    cmStrCat("CMAKE_", lang, "_LINK_DEF_FILE_FLAG"));
4018
0
  if (!defFileFlag) {
4019
0
    defFileFlag = this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG");
4020
0
  }
4021
0
  if (!defFileFlag) {
4022
0
    return;
4023
0
  }
4024
4025
  // Append the flag and value.  Use ConvertToLinkReference to help
4026
  // vs6's "cl -link" pass it to the linker.
4027
0
  std::string flag =
4028
0
    cmStrCat(*defFileFlag,
4029
0
             this->ConvertToOutputFormat(
4030
0
               linkLineComputer->ConvertToLinkReference(mdi->DefFile),
4031
0
               cmOutputConverter::SHELL));
4032
0
  this->AppendFlags(flags, flag);
4033
0
}
4034
4035
bool cmLocalGenerator::AppendLWYUFlags(std::string& flags,
4036
                                       cmGeneratorTarget const* target,
4037
                                       std::string const& lang)
4038
0
{
4039
0
  auto useLWYU = target->GetPropertyAsBool("LINK_WHAT_YOU_USE") &&
4040
0
    (target->GetType() == cm::TargetType::EXECUTABLE ||
4041
0
     target->GetType() == cm::TargetType::SHARED_LIBRARY ||
4042
0
     target->GetType() == cm::TargetType::MODULE_LIBRARY);
4043
4044
0
  if (useLWYU) {
4045
0
    auto const& lwyuFlag = this->GetMakefile()->GetSafeDefinition(
4046
0
      cmStrCat("CMAKE_", lang, "_LINK_WHAT_YOU_USE_FLAG"));
4047
0
    useLWYU = !lwyuFlag.empty();
4048
4049
0
    if (useLWYU) {
4050
0
      std::vector<BT<std::string>> lwyuOpts;
4051
0
      lwyuOpts.emplace_back(lwyuFlag);
4052
0
      this->AppendFlags(flags, target->ResolveLinkerWrapper(lwyuOpts, lang));
4053
0
    }
4054
0
  }
4055
4056
0
  return useLWYU;
4057
0
}
4058
4059
void cmLocalGenerator::AppendCompileOptions(std::string& options,
4060
                                            std::string const& options_list,
4061
                                            char const* regex) const
4062
0
{
4063
  // Short-circuit if there are no options.
4064
0
  if (options_list.empty()) {
4065
0
    return;
4066
0
  }
4067
4068
  // Expand the list of options.
4069
0
  cmList options_vec{ options_list };
4070
0
  this->AppendCompileOptions(options, options_vec, regex);
4071
0
}
4072
4073
void cmLocalGenerator::AppendCompileOptions(
4074
  std::string& options, std::vector<std::string> const& options_vec,
4075
  char const* regex) const
4076
0
{
4077
0
  if (regex) {
4078
    // Filter flags upon specified reges.
4079
0
    cmsys::RegularExpression r(regex);
4080
4081
0
    for (std::string const& opt : options_vec) {
4082
0
      if (r.find(opt)) {
4083
0
        this->AppendFlagEscape(options, opt);
4084
0
      }
4085
0
    }
4086
0
  } else {
4087
0
    for (std::string const& opt : options_vec) {
4088
0
      this->AppendFlagEscape(options, opt);
4089
0
    }
4090
0
  }
4091
0
}
4092
4093
void cmLocalGenerator::AppendCompileOptions(
4094
  std::vector<BT<std::string>>& options,
4095
  std::vector<BT<std::string>> const& options_vec, char const* regex) const
4096
0
{
4097
0
  if (regex) {
4098
    // Filter flags upon specified regular expressions.
4099
0
    cmsys::RegularExpression r(regex);
4100
4101
0
    for (BT<std::string> const& opt : options_vec) {
4102
0
      if (r.find(opt.Value)) {
4103
0
        std::string flag;
4104
0
        this->AppendFlagEscape(flag, opt.Value);
4105
0
        options.emplace_back(std::move(flag), opt.Backtrace);
4106
0
      }
4107
0
    }
4108
0
  } else {
4109
0
    for (BT<std::string> const& opt : options_vec) {
4110
0
      std::string flag;
4111
0
      this->AppendFlagEscape(flag, opt.Value);
4112
0
      options.emplace_back(std::move(flag), opt.Backtrace);
4113
0
    }
4114
0
  }
4115
0
}
4116
4117
void cmLocalGenerator::AppendIncludeDirectories(
4118
  std::vector<std::string>& includes, std::string const& includes_list,
4119
  cmSourceFile const& sourceFile) const
4120
0
{
4121
  // Short-circuit if there are no includes.
4122
0
  if (includes_list.empty()) {
4123
0
    return;
4124
0
  }
4125
4126
  // Expand the list of includes.
4127
0
  cmList includes_vec{ includes_list };
4128
0
  this->AppendIncludeDirectories(includes, includes_vec, sourceFile);
4129
0
}
4130
4131
void cmLocalGenerator::AppendIncludeDirectories(
4132
  std::vector<std::string>& includes,
4133
  std::vector<std::string> const& includes_vec,
4134
  cmSourceFile const& sourceFile) const
4135
0
{
4136
0
  std::unordered_set<std::string> uniqueIncludes;
4137
4138
0
  for (std::string const& include : includes_vec) {
4139
0
    if (!cmSystemTools::FileIsFullPath(include)) {
4140
0
      this->IssueMessage(
4141
0
        MessageType::FATAL_ERROR,
4142
0
        cmStrCat("Found relative path while evaluating include directories of "
4143
0
                 "\"",
4144
0
                 sourceFile.GetLocation().GetName(), "\":\n  \"", include,
4145
0
                 "\"\n"));
4146
0
      return;
4147
0
    }
4148
4149
0
    std::string inc = include;
4150
4151
0
    if (!cmIsOff(inc)) {
4152
0
      cmSystemTools::ConvertToUnixSlashes(inc);
4153
0
    }
4154
4155
0
    if (uniqueIncludes.insert(inc).second) {
4156
0
      includes.push_back(std::move(inc));
4157
0
    }
4158
0
  }
4159
0
}
4160
4161
void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
4162
                                     std::string const& defines_list) const
4163
0
{
4164
0
  std::set<BT<std::string>> tmp;
4165
0
  this->AppendDefines(tmp, cmExpandListWithBacktrace(defines_list));
4166
0
  for (BT<std::string> const& i : tmp) {
4167
0
    defines.emplace(i.Value);
4168
0
  }
4169
0
}
4170
4171
void cmLocalGenerator::AppendDefines(
4172
  std::set<std::string>& defines,
4173
  std::vector<BT<std::string>> const& defines_vec) const
4174
0
{
4175
0
  std::set<BT<std::string>> tmp;
4176
0
  this->AppendDefines(tmp, defines_vec);
4177
0
  for (BT<std::string> const& i : tmp) {
4178
0
    defines.emplace(i.Value);
4179
0
  }
4180
0
}
4181
4182
void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines,
4183
                                     std::string const& defines_list) const
4184
0
{
4185
  // Short-circuit if there are no definitions.
4186
0
  if (defines_list.empty()) {
4187
0
    return;
4188
0
  }
4189
4190
  // Expand the list of definitions.
4191
0
  this->AppendDefines(defines, cmExpandListWithBacktrace(defines_list));
4192
0
}
4193
4194
void cmLocalGenerator::AppendDefines(
4195
  std::set<BT<std::string>>& defines,
4196
  std::vector<BT<std::string>> const& defines_vec) const
4197
0
{
4198
0
  for (BT<std::string> const& d : defines_vec) {
4199
    // Skip unsupported definitions.
4200
0
    if (!this->CheckDefinition(d.Value)) {
4201
0
      continue;
4202
0
    }
4203
    // remove any leading -D
4204
0
    if (cmHasLiteralPrefix(d.Value, "-D")) {
4205
0
      defines.emplace(d.Value.substr(2), d.Backtrace);
4206
0
    } else {
4207
0
      defines.insert(d);
4208
0
    }
4209
0
  }
4210
0
}
4211
4212
void cmLocalGenerator::JoinDefines(std::set<std::string> const& defines,
4213
                                   std::string& definesString,
4214
                                   std::string const& lang)
4215
0
{
4216
  // Lookup the define flag for the current language.
4217
0
  std::string dflag = "-D";
4218
0
  if (!lang.empty()) {
4219
0
    cmValue df =
4220
0
      this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_DEFINE_FLAG"));
4221
0
    if (cmNonempty(df)) {
4222
0
      dflag = *df;
4223
0
    }
4224
0
  }
4225
0
  char const* itemSeparator = definesString.empty() ? "" : " ";
4226
0
  for (std::string const& define : defines) {
4227
    // Append the definition with proper escaping.
4228
0
    std::string def = dflag;
4229
0
    if (this->GetState()->UseWatcomWMake()) {
4230
      // The Watcom compiler does its own command line parsing instead
4231
      // of using the windows shell rules.  Definitions are one of
4232
      //   -DNAME
4233
      //   -DNAME=<cpp-token>
4234
      //   -DNAME="c-string with spaces and other characters(?@#$)"
4235
      //
4236
      // Watcom will properly parse each of these cases from the
4237
      // command line without any escapes.  However we still have to
4238
      // get the '$' and '#' characters through WMake as '$$' and
4239
      // '$#'.
4240
0
      for (char c : define) {
4241
0
        if (c == '$' || c == '#') {
4242
0
          def += '$';
4243
0
        }
4244
0
        def += c;
4245
0
      }
4246
0
    } else {
4247
      // Make the definition appear properly on the command line.  Use
4248
      // -DNAME="value" instead of -D"NAME=value" for historical reasons.
4249
0
      std::string::size_type eq = define.find('=');
4250
0
      def += define.substr(0, eq);
4251
0
      if (eq != std::string::npos) {
4252
0
        def += "=";
4253
0
        def += this->EscapeForShell(define.substr(eq + 1), true);
4254
0
      }
4255
0
    }
4256
0
    definesString += itemSeparator;
4257
0
    itemSeparator = " ";
4258
0
    definesString += def;
4259
0
  }
4260
0
}
4261
4262
void cmLocalGenerator::AppendFeatureOptions(std::string& flags,
4263
                                            std::string const& lang,
4264
                                            char const* feature)
4265
0
{
4266
0
  cmValue optionList = this->Makefile->GetDefinition(
4267
0
    cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature));
4268
0
  if (optionList) {
4269
0
    cmList options{ *optionList };
4270
0
    for (std::string const& o : options) {
4271
0
      this->AppendFlagEscape(flags, o);
4272
0
    }
4273
0
  }
4274
0
}
4275
4276
cmValue cmLocalGenerator::GetFeature(std::string const& feature,
4277
                                     std::string const& config)
4278
0
{
4279
0
  std::string featureName = feature;
4280
  // TODO: Define accumulation policy for features (prepend, append,
4281
  // replace). Currently we always replace.
4282
0
  if (!config.empty()) {
4283
0
    featureName += "_";
4284
0
    featureName += cmSystemTools::UpperCase(config);
4285
0
  }
4286
0
  cmStateSnapshot snp = this->StateSnapshot;
4287
0
  while (snp.IsValid()) {
4288
0
    if (cmValue value = snp.GetDirectory().GetProperty(featureName)) {
4289
0
      return value;
4290
0
    }
4291
0
    snp = snp.GetBuildsystemDirectoryParent();
4292
0
  }
4293
0
  return nullptr;
4294
0
}
4295
4296
std::string cmLocalGenerator::GetProjectName() const
4297
0
{
4298
0
  return this->StateSnapshot.GetProjectName();
4299
0
}
4300
4301
std::string cmLocalGenerator::ConstructComment(
4302
  cmCustomCommandGenerator const& ccg, char const* default_comment) const
4303
0
{
4304
  // Check for a comment provided with the command.
4305
0
  if (cm::optional<std::string> comment = ccg.GetComment()) {
4306
0
    return *comment;
4307
0
  }
4308
4309
  // Construct a reasonable default comment if possible.
4310
0
  if (!ccg.GetOutputs().empty()) {
4311
0
    std::string comment;
4312
0
    comment = "Generating ";
4313
0
    char const* sep = "";
4314
0
    for (std::string const& o : ccg.GetOutputs()) {
4315
0
      comment += sep;
4316
0
      comment += this->MaybeRelativeToCurBinDir(o);
4317
0
      sep = ", ";
4318
0
    }
4319
0
    return comment;
4320
0
  }
4321
4322
  // Otherwise use the provided default.
4323
0
  return default_comment;
4324
0
}
4325
4326
class cmInstallTargetGeneratorLocal : public cmInstallTargetGenerator
4327
{
4328
public:
4329
  cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t,
4330
                                std::string const& dest, bool implib)
4331
0
    : cmInstallTargetGenerator(
4332
0
        t, dest, implib, "", std::vector<std::string>(), "Unspecified",
4333
0
        cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false,
4334
0
        false)
4335
0
  {
4336
0
    this->Compute(lg);
4337
0
  }
4338
};
4339
4340
void cmLocalGenerator::GenerateTargetInstallRules(
4341
  std::ostream& os, std::string const& config,
4342
  std::vector<std::string> const& configurationTypes)
4343
0
{
4344
  // Convert the old-style install specification from each target to
4345
  // an install generator and run it.
4346
0
  auto const& tgts = this->GetGeneratorTargets();
4347
0
  for (auto const& l : tgts) {
4348
0
    if (l->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
4349
0
      continue;
4350
0
    }
4351
4352
    // Include the user-specified pre-install script for this target.
4353
0
    if (cmValue preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) {
4354
0
      cmInstallScriptGenerator g(*preinstall, false, "", false, false);
4355
0
      g.Generate(os, config, configurationTypes);
4356
0
    }
4357
4358
    // Install this target if a destination is given.
4359
0
    if (!l->Target->GetInstallPath().empty()) {
4360
      // Compute the full install destination.  Note that converting
4361
      // to unix slashes also removes any trailing slash.
4362
      // We also skip over the leading slash given by the user.
4363
0
      std::string destination = l->Target->GetInstallPath().substr(1);
4364
0
      cmSystemTools::ConvertToUnixSlashes(destination);
4365
0
      if (destination.empty()) {
4366
0
        destination = ".";
4367
0
      }
4368
4369
      // Generate the proper install generator for this target type.
4370
0
      switch (l->GetType()) {
4371
0
        case cm::TargetType::EXECUTABLE:
4372
0
        case cm::TargetType::STATIC_LIBRARY:
4373
0
        case cm::TargetType::MODULE_LIBRARY: {
4374
          // Use a target install generator.
4375
0
          cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
4376
0
                                          false);
4377
0
          g.Generate(os, config, configurationTypes);
4378
0
        } break;
4379
0
        case cm::TargetType::SHARED_LIBRARY: {
4380
#if defined(_WIN32) || defined(__CYGWIN__)
4381
          // Special code to handle DLL.  Install the import library
4382
          // to the normal destination and the DLL to the runtime
4383
          // destination.
4384
          cmInstallTargetGeneratorLocal g1(this, l->GetName(), destination,
4385
                                           true);
4386
          g1.Generate(os, config, configurationTypes);
4387
          // We also skip over the leading slash given by the user.
4388
          destination = l->Target->GetRuntimeInstallPath().substr(1);
4389
          cmSystemTools::ConvertToUnixSlashes(destination);
4390
          cmInstallTargetGeneratorLocal g2(this, l->GetName(), destination,
4391
                                           false);
4392
          g2.Generate(os, config, configurationTypes);
4393
#else
4394
          // Use a target install generator.
4395
0
          cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
4396
0
                                          false);
4397
0
          g.Generate(os, config, configurationTypes);
4398
0
#endif
4399
0
        } break;
4400
0
        default:
4401
0
          break;
4402
0
      }
4403
0
    }
4404
4405
    // Include the user-specified post-install script for this target.
4406
0
    if (cmValue postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) {
4407
0
      cmInstallScriptGenerator g(*postinstall, false, "", false, false);
4408
0
      g.Generate(os, config, configurationTypes);
4409
0
    }
4410
0
  }
4411
0
}
4412
4413
namespace {
4414
bool cmLocalGeneratorShortenObjectName(std::string& objName,
4415
                                       std::string::size_type max_len)
4416
0
{
4417
  // Check if the path can be shortened using an md5 sum replacement for
4418
  // a portion of the path.
4419
0
  std::string::size_type md5Len = 32;
4420
0
  std::string::size_type numExtraChars = objName.size() - max_len + md5Len;
4421
0
  std::string::size_type pos = objName.find('/', numExtraChars);
4422
0
  if (pos == std::string::npos) {
4423
0
    pos = objName.rfind('/', numExtraChars);
4424
0
    if (pos == std::string::npos || pos <= md5Len) {
4425
0
      return false;
4426
0
    }
4427
0
  }
4428
4429
  // Replace the beginning of the path portion of the object name with
4430
  // its own md5 sum.
4431
0
  cmCryptoHash md5(cmCryptoHash::AlgoMD5);
4432
0
  std::string md5name = cmStrCat(md5.HashString(objName.substr(0, pos)),
4433
0
                                 cm::string_view(objName).substr(pos));
4434
0
  objName = md5name;
4435
4436
  // The object name is now shorter, check if it is short enough.
4437
0
  return pos >= numExtraChars;
4438
0
}
4439
4440
bool cmLocalGeneratorCheckObjectName(std::string& objName,
4441
                                     std::string::size_type dir_len,
4442
                                     std::string::size_type max_total_len)
4443
0
{
4444
  // Enforce the maximum file name length if possible.
4445
0
  std::string::size_type max_obj_len = max_total_len;
4446
0
  if (dir_len < max_total_len) {
4447
0
    max_obj_len = max_total_len - dir_len;
4448
0
    if (objName.size() > max_obj_len) {
4449
      // The current object file name is too long.  Try to shorten it.
4450
0
      return cmLocalGeneratorShortenObjectName(objName, max_obj_len);
4451
0
    }
4452
    // The object file name is short enough.
4453
0
    return true;
4454
0
  }
4455
  // The build directory in which the object will be stored is
4456
  // already too deep.
4457
0
  return false;
4458
0
}
4459
}
4460
4461
std::string cmLocalGenerator::CreateSafeObjectFileName(
4462
  std::string const& sin) const
4463
0
{
4464
  // Start with the original name.
4465
0
  std::string ssin = sin;
4466
4467
  // Avoid full paths by removing leading slashes.
4468
0
  ssin.erase(0, ssin.find_first_not_of('/'));
4469
4470
  // Avoid full paths by removing colons.
4471
0
  std::replace(ssin.begin(), ssin.end(), ':', '_');
4472
4473
  // Avoid relative paths that go up the tree.
4474
0
  cmSystemTools::ReplaceString(ssin, "../", "__/");
4475
4476
  // Avoid spaces.
4477
0
  std::replace(ssin.begin(), ssin.end(), ' ', '_');
4478
4479
0
  return ssin;
4480
0
}
4481
4482
// search a the source group defined for the file set or the source itself
4483
// in case of match, result is stored in a cache to speed-up future searches
4484
cmSourceGroup* cmLocalGenerator::FindSourceGroup(
4485
  cmGeneratorTarget const* target, cmSourceFile const* source,
4486
  std::string const& config)
4487
0
{
4488
0
#if !defined(CMAKE_BOOTSTRAP)
4489
0
  std::string const SOURCE_GROUP{ "SOURCE_GROUP" };
4490
0
  std::string const& targetName = target->GetName();
4491
0
  cmGeneratorFileSet const* fileSet =
4492
0
    target->GetFileSetForSource(config, source);
4493
4494
0
  if (fileSet) {
4495
0
    std::string fsName = fileSet->GetName();
4496
0
    std::string const fsKey = cmStrCat(targetName, "::", fsName);
4497
0
    auto const indexIt = this->SourceGroupSearchIndex.find(fsKey);
4498
0
    if (indexIt != this->SourceGroupSearchIndex.cend()) {
4499
0
      return indexIt->second;
4500
0
    }
4501
4502
0
    cmValue fsSG = fileSet->GetProperty(SOURCE_GROUP);
4503
0
    if (!fsSG.IsEmpty()) {
4504
0
      cmSourceGroup* sg = this->GetMakefile()->GetOrCreateSourceGroup(*fsSG);
4505
0
      this->SourceGroupSearchIndex.emplace(fsKey, sg);
4506
0
      return sg;
4507
0
    }
4508
4509
0
    cmSourceGroup* sourceGroup = cmSourceGroup::FindSourceGroup(
4510
0
      targetName, fsName, this->Makefile->GetSourceGroups());
4511
0
    if (sourceGroup) {
4512
0
      this->SourceGroupSearchIndex.emplace(fsKey, sourceGroup);
4513
0
      return sourceGroup;
4514
0
    }
4515
0
  }
4516
4517
  // no source group defined for the file set or the source is not part of a
4518
  // file set.
4519
  // search for source group defined at source level
4520
0
  auto const indexIt =
4521
0
    this->SourceGroupSearchIndex.find(source->GetFullPath());
4522
0
  if (indexIt != this->SourceGroupSearchIndex.cend()) {
4523
0
    return indexIt->second;
4524
0
  }
4525
4526
0
  cmValue srcSG = source->GetProperty(SOURCE_GROUP);
4527
0
  if (!srcSG.IsEmpty()) {
4528
0
    cmSourceGroup* sg = this->GetMakefile()->GetOrCreateSourceGroup(*srcSG);
4529
0
    this->SourceGroupSearchIndex.emplace(source->GetFullPath(), sg);
4530
0
    return sg;
4531
0
  }
4532
4533
  // look-up in source groups definitions
4534
0
  return this->FindSourceGroup(source->GetFullPath());
4535
#else
4536
  static_cast<void>(target);
4537
  static_cast<void>(source);
4538
  static_cast<void>(config);
4539
  return nullptr;
4540
#endif
4541
0
}
4542
4543
cmSourceGroup* cmLocalGenerator::FindSourceGroup(std::string const& source)
4544
0
{
4545
0
#if !defined(CMAKE_BOOTSTRAP)
4546
0
  auto const indexIt = SourceGroupSearchIndex.find(source);
4547
0
  if (indexIt != SourceGroupSearchIndex.cend()) {
4548
0
    if (cmSourceGroup* result = indexIt->second) {
4549
0
      return result;
4550
0
    }
4551
0
  }
4552
4553
0
  cmSourceGroup* sourceGroup =
4554
0
    cmSourceGroup::FindSourceGroup(source, this->Makefile->GetSourceGroups());
4555
0
  if (sourceGroup) {
4556
    // Update index if we have a miss
4557
0
    SourceGroupSearchIndex.emplace(source, sourceGroup);
4558
0
  }
4559
0
  return sourceGroup;
4560
#else
4561
  static_cast<void>(source);
4562
  return nullptr;
4563
#endif
4564
0
}
4565
4566
std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(
4567
  std::string const& sin, std::string const& dir_max)
4568
0
{
4569
  // Look for an existing mapped name for this object file.
4570
0
  auto it = this->UniqueObjectNamesMap.find(sin);
4571
4572
  // If no entry exists create one.
4573
0
  if (it == this->UniqueObjectNamesMap.end()) {
4574
0
    auto ssin = this->CreateSafeObjectFileName(sin);
4575
4576
    // Mangle the name if necessary.
4577
0
    if (this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES")) {
4578
0
      bool done;
4579
0
      int cc = 0;
4580
0
      char rpstr[100];
4581
0
      snprintf(rpstr, sizeof(rpstr), "_p_");
4582
0
      cmSystemTools::ReplaceString(ssin, "+", rpstr);
4583
0
      std::string sssin = sin;
4584
0
      do {
4585
0
        done = true;
4586
0
        for (it = this->UniqueObjectNamesMap.begin();
4587
0
             it != this->UniqueObjectNamesMap.end(); ++it) {
4588
0
          if (it->second == ssin) {
4589
0
            done = false;
4590
0
          }
4591
0
        }
4592
0
        if (done) {
4593
0
          break;
4594
0
        }
4595
0
        sssin = ssin;
4596
0
        cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
4597
0
        snprintf(rpstr, sizeof(rpstr), "_p%d_", cc++);
4598
0
      } while (!done);
4599
0
    }
4600
4601
0
    if (!cmLocalGeneratorCheckObjectName(ssin, dir_max.size(),
4602
0
                                         this->ObjectPathMax)) {
4603
      // Warn if this is the first time the path has been seen.
4604
0
      if (this->ObjectMaxPathViolations.insert(dir_max).second) {
4605
0
        this->IssueMessage(
4606
0
          MessageType::WARNING,
4607
0
          cmStrCat("The object file directory\n"
4608
0
                   "  ",
4609
0
                   dir_max,
4610
0
                   "\n"
4611
0
                   "has ",
4612
0
                   dir_max.size(),
4613
0
                   " characters.  "
4614
0
                   "The maximum full path to an object file is ",
4615
0
                   this->ObjectPathMax,
4616
0
                   " characters "
4617
0
                   "(see CMAKE_OBJECT_PATH_MAX).  "
4618
0
                   "Object file\n"
4619
0
                   "  ",
4620
0
                   ssin,
4621
0
                   "\n"
4622
0
                   "cannot be safely placed under this directory.  "
4623
0
                   "The build may not work correctly."));
4624
0
      }
4625
0
    }
4626
4627
    // Insert the newly mapped object file name.
4628
0
    std::map<std::string, std::string>::value_type e(sin, ssin);
4629
0
    it = this->UniqueObjectNamesMap.insert(e).first;
4630
0
  }
4631
4632
  // Return the map entry.
4633
0
  return it->second;
4634
0
}
4635
4636
void cmLocalGenerator::ComputeObjectFilenames(
4637
  std::map<cmSourceFile const*, cmObjectLocations>& /*unused*/,
4638
  std::string const& /*unused*/, cmGeneratorTarget const* /*unused*/)
4639
1.02k
{
4640
1.02k
}
4641
4642
bool cmLocalGenerator::IsWindowsShell() const
4643
0
{
4644
0
  return this->GetState()->UseWindowsShell();
4645
0
}
4646
4647
bool cmLocalGenerator::IsWatcomWMake() const
4648
0
{
4649
0
  return this->GetState()->UseWatcomWMake();
4650
0
}
4651
4652
bool cmLocalGenerator::IsMinGWMake() const
4653
0
{
4654
0
  return this->GetState()->UseMinGWMake();
4655
0
}
4656
4657
bool cmLocalGenerator::IsNMake() const
4658
0
{
4659
0
  return this->GetState()->UseNMake();
4660
0
}
4661
4662
bool cmLocalGenerator::IsNinjaMulti() const
4663
0
{
4664
0
  return this->GetState()->UseNinjaMulti();
4665
0
}
4666
4667
bool cmLocalGenerator::IsWindowsVSIDE() const
4668
0
{
4669
0
  return this->GetState()->UseWindowsVSIDE();
4670
0
}
4671
4672
namespace {
4673
std::string relativeIfUnder(std::string const& top, std::string const& cur,
4674
                            std::string const& path)
4675
0
{
4676
  // Use a path relative to 'cur' if it can be expressed without
4677
  // a `../` sequence that leaves 'top'.
4678
0
  if (cmSystemTools::IsSubDirectory(path, cur) ||
4679
0
      (cmSystemTools::IsSubDirectory(cur, top) &&
4680
0
       cmSystemTools::IsSubDirectory(path, top))) {
4681
0
    return cmSystemTools::ForceToRelativePath(cur, path);
4682
0
  }
4683
0
  return path;
4684
0
}
4685
}
4686
4687
std::string cmLocalGenerator::GetRelativeSourceFileName(
4688
  cmSourceFile const& source) const
4689
0
{
4690
  // Construct the object file name using the full path to the source
4691
  // file which is its only unique identification.
4692
0
  std::string const& fullPath = source.GetFullPath();
4693
4694
  // Try referencing the source relative to the source tree.
4695
0
  std::string relFromSource = relativeIfUnder(
4696
0
    this->GetSourceDirectory(), this->GetCurrentSourceDirectory(), fullPath);
4697
0
  assert(!relFromSource.empty());
4698
0
  bool relSource = !cmSystemTools::FileIsFullPath(relFromSource);
4699
0
  bool subSource = relSource && relFromSource[0] != '.';
4700
4701
  // Try referencing the source relative to the binary tree.
4702
0
  std::string relFromBinary = relativeIfUnder(
4703
0
    this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory(), fullPath);
4704
0
  assert(!relFromBinary.empty());
4705
0
  bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary);
4706
0
  bool subBinary = relBinary && relFromBinary[0] != '.';
4707
4708
  // Select a nice-looking reference to the source file to construct
4709
  // the object file name.
4710
0
  std::string objectName;
4711
  // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
4712
  // NOLINTNEXTLINE(bugprone-branch-clone)
4713
0
  if ((relSource && !relBinary) || (subSource && !subBinary)) {
4714
0
    objectName = relFromSource;
4715
0
  } else if ((relBinary && !relSource) || (subBinary && !subSource) ||
4716
0
             relFromBinary.length() < relFromSource.length()) {
4717
0
    objectName = relFromBinary;
4718
0
  } else {
4719
0
    objectName = relFromSource;
4720
0
  }
4721
0
  return objectName;
4722
0
}
4723
4724
std::string cmLocalGenerator::GetCustomObjectFileName(
4725
  cmSourceFile const& source) const
4726
0
{
4727
0
  if (!this->GetGlobalGenerator()->SupportsCustomObjectNames()) {
4728
0
    return std::string{};
4729
0
  }
4730
4731
0
  if (auto objName = source.GetProperty("OBJECT_NAME")) {
4732
0
    cmGeneratorExpression ge(*this->GetCMakeInstance());
4733
0
    auto cge = ge.Parse(objName);
4734
0
    static std::string const INVALID_GENEX =
4735
0
      "_cmake_invalid_object_name_genex";
4736
0
    static std::string const INVALID_VALUE =
4737
0
      "_cmake_invalid_object_name_value";
4738
4739
0
    if (!cge) {
4740
0
      this->Makefile->IssueMessage(
4741
0
        MessageType::FATAL_ERROR,
4742
0
        cmStrCat("The  \"OBJECT_NAME\" property for\n  ", source.GetFullPath(),
4743
0
                 "\nis not a valid generator expression (", objName, ")."));
4744
0
      return INVALID_GENEX;
4745
0
    }
4746
0
    if (cge->GetHadHeadSensitiveCondition()) {
4747
      // Not reachable; all target-sensitive  genexes actually fail to parse.
4748
0
      this->Makefile->IssueMessage(
4749
0
        MessageType::FATAL_ERROR,
4750
0
        cmStrCat("The  \"OBJECT_NAME\" property for\n  ", source.GetFullPath(),
4751
0
                 "\ncontains a condition that queries the consuming target "
4752
0
                 "which is not supported (",
4753
0
                 objName, ")."));
4754
0
      return INVALID_GENEX;
4755
0
    }
4756
0
    if (cge->GetHadLinkLanguageSensitiveCondition()) {
4757
      // Not reachable; all target-sensitive  genexes actually fail to parse.
4758
0
      this->Makefile->IssueMessage(
4759
0
        MessageType::FATAL_ERROR,
4760
0
        cmStrCat("The  \"OBJECT_NAME\" property for\n  ", source.GetFullPath(),
4761
0
                 "\ncontains a condition that queries the link language "
4762
0
                 "which is not supported (",
4763
0
                 objName, ")."));
4764
0
      return INVALID_GENEX;
4765
0
    }
4766
4767
0
    auto objNameValue = cge->Evaluate(this, "");
4768
0
    if (cge->GetHadContextSensitiveCondition()) {
4769
0
      this->Makefile->IssueMessage(
4770
0
        MessageType::FATAL_ERROR,
4771
0
        cmStrCat("The  \"OBJECT_NAME\" property for\n  ", source.GetFullPath(),
4772
0
                 "\ncontains a context-sensitive condition which is not "
4773
0
                 "supported (",
4774
0
                 objName, ")."));
4775
0
      return INVALID_GENEX;
4776
0
    }
4777
4778
    // Skip if it evaluates to empty.
4779
0
    if (!objNameValue.empty()) {
4780
0
      cmCMakePath objNamePath = objNameValue;
4781
      // Verify that it is a relative path.
4782
0
      if (objNamePath.IsAbsolute()) {
4783
0
        this->Makefile->IssueMessage(
4784
0
          MessageType::FATAL_ERROR,
4785
0
          cmStrCat(
4786
0
            "The  \"OBJECT_NAME\" property for\n  ", source.GetFullPath(),
4787
0
            "\nresolves to an absolute path which is not supported:\n  ",
4788
0
            objNameValue));
4789
0
        return INVALID_VALUE;
4790
0
      }
4791
0
      auto isInvalidComponent = [](cmCMakePath const& component) -> bool {
4792
0
        return component == ".."_s;
4793
0
      };
4794
      // Verify that it contains no `..` components.
4795
0
      if (std::any_of(objNamePath.begin(), objNamePath.end(),
4796
0
                      isInvalidComponent)) {
4797
0
        this->Makefile->IssueMessage(
4798
0
          MessageType::FATAL_ERROR,
4799
0
          cmStrCat("The  \"OBJECT_NAME\" property for\n  ",
4800
0
                   source.GetFullPath(), "\ncontains an invalid component (",
4801
0
                   objNameValue, ")."));
4802
0
        return INVALID_VALUE;
4803
0
      }
4804
4805
0
      return objNameValue;
4806
0
    }
4807
0
  }
4808
4809
0
  return std::string{};
4810
0
}
4811
4812
std::string cmLocalGenerator::GetCustomInstallObjectFileName(
4813
  cmSourceFile const& source, std::string const& config,
4814
  char const* custom_ext) const
4815
0
{
4816
0
  if (auto objName = source.GetProperty("INSTALL_OBJECT_NAME")) {
4817
0
    cmGeneratorExpression ge(*this->GetCMakeInstance());
4818
0
    auto cge = ge.Parse(objName);
4819
0
    static std::string const INVALID_GENEX =
4820
0
      "_cmake_invalid_object_name_genex";
4821
0
    static std::string const INVALID_VALUE =
4822
0
      "_cmake_invalid_object_name_value";
4823
4824
0
    if (!cge) {
4825
0
      this->Makefile->IssueMessage(
4826
0
        MessageType::FATAL_ERROR,
4827
0
        cmStrCat("The  \"INSTALL_OBJECT_NAME\" property for\n  ",
4828
0
                 source.GetFullPath(),
4829
0
                 "\nis not a valid generator expression (", objName, ")."));
4830
0
      return INVALID_GENEX;
4831
0
    }
4832
0
    if (cge->GetHadHeadSensitiveCondition()) {
4833
      // Not reachable; all target-sensitive  genexes actually fail to parse.
4834
0
      this->Makefile->IssueMessage(
4835
0
        MessageType::FATAL_ERROR,
4836
0
        cmStrCat("The  \"INSTALL_OBJECT_NAME\" property for\n  ",
4837
0
                 source.GetFullPath(),
4838
0
                 "\ncontains a condition that queries the consuming target "
4839
0
                 "which is not supported (",
4840
0
                 objName, ")."));
4841
0
      return INVALID_GENEX;
4842
0
    }
4843
0
    if (cge->GetHadLinkLanguageSensitiveCondition()) {
4844
      // Not reachable; all target-sensitive  genexes actually fail to parse.
4845
0
      this->Makefile->IssueMessage(
4846
0
        MessageType::FATAL_ERROR,
4847
0
        cmStrCat("The  \"INSTALL_OBJECT_NAME\" property for\n  ",
4848
0
                 source.GetFullPath(),
4849
0
                 "\ncontains a condition that queries the link language "
4850
0
                 "which is not supported (",
4851
0
                 objName, ")."));
4852
0
      return INVALID_GENEX;
4853
0
    }
4854
4855
0
    auto objNameValue = cge->Evaluate(this, config);
4856
4857
    // Skip if it evaluates to empty.
4858
0
    if (!objNameValue.empty()) {
4859
0
      cmCMakePath objNamePath = objNameValue;
4860
      // Verify that it is a relative path.
4861
0
      if (objNamePath.IsAbsolute()) {
4862
0
        this->Makefile->IssueMessage(
4863
0
          MessageType::FATAL_ERROR,
4864
0
          cmStrCat(
4865
0
            "The  \"INSTALL_OBJECT_NAME\" property for\n  ",
4866
0
            source.GetFullPath(),
4867
0
            "\nresolves to an absolute path which is not supported:\n  ",
4868
0
            objNameValue));
4869
0
        return INVALID_VALUE;
4870
0
      }
4871
0
      auto isInvalidComponent = [](cmCMakePath const& component) -> bool {
4872
0
        return component == ".."_s;
4873
0
      };
4874
      // Verify that it contains no `..` components.
4875
0
      if (std::any_of(objNamePath.begin(), objNamePath.end(),
4876
0
                      isInvalidComponent)) {
4877
0
        this->Makefile->IssueMessage(
4878
0
          MessageType::FATAL_ERROR,
4879
0
          cmStrCat("The  \"INSTALL_OBJECT_NAME\" property for\n  ",
4880
0
                   source.GetFullPath(), "\ncontains an invalid component (",
4881
0
                   objNameValue, ")."));
4882
0
        return INVALID_VALUE;
4883
0
      }
4884
4885
0
      if (custom_ext) {
4886
0
        objNameValue += custom_ext;
4887
0
      } else {
4888
0
        objNameValue +=
4889
0
          this->GetGlobalGenerator()->GetLanguageOutputExtension(source);
4890
0
      }
4891
4892
0
      return objNameValue;
4893
0
    }
4894
0
  }
4895
4896
0
  return std::string{};
4897
0
}
4898
4899
void cmLocalGenerator::FillCustomInstallObjectLocations(
4900
  cmSourceFile const& source, std::string const& config,
4901
  char const* custom_ext,
4902
  std::map<std::string, cmObjectLocation>& mapping) const
4903
0
{
4904
0
  auto installLoc =
4905
0
    this->GetCustomInstallObjectFileName(source, config, custom_ext);
4906
0
  if (!installLoc.empty()) {
4907
0
    mapping[config] = installLoc;
4908
0
  }
4909
0
}
4910
4911
std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
4912
  cmSourceFile const& source, std::string const& dir_max,
4913
  bool* hasSourceExtension, char const* customOutputExtension,
4914
  bool const* forceShortObjectName)
4915
0
{
4916
0
  bool useShortObjectNames = this->UseShortObjectNames();
4917
0
  if (forceShortObjectName) {
4918
0
    useShortObjectNames = *forceShortObjectName;
4919
0
  }
4920
4921
0
  if (!useShortObjectNames &&
4922
0
      this->GetGlobalGenerator()->SupportsCustomObjectNames()) {
4923
0
    auto customName = this->GetCustomObjectFileName(source);
4924
0
    if (!customName.empty()) {
4925
0
      auto ext = this->GlobalGenerator->GetLanguageOutputExtension(source);
4926
0
      if (customOutputExtension) {
4927
0
        ext = *customOutputExtension;
4928
0
      }
4929
0
      return cmStrCat(customName, ext);
4930
0
    }
4931
0
  }
4932
4933
  // This can return an absolute path in the case where source is
4934
  // not relative to the current source or binary directories
4935
0
  std::string objectName = this->GetRelativeSourceFileName(source);
4936
  // if it is still a full path check for the try compile case
4937
  // try compile never have in source sources, and should not
4938
  // have conflicting source file names in the same target
4939
0
  if (cmSystemTools::FileIsFullPath(objectName)) {
4940
0
    if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
4941
0
      objectName = cmSystemTools::GetFilenameName(source.GetFullPath());
4942
0
    }
4943
0
  }
4944
0
  bool const isPchObject = source.IsPchHeader() || source.IsPchSource();
4945
4946
  // Short object path policy selected, use as little info as necessary to
4947
  // select an object name
4948
0
  bool keptSourceExtension = true;
4949
0
  if (useShortObjectNames) {
4950
0
    objectName = this->GetShortObjectFileName(source);
4951
0
    keptSourceExtension = false;
4952
0
  }
4953
4954
  // Ensure that for the CMakeFiles/<target>.dir/generated_source_file
4955
  // we don't end up having:
4956
  // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
4957
0
  cmValue unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
4958
0
  cmValue pchExtension = source.GetProperty("PCH_EXTENSION");
4959
0
  if (unitySourceFile || pchExtension || isPchObject) {
4960
0
    if (pchExtension) {
4961
0
      customOutputExtension = pchExtension->c_str();
4962
0
    }
4963
4964
0
    cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)");
4965
0
    if (var.find(objectName)) {
4966
0
      objectName.erase(var.start(), var.end() - var.start());
4967
0
    }
4968
0
  }
4969
4970
  // Replace the original source file extension with the object file
4971
  // extension.
4972
0
  if (!source.GetPropertyAsBool("KEEP_EXTENSION")) {
4973
    // Decide whether this language wants to replace the source
4974
    // extension with the object extension.
4975
0
    bool replaceExt = false;
4976
0
    std::string lang = source.GetLanguage();
4977
0
    if (!lang.empty()) {
4978
0
      replaceExt = this->Makefile->IsOn(
4979
0
        cmStrCat("CMAKE_", lang, "_OUTPUT_EXTENSION_REPLACE"));
4980
0
    }
4981
4982
    // Remove the source extension if it is to be replaced.
4983
0
    if (replaceExt || customOutputExtension) {
4984
0
      keptSourceExtension = false;
4985
0
      std::string::size_type dot_pos = objectName.rfind('.');
4986
0
      if (dot_pos != std::string::npos) {
4987
0
        objectName = objectName.substr(0, dot_pos);
4988
0
      }
4989
0
    }
4990
4991
    // Strip source file extension when shortening object file paths
4992
0
    if (useShortObjectNames) {
4993
0
      objectName = cmSystemTools::GetFilenameWithoutExtension(objectName);
4994
0
    }
4995
    // Store the new extension.
4996
0
    if (customOutputExtension) {
4997
0
      objectName += customOutputExtension;
4998
0
    } else {
4999
0
      objectName += this->GlobalGenerator->GetLanguageOutputExtension(source);
5000
0
    }
5001
0
  }
5002
0
  if (hasSourceExtension) {
5003
0
    *hasSourceExtension = keptSourceExtension;
5004
0
  }
5005
5006
0
  if (source.GetLanguage() == "Rust") {
5007
0
    cmValue const rustEmit = source.GetRustEmitProperty();
5008
    // Rust requires any rlib to start with lib prefix on all platforms to
5009
    // allow linking to them as crate. So we enforce having lib prefix for rust
5010
    // "object" files.
5011
0
    if (rustEmit == "link") {
5012
0
      cmCMakePath objectPath(objectName);
5013
0
      std::string const objectFileName =
5014
0
        "lib" + objectPath.GetFileName().String();
5015
0
      objectPath.ReplaceFileName(objectFileName);
5016
0
      objectName = objectPath.String();
5017
0
    }
5018
0
  }
5019
5020
  // Convert to a safe name.
5021
0
  return this->CreateSafeUniqueObjectFileName(objectName, dir_max);
5022
0
}
5023
5024
bool cmLocalGenerator::UseShortObjectNames(
5025
  cmStateEnums::IntermediateDirKind kind) const
5026
555
{
5027
555
  return this->GlobalGenerator->UseShortObjectNames(kind);
5028
555
}
5029
5030
std::string cmLocalGenerator::GetObjectOutputRoot(
5031
  cmStateEnums::IntermediateDirKind kind) const
5032
0
{
5033
0
  if (this->UseShortObjectNames(kind)) {
5034
0
    return cmStrCat(this->GetCurrentBinaryDirectory(), '/',
5035
0
                    this->GlobalGenerator->GetShortBinaryOutputDir());
5036
0
  }
5037
0
  return cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
5038
0
}
5039
5040
bool cmLocalGenerator::AlwaysUsesCMFPaths() const
5041
0
{
5042
0
  return true;
5043
0
}
5044
5045
std::string cmLocalGenerator::GetShortObjectFileName(
5046
  cmSourceFile const& source) const
5047
0
{
5048
0
  std::string objectName = this->GetRelativeSourceFileName(source);
5049
0
  cmCryptoHash objNameHasher(cmCryptoHash::AlgoSHA3_512);
5050
0
  std::string terseObjectName =
5051
0
    objNameHasher.HashString(objectName).substr(0, 8);
5052
0
  return terseObjectName;
5053
0
}
5054
5055
std::string cmLocalGenerator::ComputeShortTargetDirectory(
5056
  cmGeneratorTarget const* target) const
5057
0
{
5058
0
  auto const& tgtName = target->GetName();
5059
0
  return this->GetGlobalGenerator()->ComputeTargetShortName(
5060
0
    this->GetCurrentBinaryDirectory(), tgtName);
5061
0
}
5062
5063
std::string cmLocalGenerator::GetSourceFileLanguage(cmSourceFile const& source)
5064
0
{
5065
0
  return source.GetLanguage();
5066
0
}
5067
5068
cmake* cmLocalGenerator::GetCMakeInstance() const
5069
718k
{
5070
718k
  return this->GlobalGenerator->GetCMakeInstance();
5071
718k
}
5072
5073
std::string const& cmLocalGenerator::GetSourceDirectory() const
5074
0
{
5075
0
  return this->GetCMakeInstance()->GetHomeDirectory();
5076
0
}
5077
5078
std::string const& cmLocalGenerator::GetBinaryDirectory() const
5079
0
{
5080
0
  return this->GetCMakeInstance()->GetHomeOutputDirectory();
5081
0
}
5082
5083
std::string const& cmLocalGenerator::GetCurrentBinaryDirectory() const
5084
6.93k
{
5085
6.93k
  return this->StateSnapshot.GetDirectory().GetCurrentBinary();
5086
6.93k
}
5087
5088
std::string const& cmLocalGenerator::GetCurrentSourceDirectory() const
5089
0
{
5090
0
  return this->StateSnapshot.GetDirectory().GetCurrentSource();
5091
0
}
5092
5093
std::string cmLocalGenerator::GetTargetDirectory(
5094
  cmGeneratorTarget const* /*unused*/,
5095
  cmStateEnums::IntermediateDirKind /*kind*/) const
5096
0
{
5097
0
  cmSystemTools::Error("GetTargetDirectory"
5098
0
                       " called on cmLocalGenerator");
5099
0
  return "";
5100
0
}
5101
5102
cmPolicies::PolicyStatus cmLocalGenerator::GetPolicyStatus(
5103
  cmPolicies::PolicyID id) const
5104
43.5k
{
5105
43.5k
  return this->Makefile->GetPolicyStatus(id);
5106
43.5k
}
5107
5108
bool cmLocalGenerator::CheckDefinition(std::string const& define) const
5109
0
{
5110
  // Many compilers do not support -DNAME(arg)=sdf so we disable it.
5111
0
  std::string::size_type pos = define.find_first_of("(=");
5112
0
  if (pos != std::string::npos) {
5113
0
    if (define[pos] == '(') {
5114
0
      cmSystemTools::Message(cmStrCat(
5115
0
        "WARNING: Function-style preprocessor definitions may not be "
5116
0
        "passed on the compiler command line because many compilers "
5117
0
        "do not support it.\n"
5118
0
        "CMake is dropping a preprocessor definition: ",
5119
0
        define,
5120
0
        "\n"
5121
0
        "Consider defining the macro in a (configured) header file.\n"));
5122
0
      return false;
5123
0
    }
5124
0
  }
5125
5126
  // Many compilers do not support # in the value so we disable it.
5127
0
  if (define.find_first_of('#') != std::string::npos) {
5128
0
    cmSystemTools::Message(cmStrCat(
5129
0
      "WARNING: Preprocessor definitions containing '#' may not be "
5130
0
      "passed on the compiler command line because many compilers "
5131
0
      "do not support it.\n"
5132
0
      "CMake is dropping a preprocessor definition: ",
5133
0
      define,
5134
0
      "\n"
5135
0
      "Consider defining the macro in a (configured) header file.\n"));
5136
0
    return false;
5137
0
  }
5138
5139
  // Assume it is supported.
5140
0
  return true;
5141
0
}
5142
5143
static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
5144
                         std::string const& prop)
5145
0
{
5146
0
  if (cmValue val = target->GetProperty(prop)) {
5147
0
    mf->AddDefinition(prop, *val);
5148
0
  }
5149
0
}
5150
5151
void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
5152
                                              std::string const& targetName,
5153
                                              std::string const& fname)
5154
0
{
5155
  // Find the Info.plist template.
5156
0
  cmValue in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
5157
0
  std::string inFile = cmNonempty(in) ? *in : "MacOSXBundleInfo.plist.in";
5158
0
  if (!cmSystemTools::FileIsFullPath(inFile)) {
5159
0
    std::string inMod = this->Makefile->GetModulesFile(inFile);
5160
0
    if (!inMod.empty()) {
5161
0
      inFile = inMod;
5162
0
    }
5163
0
  }
5164
0
  if (!cmSystemTools::FileExists(inFile, true)) {
5165
0
    cmSystemTools::Error(cmStrCat("Target ", target->GetName(),
5166
0
                                  " Info.plist template \"", inFile,
5167
0
                                  "\" could not be found."));
5168
0
    return;
5169
0
  }
5170
5171
  // Convert target properties to variables in an isolated makefile
5172
  // scope to configure the file.  If properties are set they will
5173
  // override user make variables.  If not the configuration will fall
5174
  // back to the directory-level values set by the user.
5175
0
  cmMakefile* mf = this->Makefile;
5176
0
  cmMakefile::ScopePushPop varScope(mf);
5177
0
  mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName);
5178
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_INFO_STRING");
5179
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_ICON_FILE");
5180
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_GUI_IDENTIFIER");
5181
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_LONG_VERSION_STRING");
5182
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_NAME");
5183
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
5184
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
5185
0
  cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
5186
0
  mf->ConfigureFile(inFile, fname, false, false, false);
5187
0
}
5188
5189
void cmLocalGenerator::GenerateFrameworkInfoPList(
5190
  cmGeneratorTarget* target, std::string const& targetName,
5191
  std::string const& fname)
5192
0
{
5193
  // Find the Info.plist template.
5194
0
  cmValue in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
5195
0
  std::string inFile = cmNonempty(in) ? *in : "MacOSXFrameworkInfo.plist.in";
5196
0
  if (!cmSystemTools::FileIsFullPath(inFile)) {
5197
0
    std::string inMod = this->Makefile->GetModulesFile(inFile);
5198
0
    if (!inMod.empty()) {
5199
0
      inFile = inMod;
5200
0
    }
5201
0
  }
5202
0
  if (!cmSystemTools::FileExists(inFile, true)) {
5203
0
    cmSystemTools::Error(cmStrCat("Target ", target->GetName(),
5204
0
                                  " Info.plist template \"", inFile,
5205
0
                                  "\" could not be found."));
5206
0
    return;
5207
0
  }
5208
5209
  // Convert target properties to variables in an isolated makefile
5210
  // scope to configure the file.  If properties are set they will
5211
  // override user make variables.  If not the configuration will fall
5212
  // back to the directory-level values set by the user.
5213
0
  cmMakefile* mf = this->Makefile;
5214
0
  cmMakefile::ScopePushPop varScope(mf);
5215
0
  mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName);
5216
0
  cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_ICON_FILE");
5217
0
  cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
5218
0
  cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
5219
0
  cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_NAME");
5220
0
  cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
5221
0
  mf->ConfigureFile(inFile, fname, false, false, false);
5222
0
}
5223
5224
namespace {
5225
cm::string_view CustomOutputRoleKeyword(cmLocalGenerator::OutputRole role)
5226
0
{
5227
0
  return (role == cmLocalGenerator::OutputRole::Primary ? "OUTPUT"_s
5228
0
                                                        : "BYPRODUCTS"_s);
5229
0
}
5230
5231
void CreateGeneratedSource(cmLocalGenerator& lg, std::string const& output,
5232
                           cmLocalGenerator::OutputRole role,
5233
                           cmCommandOrigin origin,
5234
                           cmListFileBacktrace const& lfbt)
5235
5.92k
{
5236
5.92k
  if (cmGeneratorExpression::Find(output) != std::string::npos) {
5237
0
    lg.GetCMakeInstance()->IssueMessage(
5238
0
      MessageType::FATAL_ERROR,
5239
0
      "Generator expressions in custom command outputs are not implemented!",
5240
0
      lfbt);
5241
0
    return;
5242
0
  }
5243
5244
  // Make sure the file will not be generated into the source
5245
  // directory during an out of source build.
5246
5.92k
  if (!lg.GetMakefile()->CanIWriteThisFile(output)) {
5247
0
    lg.GetCMakeInstance()->IssueMessage(
5248
0
      MessageType::FATAL_ERROR,
5249
0
      cmStrCat(CustomOutputRoleKeyword(role), " path\n  ", output,
5250
0
               "\nin a source directory as an output of custom command."),
5251
0
      lfbt);
5252
0
    return;
5253
0
  }
5254
5255
  // Make sure the output file name has no invalid characters.
5256
5.92k
  bool const hashNotAllowed = lg.GetState()->UseBorlandMake();
5257
5.92k
  std::string::size_type pos = output.find_first_of("<>");
5258
5.92k
  if (pos == std::string::npos && hashNotAllowed) {
5259
0
    pos = output.find_first_of('#');
5260
0
  }
5261
5262
5.92k
  if (pos != std::string::npos) {
5263
0
    lg.GetCMakeInstance()->IssueMessage(
5264
0
      MessageType::FATAL_ERROR,
5265
0
      cmStrCat(CustomOutputRoleKeyword(role), " containing a \"", output[pos],
5266
0
               "\" is not allowed."),
5267
0
      lfbt);
5268
0
    return;
5269
0
  }
5270
5271
  // Outputs without generator expressions from the project are already
5272
  // created and marked as generated.  Do not mark them again, because
5273
  // other commands might have overwritten the property.
5274
5.92k
  if (origin == cmCommandOrigin::Generator) {
5275
0
    lg.GetMakefile()->GetOrCreateGeneratedSource(output);
5276
0
  }
5277
5.92k
}
5278
5279
std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg,
5280
                                             cmListFileBacktrace const& bt,
5281
                                             std::string const& output)
5282
5.92k
{
5283
  // If the output path has no generator expressions, use it directly.
5284
5.92k
  if (cmGeneratorExpression::Find(output) == std::string::npos) {
5285
5.92k
    return output;
5286
5.92k
  }
5287
5288
  // The output path contains a generator expression, but we must choose
5289
  // a single source file path to which to attach the custom command.
5290
  // Use some heuristics to provide a nice-looking name when possible.
5291
5292
  // If the only genex is $<CONFIG>, replace that gracefully.
5293
0
  {
5294
0
    std::string simple = output;
5295
0
    cmSystemTools::ReplaceString(simple, "$<CONFIG>", "(CONFIG)");
5296
0
    if (cmGeneratorExpression::Find(simple) == std::string::npos) {
5297
0
      return simple;
5298
0
    }
5299
0
  }
5300
5301
  // If the genex evaluates to the same value in all configurations, use that.
5302
0
  {
5303
0
    std::vector<std::string> allConfigOutputs =
5304
0
      lg.ExpandCustomCommandOutputGenex(output, bt);
5305
0
    if (allConfigOutputs.size() == 1) {
5306
0
      return allConfigOutputs.front();
5307
0
    }
5308
0
  }
5309
5310
  // Fall back to a deterministic unique name.
5311
0
  cmCryptoHash h(cmCryptoHash::AlgoSHA256);
5312
0
  return cmStrCat(lg.GetCurrentBinaryDirectory(), "/CMakeFiles/",
5313
0
                  h.HashString(output).substr(0, 16));
5314
0
}
5315
5316
cmSourceFile* AddCustomCommand(cmLocalGenerator& lg, cmCommandOrigin origin,
5317
                               std::unique_ptr<cmCustomCommand> cc,
5318
                               bool replace)
5319
5.92k
{
5320
5.92k
  cmMakefile* mf = lg.GetMakefile();
5321
5.92k
  auto const& lfbt = cc->GetBacktrace();
5322
5.92k
  auto const& outputs = cc->GetOutputs();
5323
5.92k
  auto const& byproducts = cc->GetByproducts();
5324
5.92k
  auto const& commandLines = cc->GetCommandLines();
5325
5326
  // Choose a source file on which to store the custom command.
5327
5.92k
  cmSourceFile* file = nullptr;
5328
5.92k
  if (!commandLines.empty() && cc->HasMainDependency()) {
5329
0
    auto const& main_dependency = cc->GetMainDependency();
5330
    // The main dependency was specified.  Use it unless a different
5331
    // custom command already used it.
5332
0
    file = mf->GetSource(main_dependency);
5333
0
    if (file && file->GetCustomCommand() && !replace) {
5334
      // The main dependency already has a custom command.
5335
0
      if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
5336
        // The existing custom command is identical.  Silently ignore
5337
        // the duplicate.
5338
0
        return file;
5339
0
      }
5340
      // The existing custom command is different.  We need to
5341
      // generate a rule file for this new command.
5342
0
      file = nullptr;
5343
0
    } else if (!file) {
5344
0
      file = mf->CreateSource(main_dependency);
5345
0
    }
5346
0
  }
5347
5348
  // Generate a rule file if the main dependency is not available.
5349
5.92k
  if (!file) {
5350
5.92k
    cmGlobalGenerator* gg = lg.GetGlobalGenerator();
5351
5352
    // Construct a rule file associated with the first output produced.
5353
5.92k
    std::string outName = gg->GenerateRuleFile(
5354
5.92k
      ComputeCustomCommandRuleFileName(lg, lfbt, outputs[0]));
5355
5356
    // Check if the rule file already exists.
5357
5.92k
    file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
5358
5.92k
    if (file && file->GetCustomCommand() && !replace) {
5359
      // The rule file already exists.
5360
0
      if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
5361
0
        lg.GetCMakeInstance()->IssueMessage(
5362
0
          MessageType::FATAL_ERROR,
5363
0
          cmStrCat("Attempt to add a custom rule to output\n  ", outName,
5364
0
                   "\nwhich already has a custom rule."),
5365
0
          lfbt);
5366
0
      }
5367
0
      return file;
5368
0
    }
5369
5370
    // Create a cmSourceFile for the rule file.
5371
5.92k
    if (!file) {
5372
5.92k
      file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known);
5373
5.92k
    }
5374
5.92k
    file->SetProperty("__CMAKE_RULE", "1");
5375
5.92k
  }
5376
5377
  // Attach the custom command to the file.
5378
5.92k
  if (file) {
5379
5.92k
    cc->SetEscapeAllowMakeVars(true);
5380
5381
5.92k
    lg.AddSourceOutputs(file, outputs, cmLocalGenerator::OutputRole::Primary,
5382
5.92k
                        lfbt, origin);
5383
5.92k
    lg.AddSourceOutputs(file, byproducts,
5384
5.92k
                        cmLocalGenerator::OutputRole::Byproduct, lfbt, origin);
5385
5386
5.92k
    file->SetCustomCommand(std::move(cc));
5387
5.92k
  }
5388
5.92k
  return file;
5389
5.92k
}
5390
5391
bool AnyOutputMatches(std::string const& name,
5392
                      std::vector<std::string> const& outputs)
5393
0
{
5394
0
  return std::any_of(outputs.begin(), outputs.end(),
5395
0
                     [&name](std::string const& output) -> bool {
5396
0
                       std::string::size_type pos = output.rfind(name);
5397
                       // If the output matches exactly
5398
0
                       return (pos != std::string::npos &&
5399
0
                               pos == output.size() - name.size() &&
5400
0
                               (pos == 0 || output[pos - 1] == '/'));
5401
0
                     });
5402
0
}
5403
5404
bool AnyTargetCommandOutputMatches(
5405
  std::string const& name, std::vector<cmCustomCommand> const& commands)
5406
0
{
5407
0
  return std::any_of(commands.begin(), commands.end(),
5408
0
                     [&name](cmCustomCommand const& command) -> bool {
5409
0
                       return AnyOutputMatches(name, command.GetByproducts());
5410
0
                     });
5411
0
}
5412
}
5413
5414
namespace detail {
5415
void AddCustomCommandToTarget(cmLocalGenerator& lg, cmCommandOrigin origin,
5416
                              cmTarget* target, cmCustomCommandType type,
5417
                              std::unique_ptr<cmCustomCommand> cc)
5418
0
{
5419
  // Add the command to the appropriate build step for the target.
5420
0
  cc->SetEscapeAllowMakeVars(true);
5421
0
  cc->SetTarget(target->GetName());
5422
5423
0
  lg.AddTargetByproducts(target, cc->GetByproducts(), cc->GetBacktrace(),
5424
0
                         origin);
5425
5426
0
  switch (type) {
5427
0
    case cmCustomCommandType::PRE_BUILD:
5428
0
      target->AddPreBuildCommand(std::move(*cc));
5429
0
      break;
5430
0
    case cmCustomCommandType::PRE_LINK:
5431
0
      target->AddPreLinkCommand(std::move(*cc));
5432
0
      break;
5433
0
    case cmCustomCommandType::POST_BUILD:
5434
0
      target->AddPostBuildCommand(std::move(*cc));
5435
0
      break;
5436
0
  }
5437
5438
0
  cc.reset();
5439
0
}
5440
5441
cmSourceFile* AddCustomCommandToOutput(cmLocalGenerator& lg,
5442
                                       cmCommandOrigin origin,
5443
                                       std::unique_ptr<cmCustomCommand> cc,
5444
                                       bool replace)
5445
0
{
5446
0
  return AddCustomCommand(lg, origin, std::move(cc), replace);
5447
0
}
5448
5449
void AppendCustomCommandToOutput(cmLocalGenerator& lg,
5450
                                 cmListFileBacktrace const& lfbt,
5451
                                 std::string const& output,
5452
                                 std::vector<std::string> const& depends,
5453
                                 cmImplicitDependsList const& implicit_depends,
5454
                                 cmCustomCommandLines const& commandLines)
5455
0
{
5456
  // Lookup an existing command.
5457
0
  cmSourceFile* sf = nullptr;
5458
0
  if (cmGeneratorExpression::Find(output) == std::string::npos) {
5459
0
    sf = lg.GetSourceFileWithOutput(output);
5460
0
  } else {
5461
    // This output path has a generator expression.  Evaluate it to
5462
    // find the output for any configurations.
5463
0
    for (std::string const& out :
5464
0
         lg.ExpandCustomCommandOutputGenex(output, lfbt)) {
5465
0
      sf = lg.GetSourceFileWithOutput(out);
5466
0
      if (sf) {
5467
0
        break;
5468
0
      }
5469
0
    }
5470
0
  }
5471
5472
0
  if (sf) {
5473
0
    if (cmCustomCommand* cc = sf->GetCustomCommand()) {
5474
0
      cc->AppendCommands(commandLines);
5475
0
      cc->AppendDepends(depends);
5476
0
      if (cc->GetCodegen() && !implicit_depends.empty()) {
5477
0
        lg.GetCMakeInstance()->IssueMessage(
5478
0
          MessageType::FATAL_ERROR,
5479
0
          "Cannot append IMPLICIT_DEPENDS to existing CODEGEN custom "
5480
0
          "command.");
5481
0
      }
5482
0
      cc->AppendImplicitDepends(implicit_depends);
5483
0
      return;
5484
0
    }
5485
0
  }
5486
5487
  // No existing command found.
5488
0
  lg.GetCMakeInstance()->IssueMessage(
5489
0
    MessageType::FATAL_ERROR,
5490
0
    cmStrCat("Attempt to APPEND to custom command with output\n  ", output,
5491
0
             "\nwhich is not already a custom command output."),
5492
0
    lfbt);
5493
0
}
5494
5495
void AddUtilityCommand(cmLocalGenerator& lg, cmCommandOrigin origin,
5496
                       cmTarget* target, std::unique_ptr<cmCustomCommand> cc)
5497
5.92k
{
5498
  // They might be moved away
5499
5.92k
  auto byproducts = cc->GetByproducts();
5500
5.92k
  auto lfbt = cc->GetBacktrace();
5501
5502
  // Use an empty comment to avoid generation of default comment.
5503
5.92k
  if (!cc->GetComment()) {
5504
5.92k
    cc->SetComment("");
5505
5.92k
  }
5506
5507
  // Create the generated symbolic output name of the utility target.
5508
5.92k
  std::string output =
5509
5.92k
    lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt);
5510
5.92k
  cc->SetOutputs(output);
5511
5512
5.92k
  cmSourceFile* rule = AddCustomCommand(lg, origin, std::move(cc),
5513
5.92k
                                        /*replace=*/false);
5514
5.92k
  if (rule) {
5515
5.92k
    lg.AddTargetByproducts(target, byproducts, lfbt, origin);
5516
5.92k
  }
5517
5518
5.92k
  target->AddSource(output);
5519
5.92k
}
5520
5521
std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target)
5522
0
{
5523
0
  cmValue const targetProperty = target->GetProperty("ISPC_INSTRUCTION_SETS");
5524
0
  cmList ispcTargets;
5525
5526
0
  if (!targetProperty.IsOff()) {
5527
0
    ispcTargets.assign(targetProperty);
5528
0
    for (auto& ispcTarget : ispcTargets) {
5529
      // transform targets into the suffixes
5530
0
      auto pos = ispcTarget.find('-');
5531
0
      auto target_suffix = ispcTarget.substr(0, pos);
5532
      // ISPC uses underscores in output file suffixes where the target name
5533
      // has dots (e.g. "avx10.2dmr" produces files with "_avx10_2dmr" suffix)
5534
0
      std::replace(target_suffix.begin(), target_suffix.end(), '.', '_');
5535
0
      if (target_suffix ==
5536
0
          "avx1") { // when targeting avx1 ISPC uses the 'avx' output string
5537
0
        target_suffix = "avx";
5538
0
      } else if (target_suffix == "sse4_1" || target_suffix == "sse4_2") {
5539
        // when targeting sse4.1 or sse4.2 ISPC uses the 'sse4' output string
5540
0
        target_suffix = "sse4";
5541
0
      }
5542
0
      ispcTarget = target_suffix;
5543
0
    }
5544
0
  }
5545
0
  return std::move(ispcTargets.data());
5546
0
}
5547
5548
std::vector<std::string> ComputeISPCExtraObjects(
5549
  std::string const& objectName, std::string const& buildDirectory,
5550
  std::vector<std::string> const& ispcSuffixes)
5551
0
{
5552
0
  auto normalizedDir = cmSystemTools::CollapseFullPath(buildDirectory);
5553
0
  std::vector<std::string> computedObjects;
5554
0
  computedObjects.reserve(ispcSuffixes.size());
5555
5556
0
  auto extension = cmSystemTools::GetFilenameLastExtensionView(objectName);
5557
5558
  // We can't use cmSystemTools::GetFilenameWithoutLastExtension as it
5559
  // drops any directories in objectName
5560
0
  auto objNameNoExt = objectName;
5561
0
  std::string::size_type dot_pos = objectName.rfind('.');
5562
0
  if (dot_pos != std::string::npos) {
5563
0
    objNameNoExt.resize(dot_pos);
5564
0
  }
5565
5566
0
  for (auto const& ispcTarget : ispcSuffixes) {
5567
0
    computedObjects.emplace_back(
5568
0
      cmStrCat(normalizedDir, '/', objNameNoExt, '_', ispcTarget, extension));
5569
0
  }
5570
5571
0
  return computedObjects;
5572
0
}
5573
}
5574
5575
cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput(
5576
  std::string const& name) const
5577
0
{
5578
  // Linear search?  Also see GetSourceFileWithOutput for detail.
5579
0
  if (!cmSystemTools::FileIsFullPath(name)) {
5580
0
    cmSourcesWithOutput sources;
5581
0
    sources.Target = this->LinearGetTargetWithOutput(name);
5582
0
    sources.Source = this->LinearGetSourceFileWithOutput(
5583
0
      name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
5584
0
    return sources;
5585
0
  }
5586
  // Otherwise we use an efficient lookup map.
5587
0
  auto o = this->OutputToSource.find(name);
5588
0
  if (o != this->OutputToSource.end()) {
5589
0
    return o->second.Sources;
5590
0
  }
5591
0
  return {};
5592
0
}
5593
5594
void cmLocalGenerator::AppendOutputsAndByproducts(
5595
  std::unordered_set<std::string>& outputs) const
5596
0
{
5597
0
  for (auto const& entry : this->OutputToSource) {
5598
0
    outputs.insert(entry.first);
5599
0
  }
5600
0
}
5601
5602
cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput(
5603
  std::string const& name, cmSourceOutputKind kind) const
5604
0
{
5605
  // If the queried path is not absolute we use the backward compatible
5606
  // linear-time search for an output with a matching suffix.
5607
0
  if (!cmSystemTools::FileIsFullPath(name)) {
5608
0
    bool byproduct = false;
5609
0
    return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
5610
0
  }
5611
  // Otherwise we use an efficient lookup map.
5612
0
  auto o = this->OutputToSource.find(name);
5613
0
  if (o != this->OutputToSource.end() &&
5614
0
      (!o->second.Sources.SourceIsByproduct ||
5615
0
       kind == cmSourceOutputKind::OutputOrByproduct)) {
5616
    // Source file could also be null pointer for example if we found the
5617
    // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
5618
    // command of a target, or a not yet created custom command.
5619
0
    return o->second.Sources.Source;
5620
0
  }
5621
0
  return nullptr;
5622
0
}
5623
5624
std::string cmLocalGenerator::CreateUtilityOutput(
5625
  std::string const& targetName, std::vector<std::string> const&,
5626
  cmListFileBacktrace const&)
5627
5.92k
{
5628
5.92k
  std::string force =
5629
5.92k
    cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", targetName);
5630
  // The output is not actually created so mark it symbolic.
5631
5.92k
  if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
5632
5.92k
    sf->SetProperty("SYMBOLIC", "1");
5633
5.92k
  } else {
5634
0
    cmSystemTools::Error("Could not get source file entry for " + force);
5635
0
  }
5636
5.92k
  return force;
5637
5.92k
}
5638
5639
std::vector<cmCustomCommandGenerator>
5640
cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc,
5641
                                              std::string const& config)
5642
0
{
5643
0
  std::vector<cmCustomCommandGenerator> ccgs;
5644
0
  ccgs.emplace_back(cc, config, this);
5645
0
  return ccgs;
5646
0
}
5647
5648
std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths(
5649
  cmCompiledGeneratorExpression const& cge, std::string const& config)
5650
0
{
5651
0
  cmList paths{ cge.Evaluate(this, config) };
5652
0
  for (std::string& p : paths) {
5653
0
    p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory());
5654
0
  }
5655
0
  return std::move(paths.data());
5656
0
}
5657
5658
std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex(
5659
  std::string const& o, cmListFileBacktrace const& bt)
5660
0
{
5661
0
  std::vector<std::string> allConfigOutputs;
5662
0
  cmGeneratorExpression ge(*this->GetCMakeInstance(), bt);
5663
0
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o);
5664
0
  std::vector<std::string> configs =
5665
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
5666
0
  for (std::string const& config : configs) {
5667
0
    std::vector<std::string> configOutputs =
5668
0
      this->ExpandCustomCommandOutputPaths(*cge, config);
5669
0
    allConfigOutputs.reserve(allConfigOutputs.size() + configOutputs.size());
5670
0
    std::move(configOutputs.begin(), configOutputs.end(),
5671
0
              std::back_inserter(allConfigOutputs));
5672
0
  }
5673
0
  auto endUnique =
5674
0
    cmRemoveDuplicates(allConfigOutputs.begin(), allConfigOutputs.end());
5675
0
  allConfigOutputs.erase(endUnique, allConfigOutputs.end());
5676
0
  return allConfigOutputs;
5677
0
}
5678
5679
void cmLocalGenerator::AddTargetByproducts(
5680
  cmTarget* target, std::vector<std::string> const& byproducts,
5681
  cmListFileBacktrace const& bt, cmCommandOrigin origin)
5682
5.92k
{
5683
5.92k
  for (std::string const& o : byproducts) {
5684
0
    if (cmGeneratorExpression::Find(o) == std::string::npos) {
5685
0
      this->UpdateOutputToSourceMap(o, target, bt, origin);
5686
0
      continue;
5687
0
    }
5688
5689
    // This byproduct path has a generator expression.  Evaluate it to
5690
    // register the byproducts for all configurations.
5691
0
    for (std::string const& b : this->ExpandCustomCommandOutputGenex(o, bt)) {
5692
0
      this->UpdateOutputToSourceMap(b, target, bt, cmCommandOrigin::Generator);
5693
0
    }
5694
0
  }
5695
5.92k
}
5696
5697
void cmLocalGenerator::AddSourceOutputs(
5698
  cmSourceFile* source, std::vector<std::string> const& outputs,
5699
  OutputRole role, cmListFileBacktrace const& bt, cmCommandOrigin origin)
5700
11.8k
{
5701
11.8k
  for (std::string const& o : outputs) {
5702
5.92k
    if (cmGeneratorExpression::Find(o) == std::string::npos) {
5703
5.92k
      this->UpdateOutputToSourceMap(o, source, role, bt, origin);
5704
5.92k
      continue;
5705
5.92k
    }
5706
5707
    // This output path has a generator expression.  Evaluate it to
5708
    // register the outputs for all configurations.
5709
0
    for (std::string const& out :
5710
0
         this->ExpandCustomCommandOutputGenex(o, bt)) {
5711
0
      this->UpdateOutputToSourceMap(out, source, role, bt,
5712
0
                                    cmCommandOrigin::Generator);
5713
0
    }
5714
0
  }
5715
11.8k
}
5716
5717
void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct,
5718
                                               cmTarget* target,
5719
                                               cmListFileBacktrace const& bt,
5720
                                               cmCommandOrigin origin)
5721
0
{
5722
0
  SourceEntry entry;
5723
0
  entry.Sources.Target = target;
5724
5725
0
  auto pr = this->OutputToSource.emplace(byproduct, entry);
5726
0
  if (pr.second) {
5727
0
    this->GlobalGenerator->InvalidateGeneratedByBuildIndex();
5728
0
    CreateGeneratedSource(*this, byproduct, OutputRole::Byproduct, origin, bt);
5729
0
  } else {
5730
0
    SourceEntry& current = pr.first->second;
5731
    // Has the target already been set?
5732
0
    if (!current.Sources.Target) {
5733
0
      current.Sources.Target = target;
5734
0
    } else {
5735
      // Multiple custom commands/targets produce the same output (source file
5736
      // or target).  See also comment in other UpdateOutputToSourceMap
5737
      // overload.
5738
      //
5739
      // TODO: Warn the user about this case.
5740
0
    }
5741
0
  }
5742
0
}
5743
5744
void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
5745
                                               cmSourceFile* source,
5746
                                               OutputRole role,
5747
                                               cmListFileBacktrace const& bt,
5748
                                               cmCommandOrigin origin)
5749
5.92k
{
5750
5.92k
  SourceEntry entry;
5751
5.92k
  entry.Sources.Source = source;
5752
5.92k
  entry.Sources.SourceIsByproduct = role == OutputRole::Byproduct;
5753
5754
5.92k
  auto pr = this->OutputToSource.emplace(output, entry);
5755
5.92k
  if (pr.second) {
5756
5.92k
    this->GlobalGenerator->InvalidateGeneratedByBuildIndex();
5757
5.92k
    CreateGeneratedSource(*this, output, role, origin, bt);
5758
5.92k
  } else {
5759
0
    SourceEntry& current = pr.first->second;
5760
    // Outputs take precedence over byproducts
5761
0
    if (!current.Sources.Source ||
5762
0
        (current.Sources.SourceIsByproduct && role == OutputRole::Primary)) {
5763
0
      current.Sources.Source = source;
5764
0
      current.Sources.SourceIsByproduct = false;
5765
0
    } else {
5766
      // Multiple custom commands produce the same output but may
5767
      // be attached to a different source file (MAIN_DEPENDENCY).
5768
      // LinearGetSourceFileWithOutput would return the first one,
5769
      // so keep the mapping for the first one.
5770
      //
5771
      // TODO: Warn the user about this case.  However, the VS 8 generator
5772
      // triggers it for separate generate.stamp rules in ZERO_CHECK and
5773
      // individual targets.
5774
0
    }
5775
0
  }
5776
5.92k
}
5777
5778
cmTarget* cmLocalGenerator::LinearGetTargetWithOutput(
5779
  std::string const& name) const
5780
0
{
5781
  // We go through the ordered vector of targets to get reproducible results
5782
  // should multiple names match.
5783
0
  for (cmTarget* t : this->Makefile->GetOrderedTargets()) {
5784
    // Does the output of any command match the source file name?
5785
0
    if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
5786
0
      return t;
5787
0
    }
5788
0
    if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
5789
0
      return t;
5790
0
    }
5791
0
    if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
5792
0
      return t;
5793
0
    }
5794
0
  }
5795
0
  return nullptr;
5796
0
}
5797
5798
cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput(
5799
  std::string const& name, cmSourceOutputKind kind, bool& byproduct) const
5800
0
{
5801
  // Outputs take precedence over byproducts.
5802
0
  byproduct = false;
5803
0
  cmSourceFile* fallback = nullptr;
5804
5805
  // Look through all the source files that have custom commands and see if the
5806
  // custom command has the passed source file as an output.
5807
0
  for (auto const& src : this->Makefile->GetSourceFiles()) {
5808
    // Does this source file have a custom command?
5809
0
    if (src->GetCustomCommand()) {
5810
      // Does the output of the custom command match the source file name?
5811
0
      if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
5812
        // Return the first matching output.
5813
0
        return src.get();
5814
0
      }
5815
0
      if (kind == cmSourceOutputKind::OutputOrByproduct) {
5816
0
        if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
5817
          // Do not return the source yet as there might be a matching output.
5818
0
          fallback = src.get();
5819
0
        }
5820
0
      }
5821
0
    }
5822
0
  }
5823
5824
  // Did we find a byproduct?
5825
0
  byproduct = fallback != nullptr;
5826
0
  return fallback;
5827
0
}