Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratorTarget.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 "cmGeneratorTarget.h"
4
5
#include <algorithm>
6
#include <array>
7
#include <cassert>
8
#include <cstddef>
9
#include <cstdio>
10
#include <cstring>
11
#include <initializer_list>
12
#include <sstream>
13
#include <unordered_set>
14
#include <utility>
15
16
#include <cm/memory>
17
#include <cm/optional>
18
#include <cm/string_view>
19
#include <cmext/algorithm>
20
#include <cmext/string_view>
21
22
#include "cmsys/String.h"
23
24
#include "cmAlgorithms.h"
25
#include "cmComputeLinkInformation.h" // IWYU pragma: keep
26
#include "cmCryptoHash.h"
27
#include "cmCxxModuleMetadata.h"
28
#include "cmCxxModuleUsageEffects.h"
29
#include "cmExperimental.h"
30
#include "cmFileSet.h"
31
#include "cmFileSetMetadata.h"
32
#include "cmFileTimes.h"
33
#include "cmGenExContext.h"
34
#include "cmGeneratedFileStream.h"
35
#include "cmGeneratorExpression.h"
36
#include "cmGeneratorExpressionDAGChecker.h"
37
#include "cmGeneratorFileSet.h"
38
#include "cmGeneratorFileSets.h"
39
#include "cmGeneratorOptions.h"
40
#include "cmGlobalGenerator.h"
41
#include "cmList.h"
42
#include "cmLocalGenerator.h"
43
#include "cmMakefile.h"
44
#include "cmMessageType.h"
45
#include "cmOutputConverter.h"
46
#include "cmPropertyMap.h"
47
#include "cmRulePlaceholderExpander.h"
48
#include "cmSourceFile.h"
49
#include "cmSourceFileLocation.h"
50
#include "cmSourceFileLocationKind.h"
51
#include "cmStandardLevel.h"
52
#include "cmStandardLevelResolver.h"
53
#include "cmState.h"
54
#include "cmStateTypes.h"
55
#include "cmStringAlgorithms.h"
56
#include "cmSyntheticTargetCache.h"
57
#include "cmSystemTools.h"
58
#include "cmTarget.h"
59
#include "cmTargetLinkLibraryType.h"
60
#include "cmTargetPropertyComputer.h"
61
#include "cmTargetTraceDependencies.h"
62
#include "cmake.h"
63
64
namespace {
65
using UseTo = cmGeneratorTarget::UseTo;
66
}
67
68
template <>
69
cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
70
  cmGeneratorTarget const* tgt)
71
0
{
72
0
  return tgt->GetSourcesProperty();
73
0
}
74
75
template <>
76
std::string const&
77
cmTargetPropertyComputer::ImportedLocation<cmGeneratorTarget>(
78
  cmGeneratorTarget const* tgt, std::string const& config)
79
0
{
80
0
  return tgt->GetLocation(config);
81
0
}
82
83
static void CreatePropertyGeneratorExpressions(
84
  cmake& cmakeInstance, cmBTStringRange entries,
85
  std::vector<std::unique_ptr<cm::TargetPropertyEntry>>& items,
86
  bool evaluateForBuildsystem = false)
87
0
{
88
0
  for (auto const& entry : entries) {
89
0
    items.emplace_back(cm::TargetPropertyEntry::Create(
90
0
      cmakeInstance, entry, evaluateForBuildsystem));
91
0
  }
92
0
}
93
94
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
95
0
  : Target(t)
96
0
  , FileSets(cm::make_unique<cmGeneratorFileSets>(this, lg))
97
0
{
98
0
  this->Makefile = this->Target->GetMakefile();
99
0
  this->LocalGenerator = lg;
100
0
  this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
101
102
0
  this->GlobalGenerator->ComputeTargetObjectDirectory(this);
103
104
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
105
0
                                     t->GetIncludeDirectoriesEntries(),
106
0
                                     this->IncludeDirectoriesEntries);
107
108
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
109
0
                                     t->GetCompileOptionsEntries(),
110
0
                                     this->CompileOptionsEntries);
111
112
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
113
0
                                     t->GetCompileFeaturesEntries(),
114
0
                                     this->CompileFeaturesEntries);
115
116
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
117
0
                                     t->GetCompileDefinitionsEntries(),
118
0
                                     this->CompileDefinitionsEntries);
119
120
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
121
0
                                     t->GetLinkOptionsEntries(),
122
0
                                     this->LinkOptionsEntries);
123
124
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
125
0
                                     t->GetLinkDirectoriesEntries(),
126
0
                                     this->LinkDirectoriesEntries);
127
128
0
  CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
129
0
                                     t->GetPrecompileHeadersEntries(),
130
0
                                     this->PrecompileHeadersEntries);
131
132
0
  CreatePropertyGeneratorExpressions(
133
0
    *lg->GetCMakeInstance(), t->GetSourceEntries(), this->SourceEntries, true);
134
135
0
  this->PolicyMap = t->GetPolicyMap();
136
137
  // Get hard-coded linker language
138
0
  if (this->Target->GetProperty("HAS_CXX")) {
139
0
    this->LinkerLanguage = "CXX";
140
0
  } else {
141
0
    this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
142
0
  }
143
144
0
  auto configs =
145
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
146
0
  std::string build_db_languages[] = { "CXX" };
147
0
  for (auto const& language : build_db_languages) {
148
0
    for (auto const& config : configs) {
149
0
      auto bdb_path = this->BuildDatabasePath(language, config);
150
0
      if (!bdb_path.empty()) {
151
0
        this->Makefile->GetOrCreateGeneratedSource(bdb_path);
152
0
        this->GetGlobalGenerator()->AddBuildDatabaseFile(language, config,
153
0
                                                         bdb_path);
154
0
      }
155
0
    }
156
0
  }
157
0
}
158
159
0
cmGeneratorTarget::~cmGeneratorTarget() = default;
160
161
cmValue cmGeneratorTarget::GetSourcesProperty() const
162
0
{
163
0
  std::vector<std::string> values;
164
0
  for (auto const& se : this->SourceEntries) {
165
0
    values.push_back(se->GetInput());
166
0
  }
167
0
  static std::string value;
168
0
  value = cmList::to_string(values);
169
0
  return cmValue(value);
170
0
}
171
172
cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
173
0
{
174
0
  return this->GetLocalGenerator()->GetGlobalGenerator();
175
0
}
176
177
cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
178
0
{
179
0
  return this->LocalGenerator;
180
0
}
181
182
cmStateEnums::TargetType cmGeneratorTarget::GetType() const
183
0
{
184
0
  return this->Target->GetType();
185
0
}
186
187
std::string const& cmGeneratorTarget::GetName() const
188
0
{
189
0
  return this->Target->GetName();
190
0
}
191
192
std::string cmGeneratorTarget::GetFamilyName() const
193
0
{
194
0
  if (!this->IsImported() && !this->IsSynthetic()) {
195
0
    return this->Target->GetTemplateName();
196
0
  }
197
0
  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
198
0
  constexpr size_t HASH_TRUNCATION = 12;
199
0
  auto dirhash =
200
0
    hasher.HashString(this->GetLocalGenerator()->GetCurrentBinaryDirectory());
201
0
  auto targetIdent = hasher.HashString(cmStrCat("@d_", dirhash));
202
0
  return cmStrCat(this->Target->GetTemplateName(), '@',
203
0
                  targetIdent.substr(0, HASH_TRUNCATION));
204
0
}
205
206
std::string cmGeneratorTarget::GetExportName() const
207
0
{
208
0
  cmValue exportName = this->GetProperty("EXPORT_NAME");
209
210
0
  if (cmNonempty(exportName)) {
211
0
    if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
212
0
      std::ostringstream e;
213
0
      e << "EXPORT_NAME property \"" << *exportName << "\" for \""
214
0
        << this->GetName() << "\": is not valid.";
215
0
      cmSystemTools::Error(e.str());
216
0
      return "";
217
0
    }
218
0
    return *exportName;
219
0
  }
220
0
  return this->GetName();
221
0
}
222
223
std::string cmGeneratorTarget::GetFilesystemExportName() const
224
0
{
225
0
  auto fs_safe = this->GetExportName();
226
  // First escape any `_` characters to avoid collisions.
227
0
  cmSystemTools::ReplaceString(fs_safe, "_", "__");
228
  // Escape other characters that are not generally filesystem-safe.
229
0
  cmSystemTools::ReplaceString(fs_safe, ":", "_c");
230
0
  return fs_safe;
231
0
}
232
233
cmValue cmGeneratorTarget::GetProperty(std::string const& prop) const
234
0
{
235
0
  if (cmValue result =
236
0
        cmTargetPropertyComputer::GetProperty(this, prop, *this->Makefile)) {
237
0
    return result;
238
0
  }
239
0
  if (cmSystemTools::GetFatalErrorOccurred()) {
240
0
    return nullptr;
241
0
  }
242
0
  return this->Target->GetProperty(prop);
243
0
}
244
245
std::string const& cmGeneratorTarget::GetSafeProperty(
246
  std::string const& prop) const
247
0
{
248
0
  return this->GetProperty(prop);
249
0
}
250
251
char const* cmGeneratorTarget::GetOutputTargetType(
252
  cmStateEnums::ArtifactType artifact) const
253
0
{
254
0
  if (this->IsFrameworkOnApple() || this->GetGlobalGenerator()->IsXcode()) {
255
    // import file (i.e. .tbd file) is always in same location as library
256
0
    artifact = cmStateEnums::RuntimeBinaryArtifact;
257
0
  }
258
259
0
  switch (this->GetType()) {
260
0
    case cmStateEnums::SHARED_LIBRARY:
261
0
      if (this->IsDLLPlatform()) {
262
0
        switch (artifact) {
263
0
          case cmStateEnums::RuntimeBinaryArtifact:
264
            // A DLL shared library is treated as a runtime target.
265
0
            return "RUNTIME";
266
0
          case cmStateEnums::ImportLibraryArtifact:
267
            // A DLL import library is treated as an archive target.
268
0
            return "ARCHIVE";
269
0
        }
270
0
      } else {
271
0
        switch (artifact) {
272
0
          case cmStateEnums::RuntimeBinaryArtifact:
273
            // For non-DLL platforms shared libraries are treated as
274
            // library targets.
275
0
            return "LIBRARY";
276
0
          case cmStateEnums::ImportLibraryArtifact:
277
            // Library import libraries are treated as archive targets.
278
0
            return "ARCHIVE";
279
0
        }
280
0
      }
281
0
      break;
282
0
    case cmStateEnums::STATIC_LIBRARY:
283
      // Static libraries are always treated as archive targets.
284
0
      return "ARCHIVE";
285
0
    case cmStateEnums::MODULE_LIBRARY:
286
0
      switch (artifact) {
287
0
        case cmStateEnums::RuntimeBinaryArtifact:
288
          // Module libraries are always treated as library targets.
289
0
          return "LIBRARY";
290
0
        case cmStateEnums::ImportLibraryArtifact:
291
          // Module import libraries are treated as archive targets.
292
0
          return "ARCHIVE";
293
0
      }
294
0
      break;
295
0
    case cmStateEnums::OBJECT_LIBRARY:
296
      // Object libraries are always treated as object targets.
297
0
      return "OBJECT";
298
0
    case cmStateEnums::EXECUTABLE:
299
0
      switch (artifact) {
300
0
        case cmStateEnums::RuntimeBinaryArtifact:
301
          // Executables are always treated as runtime targets.
302
0
          return "RUNTIME";
303
0
        case cmStateEnums::ImportLibraryArtifact:
304
          // Executable import libraries are treated as archive targets.
305
0
          return "ARCHIVE";
306
0
      }
307
0
      break;
308
0
    default:
309
0
      break;
310
0
  }
311
0
  return "";
312
0
}
313
314
std::string cmGeneratorTarget::GetOutputName(
315
  std::string const& config, cmStateEnums::ArtifactType artifact) const
316
0
{
317
  // Lookup/compute/cache the output name for this configuration.
318
0
  OutputNameKey key(config, artifact);
319
0
  auto i = this->OutputNameMap.find(key);
320
0
  if (i == this->OutputNameMap.end()) {
321
    // Add empty name in map to detect potential recursion.
322
0
    OutputNameMapType::value_type entry(key, "");
323
0
    i = this->OutputNameMap.insert(entry).first;
324
325
    // Compute output name.
326
0
    std::vector<std::string> props;
327
0
    std::string type = this->GetOutputTargetType(artifact);
328
0
    std::string configUpper = cmSystemTools::UpperCase(config);
329
0
    if (!type.empty() && !configUpper.empty()) {
330
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
331
0
      props.push_back(cmStrCat(type, "_OUTPUT_NAME_", configUpper));
332
0
    }
333
0
    if (!type.empty()) {
334
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
335
0
      props.push_back(type + "_OUTPUT_NAME");
336
0
    }
337
0
    if (!configUpper.empty()) {
338
      // OUTPUT_NAME_<CONFIG>
339
0
      props.push_back("OUTPUT_NAME_" + configUpper);
340
      // <CONFIG>_OUTPUT_NAME
341
0
      props.push_back(configUpper + "_OUTPUT_NAME");
342
0
    }
343
    // OUTPUT_NAME
344
0
    props.emplace_back("OUTPUT_NAME");
345
346
0
    std::string outName;
347
0
    for (std::string const& p : props) {
348
0
      if (cmValue outNameProp = this->GetProperty(p)) {
349
0
        outName = *outNameProp;
350
0
        break;
351
0
      }
352
0
    }
353
354
0
    if (outName.empty()) {
355
0
      outName = this->GetName();
356
0
    }
357
358
    // Now evaluate genex and update the previously-prepared map entry.
359
0
    i->second =
360
0
      cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
361
0
  } else if (i->second.empty()) {
362
    // An empty map entry indicates we have been called recursively
363
    // from the above block.
364
0
    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
365
0
      MessageType::FATAL_ERROR,
366
0
      cmStrCat("Target '", this->GetName(),
367
0
               "' OUTPUT_NAME depends on itself."),
368
0
      this->GetBacktrace());
369
0
  }
370
0
  return i->second;
371
0
}
372
373
std::string cmGeneratorTarget::GetFilePrefix(
374
  std::string const& config, cmStateEnums::ArtifactType artifact) const
375
0
{
376
0
  if (this->IsImported()) {
377
0
    cmValue prefix = this->GetFilePrefixInternal(config, artifact);
378
0
    return prefix ? *prefix : std::string();
379
0
  }
380
0
  return this->GetFullNameInternalComponents(config, artifact).prefix;
381
0
}
382
std::string cmGeneratorTarget::GetFileSuffix(
383
  std::string const& config, cmStateEnums::ArtifactType artifact) const
384
0
{
385
0
  if (this->IsImported()) {
386
0
    cmValue suffix = this->GetFileSuffixInternal(config, artifact);
387
0
    return suffix ? *suffix : std::string();
388
0
  }
389
0
  return this->GetFullNameInternalComponents(config, artifact).suffix;
390
0
}
391
392
std::string cmGeneratorTarget::GetFilePostfix(std::string const& config) const
393
0
{
394
0
  cmValue postfix = nullptr;
395
0
  std::string frameworkPostfix;
396
0
  if (!config.empty()) {
397
0
    std::string configProp =
398
0
      cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
399
0
    postfix = this->GetProperty(configProp);
400
401
    // Mac application bundles and frameworks have no regular postfix like
402
    // libraries do.
403
0
    if (!this->IsImported() && postfix &&
404
0
        (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
405
0
      postfix = nullptr;
406
0
    }
407
408
    // Frameworks created by multi config generators can have a special
409
    // framework postfix.
410
0
    frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
411
0
    if (!frameworkPostfix.empty()) {
412
0
      postfix = cmValue(frameworkPostfix);
413
0
    }
414
0
  }
415
0
  return postfix ? *postfix : std::string();
416
0
}
417
418
std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
419
  std::string const& config) const
420
0
{
421
0
  cmValue postfix = nullptr;
422
0
  if (!config.empty()) {
423
0
    std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
424
0
                                      cmSystemTools::UpperCase(config));
425
0
    postfix = this->GetProperty(configProp);
426
427
0
    if (!this->IsImported() && postfix &&
428
0
        (this->IsFrameworkOnApple() &&
429
0
         !this->GetGlobalGenerator()->IsMultiConfig())) {
430
0
      postfix = nullptr;
431
0
    }
432
0
  }
433
0
  return postfix ? *postfix : std::string();
434
0
}
435
436
cmValue cmGeneratorTarget::GetFilePrefixInternal(
437
  std::string const& config, cmStateEnums::ArtifactType artifact,
438
  std::string const& language) const
439
0
{
440
  // no prefix for non-main target types.
441
0
  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
442
0
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
443
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
444
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
445
0
    return nullptr;
446
0
  }
447
448
0
  bool const isImportedLibraryArtifact =
449
0
    (artifact == cmStateEnums::ImportLibraryArtifact);
450
451
  // Return an empty prefix for the import library if this platform
452
  // does not support import libraries.
453
0
  if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
454
0
    return nullptr;
455
0
  }
456
457
  // The implib option is only allowed for shared libraries, module
458
  // libraries, and executables.
459
0
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
460
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
461
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
462
0
    artifact = cmStateEnums::RuntimeBinaryArtifact;
463
0
  }
464
465
  // Compute prefix value.
466
0
  cmValue targetPrefix =
467
0
    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
468
0
                               : this->GetProperty("PREFIX"));
469
470
0
  if (!targetPrefix) {
471
0
    char const* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
472
0
    if (!language.empty() && cmNonempty(prefixVar)) {
473
0
      std::string langPrefix = cmStrCat(prefixVar, '_', language);
474
0
      targetPrefix = this->Makefile->GetDefinition(langPrefix);
475
0
    }
476
477
    // if there is no prefix on the target nor specific language
478
    // use the cmake definition.
479
0
    if (!targetPrefix && prefixVar) {
480
0
      targetPrefix = this->Makefile->GetDefinition(prefixVar);
481
0
    }
482
0
  }
483
484
0
  return targetPrefix;
485
0
}
486
487
cmValue cmGeneratorTarget::GetFileSuffixInternal(
488
  std::string const& config, cmStateEnums::ArtifactType artifact,
489
  std::string const& language) const
490
0
{
491
  // no suffix for non-main target types.
492
0
  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
493
0
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
494
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
495
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
496
0
    return nullptr;
497
0
  }
498
499
0
  bool const isImportedLibraryArtifact =
500
0
    (artifact == cmStateEnums::ImportLibraryArtifact);
501
502
  // Return an empty suffix for the import library if this platform
503
  // does not support import libraries.
504
0
  if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
505
0
    return nullptr;
506
0
  }
507
508
  // The implib option is only allowed for shared libraries, module
509
  // libraries, and executables.
510
0
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
511
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
512
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
513
0
    artifact = cmStateEnums::RuntimeBinaryArtifact;
514
0
  }
515
516
  // Compute suffix value.
517
0
  cmValue targetSuffix =
518
0
    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
519
0
                               : this->GetProperty("SUFFIX"));
520
521
0
  if (!targetSuffix) {
522
0
    char const* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
523
0
    if (!language.empty() && cmNonempty(suffixVar)) {
524
0
      std::string langSuffix = cmStrCat(suffixVar, '_', language);
525
0
      targetSuffix = this->Makefile->GetDefinition(langSuffix);
526
0
    }
527
528
    // if there is no suffix on the target nor specific language
529
    // use the cmake definition.
530
0
    if (!targetSuffix && suffixVar) {
531
0
      targetSuffix = this->Makefile->GetDefinition(suffixVar);
532
0
    }
533
0
  }
534
535
0
  return targetSuffix;
536
0
}
537
538
void cmGeneratorTarget::ClearSourcesCache()
539
0
{
540
0
  this->AllConfigSources.clear();
541
0
  this->AllConfigCompileLanguages.clear();
542
0
  this->KindedSourcesMap.clear();
543
0
  this->SourcesAreContextDependent = Tribool::Indeterminate;
544
0
  this->Objects.clear();
545
0
  this->VisitedConfigsForObjects.clear();
546
0
  this->LinkImplClosureForLinkMap.clear();
547
0
  this->LinkImplClosureForUsageMap.clear();
548
0
  this->LinkImplMap.clear();
549
0
  this->LinkImplUsageRequirementsOnlyMap.clear();
550
0
  this->IncludeDirectoriesCache.clear();
551
0
  this->CompileOptionsCache.clear();
552
0
  this->CompileDefinitionsCache.clear();
553
0
  this->CustomTransitiveBuildPropertiesMap.clear();
554
0
  this->CustomTransitiveInterfacePropertiesMap.clear();
555
0
  this->PrecompileHeadersCache.clear();
556
0
  this->LinkOptionsCache.clear();
557
0
  this->LinkDirectoriesCache.clear();
558
0
  this->RuntimeBinaryFullNameCache.clear();
559
0
  this->ImportLibraryFullNameCache.clear();
560
0
}
561
562
void cmGeneratorTarget::ClearLinkInterfaceCache()
563
0
{
564
0
  this->LinkInterfaceMap.clear();
565
0
  this->LinkInterfaceUsageRequirementsOnlyMap.clear();
566
0
}
567
568
void cmGeneratorTarget::AddSourceCommon(std::string const& src, bool before)
569
0
{
570
0
  this->SourceEntries.insert(
571
0
    before ? this->SourceEntries.begin() : this->SourceEntries.end(),
572
0
    TargetPropertyEntry::Create(
573
0
      *this->LocalGenerator->GetCMakeInstance(),
574
0
      BT<std::string>(src, this->Makefile->GetBacktrace()), true));
575
0
  this->ClearSourcesCache();
576
0
}
577
578
cmSourceFile* cmGeneratorTarget::AddSource(std::string const& src, bool before)
579
0
{
580
0
  auto* sf = this->Target->AddSource(src, before);
581
0
  this->AddSourceCommon(src, before);
582
0
  return sf;
583
0
}
584
585
void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
586
0
{
587
0
  this->Target->AddTracedSources(srcs);
588
0
  if (!srcs.empty()) {
589
0
    this->AddSourceCommon(cmJoin(srcs, ";"));
590
0
  }
591
0
}
592
593
void cmGeneratorTarget::AddIncludeDirectory(std::string const& src,
594
                                            bool before)
595
0
{
596
0
  this->Target->InsertInclude(
597
0
    BT<std::string>(src, this->Makefile->GetBacktrace()), before);
598
0
  this->IncludeDirectoriesEntries.insert(
599
0
    before ? this->IncludeDirectoriesEntries.begin()
600
0
           : this->IncludeDirectoriesEntries.end(),
601
0
    TargetPropertyEntry::Create(
602
0
      *this->Makefile->GetCMakeInstance(),
603
0
      BT<std::string>(src, this->Makefile->GetBacktrace()), true));
604
0
}
605
606
void cmGeneratorTarget::AddSystemIncludeDirectory(std::string const& inc,
607
                                                  std::string const& lang)
608
0
{
609
0
  std::string config_upper;
610
0
  auto const& configs =
611
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
612
613
0
  for (auto const& config : configs) {
614
0
    std::string inc_with_config = inc;
615
0
    if (!config.empty()) {
616
0
      cmSystemTools::ReplaceString(inc_with_config, "$<CONFIG>", config);
617
0
      config_upper = cmSystemTools::UpperCase(config);
618
0
    }
619
0
    auto const& key = cmStrCat(config_upper, '/', lang);
620
0
    this->Target->AddSystemIncludeDirectories({ inc_with_config });
621
0
    if (this->SystemIncludesCache.find(key) ==
622
0
        this->SystemIncludesCache.end()) {
623
0
      this->AddSystemIncludeCacheKey(key, config, lang);
624
0
    }
625
0
    this->SystemIncludesCache[key].emplace_back(inc_with_config);
626
627
    // SystemIncludesCache should be sorted so that binary search can be used
628
0
    std::sort(this->SystemIncludesCache[key].begin(),
629
0
              this->SystemIncludesCache[key].end());
630
0
  }
631
0
}
632
633
std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
634
  cmSourceFile const* sf) const
635
0
{
636
0
  auto i = this->SourceDepends.find(sf);
637
0
  if (i != this->SourceDepends.end()) {
638
0
    return &i->second.Depends;
639
0
  }
640
0
  return nullptr;
641
0
}
642
643
namespace {
644
void handleSystemIncludesDep(cmLocalGenerator const* lg,
645
                             cmGeneratorTarget const* depTgt,
646
                             std::string const& config,
647
                             cmGeneratorTarget const* headTarget,
648
                             cmGeneratorExpressionDAGChecker* dagChecker,
649
                             cmList& result, bool excludeImported,
650
                             std::string const& language)
651
0
{
652
0
  if (cmValue dirs =
653
0
        depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
654
0
    result.append(cmGeneratorExpression::Evaluate(
655
0
      *dirs, lg, config, headTarget, dagChecker, depTgt, language));
656
0
  }
657
0
  if (!depTgt->GetPropertyAsBool("SYSTEM")) {
658
0
    return;
659
0
  }
660
0
  if (depTgt->IsImported()) {
661
0
    if (excludeImported) {
662
0
      return;
663
0
    }
664
0
    if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
665
0
      return;
666
0
    }
667
0
  }
668
669
0
  if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
670
0
    result.append(cmGeneratorExpression::Evaluate(
671
0
      *dirs, lg, config, headTarget, dagChecker, depTgt, language));
672
0
  }
673
674
0
  if (depTgt->Target->IsFrameworkOnApple() ||
675
0
      depTgt->IsImportedFrameworkFolderOnApple(config)) {
676
0
    if (auto fwDescriptor = depTgt->GetGlobalGenerator()->SplitFrameworkPath(
677
0
          depTgt->GetLocation(config))) {
678
0
      result.push_back(fwDescriptor->Directory);
679
0
      result.push_back(fwDescriptor->GetFrameworkPath());
680
0
    }
681
0
  }
682
0
}
683
}
684
685
/* clang-format off */
686
#define IMPLEMENT_VISIT(KIND)                                                 \
687
0
  do {                                                                        \
688
0
    KindedSources const& kinded = this->GetKindedSources(config);             \
689
0
    for (SourceAndKind const& s : kinded.Sources) {                           \
690
0
      if (s.Kind == KIND) {                                                   \
691
0
        data.push_back(s.Source.Value);                                       \
692
0
      }                                                                       \
693
0
    }                                                                         \
694
0
  } while (false)
695
/* clang-format on */
696
697
void cmGeneratorTarget::GetObjectSources(
698
  std::vector<cmSourceFile const*>& data, std::string const& config) const
699
0
{
700
0
  IMPLEMENT_VISIT(SourceKindObjectSource);
701
702
0
  if (this->VisitedConfigsForObjects.count(config)) {
703
0
    return;
704
0
  }
705
706
0
  for (cmSourceFile const* it : data) {
707
0
    this->Objects[it];
708
0
  }
709
710
0
  this->LocalGenerator->ComputeObjectFilenames(this->Objects, config, this);
711
0
  this->VisitedConfigsForObjects.insert(config);
712
0
}
713
714
void cmGeneratorTarget::ComputeObjectMapping()
715
0
{
716
0
  auto const& configs =
717
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
718
0
  std::set<std::string> configSet(configs.begin(), configs.end());
719
0
  if (configSet == this->VisitedConfigsForObjects) {
720
0
    return;
721
0
  }
722
723
0
  for (std::string const& c : configs) {
724
0
    std::vector<cmSourceFile const*> sourceFiles;
725
0
    this->GetObjectSources(sourceFiles, c);
726
0
  }
727
0
}
728
729
cmValue cmGeneratorTarget::GetFeature(std::string const& feature,
730
                                      std::string const& config) const
731
0
{
732
0
  if (!config.empty()) {
733
0
    std::string featureConfig =
734
0
      cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
735
0
    if (cmValue value = this->GetProperty(featureConfig)) {
736
0
      return value;
737
0
    }
738
0
  }
739
0
  if (cmValue value = this->GetProperty(feature)) {
740
0
    return value;
741
0
  }
742
0
  return this->LocalGenerator->GetFeature(feature, config);
743
0
}
744
745
std::string cmGeneratorTarget::GetLinkerTypeProperty(
746
  std::string const& lang, std::string const& config) const
747
0
{
748
0
  std::string propName{ "LINKER_TYPE" };
749
0
  auto linkerType = this->GetProperty(propName);
750
0
  if (!linkerType.IsEmpty()) {
751
0
    cm::GenEx::Context context(this->LocalGenerator, config, lang);
752
0
    cmGeneratorExpressionDAGChecker dagChecker{
753
0
      this, propName, nullptr, nullptr, context,
754
0
    };
755
0
    auto ltype = cmGeneratorExpression::Evaluate(
756
0
      *linkerType, context.LG, context.Config, this, &dagChecker, this,
757
0
      context.Language);
758
0
    if (this->IsDeviceLink()) {
759
0
      cmList list{ ltype };
760
0
      auto const DL_BEGIN = "<DEVICE_LINK>"_s;
761
0
      auto const DL_END = "</DEVICE_LINK>"_s;
762
0
      cm::erase_if(list, [&](std::string const& item) {
763
0
        return item == DL_BEGIN || item == DL_END;
764
0
      });
765
0
      return list.to_string();
766
0
    }
767
0
    return ltype;
768
0
  }
769
0
  return std::string{};
770
0
}
771
772
char const* cmGeneratorTarget::GetLinkPIEProperty(
773
  std::string const& config) const
774
0
{
775
0
  static std::string PICValue;
776
777
0
  PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty(
778
0
    "POSITION_INDEPENDENT_CODE", config);
779
780
0
  if (PICValue == "(unset)") {
781
    // POSITION_INDEPENDENT_CODE is not set
782
0
    return nullptr;
783
0
  }
784
785
0
  auto status = this->GetPolicyStatusCMP0083();
786
0
  return (status != cmPolicies::WARN && status != cmPolicies::OLD)
787
0
    ? PICValue.c_str()
788
0
    : nullptr;
789
0
}
790
791
bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
792
                                     std::string const& config) const
793
0
{
794
0
  cmValue feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
795
796
0
  if (!feature.IsOn()) {
797
    // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
798
0
    return false;
799
0
  }
800
801
0
  if (lang != "C" && lang != "CXX" && lang != "CUDA" && lang != "Fortran") {
802
    // We do not define IPO behavior for other languages.
803
0
    return false;
804
0
  }
805
806
0
  if (lang == "CUDA") {
807
    // CUDA IPO requires both CUDA_ARCHITECTURES and CUDA_SEPARABLE_COMPILATION
808
0
    if (cmIsOff(this->GetSafeProperty("CUDA_ARCHITECTURES")) ||
809
0
        cmIsOff(this->GetSafeProperty("CUDA_SEPARABLE_COMPILATION"))) {
810
0
      return false;
811
0
    }
812
0
  }
813
814
0
  cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
815
816
0
  if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
817
0
    if (this->Makefile->IsOn(
818
0
          cmStrCat("_CMAKE_", lang, "_IPO_LEGACY_BEHAVIOR"))) {
819
0
      return true;
820
0
    }
821
0
    if (this->PolicyReportedCMP0069) {
822
      // problem is already reported, no need to issue a message
823
0
      return false;
824
0
    }
825
0
    bool const in_try_compile =
826
0
      this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
827
0
    if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
828
0
      std::ostringstream w;
829
0
      w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
830
0
      w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
831
0
        << "'" << this->GetName() << "'.";
832
0
      this->LocalGenerator->GetCMakeInstance()->IssueMessage(
833
0
        MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
834
835
0
      this->PolicyReportedCMP0069 = true;
836
0
    }
837
0
    return false;
838
0
  }
839
840
  // Note: check consistency with messages from CheckIPOSupported
841
0
  char const* message = nullptr;
842
0
  if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
843
0
    message = "CMake doesn't support IPO for current compiler";
844
0
  } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
845
0
                                   "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
846
0
    message = "Compiler doesn't support IPO";
847
0
  } else if (!this->GlobalGenerator->IsIPOSupported()) {
848
0
    message = "CMake doesn't support IPO for current generator";
849
0
  }
850
851
0
  if (!message) {
852
    // No error/warning messages
853
0
    return true;
854
0
  }
855
856
0
  if (this->PolicyReportedCMP0069) {
857
    // problem is already reported, no need to issue a message
858
0
    return false;
859
0
  }
860
861
0
  this->PolicyReportedCMP0069 = true;
862
863
0
  this->LocalGenerator->GetCMakeInstance()->IssueMessage(
864
0
    MessageType::FATAL_ERROR, message, this->GetBacktrace());
865
0
  return false;
866
0
}
867
868
std::string const& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
869
0
{
870
0
  this->ComputeObjectMapping();
871
0
  auto const useShortPaths = this->GetUseShortObjectNames()
872
0
    ? cmObjectLocations::UseShortPath::Yes
873
0
    : cmObjectLocations::UseShortPath::No;
874
0
  return this->Objects[file].GetPath(useShortPaths);
875
0
}
876
877
char const* cmGeneratorTarget::GetCustomObjectExtension() const
878
0
{
879
0
  struct compiler_mode
880
0
  {
881
0
    std::string variable;
882
0
    std::string extension;
883
0
  };
884
0
  static std::array<compiler_mode, 4> const modes{
885
0
    { { "CUDA_PTX_COMPILATION", ".ptx" },
886
0
      { "CUDA_CUBIN_COMPILATION", ".cubin" },
887
0
      { "CUDA_FATBIN_COMPILATION", ".fatbin" },
888
0
      { "CUDA_OPTIX_COMPILATION", ".optixir" } }
889
0
  };
890
891
0
  std::string const& compiler =
892
0
    this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
893
0
  if (!compiler.empty()) {
894
0
    for (auto const& m : modes) {
895
0
      bool const has_extension = this->GetPropertyAsBool(m.variable);
896
0
      if (has_extension) {
897
0
        return m.extension.c_str();
898
0
      }
899
0
    }
900
0
  }
901
0
  return nullptr;
902
0
}
903
904
void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
905
0
{
906
0
  this->ExplicitObjectName.insert(sf);
907
0
}
908
909
bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
910
0
{
911
0
  const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
912
0
  auto it = this->ExplicitObjectName.find(file);
913
0
  return it != this->ExplicitObjectName.end();
914
0
}
915
916
BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
917
  std::string const& lang, std::string const& config) const
918
0
{
919
0
  std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
920
0
  auto langStandardIter = this->LanguageStandardMap.find(key);
921
0
  if (langStandardIter != this->LanguageStandardMap.end()) {
922
0
    return &langStandardIter->second;
923
0
  }
924
925
0
  return this->Target->GetLanguageStandardProperty(
926
0
    cmStrCat(lang, "_STANDARD"));
927
0
}
928
929
cmValue cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
930
                                               std::string const& config) const
931
0
{
932
0
  BTs<std::string> const* languageStandard =
933
0
    this->GetLanguageStandardProperty(lang, config);
934
935
0
  if (languageStandard) {
936
0
    return cmValue(languageStandard->Value);
937
0
  }
938
939
0
  return nullptr;
940
0
}
941
942
cmValue cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
943
  std::string const& lang, char const* suffix) const
944
0
{
945
0
  cmValue propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix));
946
0
  if (!propertyValue) {
947
    // Check if we should use the value set by another language.
948
0
    if (lang == "OBJC") {
949
0
      propertyValue = this->GetPropertyWithPairedLanguageSupport("C", suffix);
950
0
    } else if (lang == "OBJCXX" || lang == "CUDA" || lang == "HIP") {
951
0
      propertyValue =
952
0
        this->GetPropertyWithPairedLanguageSupport("CXX", suffix);
953
0
    }
954
0
  }
955
0
  return propertyValue;
956
0
}
957
958
cmValue cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
959
0
{
960
0
  return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS");
961
0
}
962
963
bool cmGeneratorTarget::GetLanguageStandardRequired(
964
  std::string const& lang) const
965
0
{
966
0
  return this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED")
967
0
    .IsOn();
968
0
}
969
970
void cmGeneratorTarget::GetModuleDefinitionSources(
971
  std::vector<cmSourceFile const*>& data, std::string const& config) const
972
0
{
973
0
  IMPLEMENT_VISIT(SourceKindModuleDefinition);
974
0
}
975
976
void cmGeneratorTarget::GetHeaderSources(
977
  std::vector<cmSourceFile const*>& data, std::string const& config) const
978
0
{
979
0
  IMPLEMENT_VISIT(SourceKindHeader);
980
0
}
981
982
void cmGeneratorTarget::GetCxxModuleSources(
983
  std::vector<cmSourceFile const*>& data, std::string const& config) const
984
0
{
985
0
  IMPLEMENT_VISIT(SourceKindCxxModuleSource);
986
0
}
987
988
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
989
                                        std::string const& config) const
990
0
{
991
0
  IMPLEMENT_VISIT(SourceKindExtra);
992
0
}
993
994
void cmGeneratorTarget::GetCustomCommands(
995
  std::vector<cmSourceFile const*>& data, std::string const& config) const
996
0
{
997
0
  IMPLEMENT_VISIT(SourceKindCustomCommand);
998
0
}
999
1000
void cmGeneratorTarget::GetExternalObjects(
1001
  std::vector<cmSourceFile const*>& data, std::string const& config) const
1002
0
{
1003
0
  IMPLEMENT_VISIT(SourceKindExternalObject);
1004
0
}
1005
1006
void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
1007
                                     std::string const& config) const
1008
0
{
1009
0
  IMPLEMENT_VISIT(SourceKindManifest);
1010
0
}
1011
1012
std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
1013
0
{
1014
0
  if (!this->UtilityItemsDone) {
1015
0
    this->UtilityItemsDone = true;
1016
0
    std::set<BT<std::pair<std::string, bool>>> const& utilities =
1017
0
      this->GetUtilities();
1018
0
    for (BT<std::pair<std::string, bool>> const& i : utilities) {
1019
0
      if (cmGeneratorTarget* gt =
1020
0
            this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) {
1021
0
        this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace));
1022
0
      } else {
1023
0
        this->UtilityItems.insert(
1024
0
          cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
1025
0
      }
1026
0
    }
1027
0
    if (cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget()) {
1028
0
      this->UtilityItems.insert(
1029
0
        cmLinkItem(reuseTarget, false, cmListFileBacktrace()));
1030
0
    }
1031
0
  }
1032
0
  return this->UtilityItems;
1033
0
}
1034
1035
std::string const& cmGeneratorTarget::GetLocation(
1036
  std::string const& config) const
1037
0
{
1038
0
  static std::string location;
1039
0
  if (this->IsImported()) {
1040
0
    location = this->Target->ImportedGetFullPath(
1041
0
      config, cmStateEnums::RuntimeBinaryArtifact);
1042
0
  } else {
1043
0
    location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1044
0
  }
1045
0
  return location;
1046
0
}
1047
1048
cm::optional<std::string> cmGeneratorTarget::MaybeGetLocation(
1049
  std::string const& config) const
1050
0
{
1051
0
  cm::optional<std::string> location;
1052
0
  if (cmGeneratorTarget::ImportInfo const* imp = this->GetImportInfo(config)) {
1053
0
    if (!imp->Location.empty()) {
1054
0
      location = imp->Location;
1055
0
    }
1056
0
  } else {
1057
0
    location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
1058
0
  }
1059
0
  return location;
1060
0
}
1061
1062
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
1063
  const
1064
0
{
1065
0
  return this->Target->GetPreBuildCommands();
1066
0
}
1067
1068
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
1069
  const
1070
0
{
1071
0
  return this->Target->GetPreLinkCommands();
1072
0
}
1073
1074
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
1075
  const
1076
0
{
1077
0
  return this->Target->GetPostBuildCommands();
1078
0
}
1079
1080
void cmGeneratorTarget::AppendCustomCommandSideEffects(
1081
  std::set<cmGeneratorTarget const*>& sideEffects) const
1082
0
{
1083
0
  if (!this->GetPreBuildCommands().empty() ||
1084
0
      !this->GetPreLinkCommands().empty() ||
1085
0
      !this->GetPostBuildCommands().empty()) {
1086
0
    sideEffects.insert(this);
1087
0
  } else {
1088
0
    for (auto const& source : this->GetAllConfigSources()) {
1089
0
      if (source.Source->GetCustomCommand()) {
1090
0
        sideEffects.insert(this);
1091
0
        break;
1092
0
      }
1093
0
    }
1094
0
  }
1095
0
}
1096
1097
void cmGeneratorTarget::AppendLanguageSideEffects(
1098
  std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const
1099
0
{
1100
0
  static std::set<cm::string_view> const LANGS_WITH_NO_SIDE_EFFECTS = {
1101
0
    "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s, "HIP"_s
1102
0
  };
1103
1104
0
  for (auto const& lang : this->GetAllConfigCompileLanguages()) {
1105
0
    if (!LANGS_WITH_NO_SIDE_EFFECTS.count(lang)) {
1106
0
      sideEffects[lang].insert(this);
1107
0
    }
1108
0
  }
1109
0
}
1110
1111
bool cmGeneratorTarget::IsInBuildSystem() const
1112
0
{
1113
0
  if (this->IsImported()) {
1114
0
    return false;
1115
0
  }
1116
0
  switch (this->Target->GetType()) {
1117
0
    case cmStateEnums::EXECUTABLE:
1118
0
    case cmStateEnums::STATIC_LIBRARY:
1119
0
    case cmStateEnums::SHARED_LIBRARY:
1120
0
    case cmStateEnums::MODULE_LIBRARY:
1121
0
    case cmStateEnums::OBJECT_LIBRARY:
1122
0
    case cmStateEnums::UTILITY:
1123
0
    case cmStateEnums::GLOBAL_TARGET:
1124
0
      return true;
1125
0
    case cmStateEnums::INTERFACE_LIBRARY:
1126
      // An INTERFACE library is in the build system if it has SOURCES
1127
      // or C++ module filesets.
1128
0
      if (!this->SourceEntries.empty() ||
1129
0
          !this->GetFileSets(cm::FileSetMetadata::HEADERS).empty() ||
1130
0
          !this->GetFileSets(cm::FileSetMetadata::CXX_MODULES).empty()) {
1131
0
        return true;
1132
0
      }
1133
0
      break;
1134
0
    case cmStateEnums::UNKNOWN_LIBRARY:
1135
0
      break;
1136
0
  }
1137
0
  return false;
1138
0
}
1139
1140
bool cmGeneratorTarget::IsNormal() const
1141
0
{
1142
0
  return this->Target->IsNormal();
1143
0
}
1144
1145
bool cmGeneratorTarget::IsRuntimeBinary() const
1146
0
{
1147
0
  return this->Target->IsRuntimeBinary();
1148
0
}
1149
1150
bool cmGeneratorTarget::IsSynthetic() const
1151
0
{
1152
0
  return this->Target->IsSynthetic();
1153
0
}
1154
1155
bool cmGeneratorTarget::IsImported() const
1156
0
{
1157
0
  return this->Target->IsImported();
1158
0
}
1159
1160
bool cmGeneratorTarget::IsImportedGloballyVisible() const
1161
0
{
1162
0
  return this->Target->IsImportedGloballyVisible();
1163
0
}
1164
1165
bool cmGeneratorTarget::IsSymbolic() const
1166
0
{
1167
0
  return this->Target->IsSymbolic();
1168
0
}
1169
1170
bool cmGeneratorTarget::IsForeign() const
1171
0
{
1172
0
  return this->Target->IsForeign();
1173
0
}
1174
1175
bool cmGeneratorTarget::CanCompileSources() const
1176
0
{
1177
0
  return this->Target->CanCompileSources();
1178
0
}
1179
1180
bool cmGeneratorTarget::HasKnownRuntimeArtifactLocation(
1181
  std::string const& config) const
1182
0
{
1183
0
  if (!this->IsRuntimeBinary()) {
1184
0
    return false;
1185
0
  }
1186
0
  if (!this->IsImported()) {
1187
0
    return true;
1188
0
  }
1189
0
  ImportInfo const* info = this->GetImportInfo(config);
1190
0
  return info && !info->Location.empty();
1191
0
}
1192
1193
std::string const& cmGeneratorTarget::GetLocationForBuild() const
1194
0
{
1195
0
  static std::string location;
1196
0
  if (this->IsImported()) {
1197
0
    location = this->Target->ImportedGetFullPath(
1198
0
      "", cmStateEnums::RuntimeBinaryArtifact);
1199
0
    return location;
1200
0
  }
1201
1202
  // Now handle the deprecated build-time configuration location.
1203
0
  std::string const noConfig;
1204
0
  location = this->GetDirectory(noConfig);
1205
0
  cmValue cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
1206
0
  if (cfgid && (*cfgid != ".")) {
1207
0
    location += "/";
1208
0
    location += *cfgid;
1209
0
  }
1210
1211
0
  if (this->IsAppBundleOnApple()) {
1212
0
    std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
1213
0
    if (!macdir.empty()) {
1214
0
      location += "/";
1215
0
      location += macdir;
1216
0
    }
1217
0
  }
1218
0
  location += "/";
1219
0
  location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
1220
0
  return location;
1221
0
}
1222
1223
void cmGeneratorTarget::AddSystemIncludeCacheKey(
1224
  std::string const& key, std::string const& config,
1225
  std::string const& language) const
1226
0
{
1227
0
  cm::GenEx::Context context(this->LocalGenerator, config, language);
1228
0
  cmGeneratorExpressionDAGChecker dagChecker{
1229
0
    this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr, context,
1230
0
  };
1231
1232
0
  bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
1233
1234
0
  cmList result;
1235
0
  for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
1236
0
    result.append(
1237
0
      cmGeneratorExpression::Evaluate(it, context.LG, context.Config, this,
1238
0
                                      &dagChecker, nullptr, context.Language));
1239
0
  }
1240
1241
0
  std::vector<cmGeneratorTarget const*> const& deps =
1242
0
    this->GetLinkImplementationClosure(config, UseTo::Compile);
1243
0
  for (cmGeneratorTarget const* dep : deps) {
1244
0
    handleSystemIncludesDep(context.LG, dep, context.Config, this, &dagChecker,
1245
0
                            result, excludeImported, context.Language);
1246
0
  }
1247
1248
0
  cmLinkImplementation const* impl =
1249
0
    this->GetLinkImplementation(config, UseTo::Compile);
1250
0
  if (impl) {
1251
0
    auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language);
1252
0
    if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) {
1253
0
      for (auto const& lib : runtimeEntries->second) {
1254
0
        if (lib.Target) {
1255
0
          handleSystemIncludesDep(context.LG, lib.Target, context.Config, this,
1256
0
                                  &dagChecker, result, excludeImported,
1257
0
                                  context.Language);
1258
0
        }
1259
0
      }
1260
0
    }
1261
0
  }
1262
1263
0
  std::for_each(result.begin(), result.end(),
1264
0
                cmSystemTools::ConvertToUnixSlashes);
1265
0
  std::sort(result.begin(), result.end());
1266
0
  result.erase(std::unique(result.begin(), result.end()), result.end());
1267
0
  SystemIncludesCache.emplace(key, result);
1268
0
}
1269
1270
bool cmGeneratorTarget::IsSystemIncludeDirectory(
1271
  std::string const& dir, std::string const& config,
1272
  std::string const& language) const
1273
0
{
1274
0
  std::string config_upper;
1275
0
  if (!config.empty()) {
1276
0
    config_upper = cmSystemTools::UpperCase(config);
1277
0
  }
1278
1279
0
  std::string key = cmStrCat(config_upper, '/', language);
1280
0
  auto iter = this->SystemIncludesCache.find(key);
1281
1282
0
  if (iter == this->SystemIncludesCache.end()) {
1283
0
    this->AddSystemIncludeCacheKey(key, config, language);
1284
0
    iter = this->SystemIncludesCache.find(key);
1285
0
  }
1286
1287
0
  return std::binary_search(iter->second.begin(), iter->second.end(), dir);
1288
0
}
1289
1290
bool cmGeneratorTarget::GetPropertyAsBool(std::string const& prop) const
1291
0
{
1292
0
  return this->Target->GetPropertyAsBool(prop);
1293
0
}
1294
1295
std::string cmGeneratorTarget::GetCompilePDBName(
1296
  std::string const& config) const
1297
0
{
1298
0
  if (cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget()) {
1299
0
    if (reuseTarget != this) {
1300
0
      return reuseTarget->GetCompilePDBName(config);
1301
0
    }
1302
0
  }
1303
1304
  // Check for a per-configuration output directory target property.
1305
0
  std::string configUpper = cmSystemTools::UpperCase(config);
1306
0
  std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
1307
0
  cmValue config_name = this->GetProperty(configProp);
1308
0
  if (cmNonempty(config_name)) {
1309
0
    std::string pdbName = cmGeneratorExpression::Evaluate(
1310
0
      *config_name, this->LocalGenerator, config, this);
1311
0
    NameComponents const& components = GetFullNameInternalComponents(
1312
0
      config, cmStateEnums::RuntimeBinaryArtifact);
1313
0
    return components.prefix + pdbName + ".pdb";
1314
0
  }
1315
1316
0
  cmValue name = this->GetProperty("COMPILE_PDB_NAME");
1317
0
  if (cmNonempty(name)) {
1318
0
    std::string pdbName = cmGeneratorExpression::Evaluate(
1319
0
      *name, this->LocalGenerator, config, this);
1320
0
    NameComponents const& components = GetFullNameInternalComponents(
1321
0
      config, cmStateEnums::RuntimeBinaryArtifact);
1322
0
    return components.prefix + pdbName + ".pdb";
1323
0
  }
1324
1325
  // If the target is PCH-reused or PCH-reuses, we need a stable name for the
1326
  // PDB file so that reusing targets can construct a stable name for it.
1327
0
  cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget();
1328
0
  bool const hasReuse = reuseTarget && reuseTarget != this;
1329
0
  if (this->PchReused || hasReuse) {
1330
0
    NameComponents const& components = GetFullNameInternalComponents(
1331
0
      config, cmStateEnums::RuntimeBinaryArtifact);
1332
0
    return cmStrCat(components.prefix, this->GetName(), ".pdb");
1333
0
  }
1334
1335
0
  return std::string{};
1336
0
}
1337
1338
std::string cmGeneratorTarget::GetCompilePDBPath(
1339
  std::string const& config) const
1340
0
{
1341
0
  std::string dir = this->GetCompilePDBDirectory(config);
1342
0
  std::string name = this->GetCompilePDBName(config);
1343
0
  if (dir.empty() && !name.empty() && this->HaveWellDefinedOutputFiles()) {
1344
0
    dir = this->GetPDBDirectory(config);
1345
0
  }
1346
0
  if (!dir.empty()) {
1347
0
    dir += "/";
1348
0
  }
1349
0
  return dir + name;
1350
0
}
1351
1352
bool cmGeneratorTarget::HasSOName(std::string const& config) const
1353
0
{
1354
  // soname is supported only for shared libraries and modules,
1355
  // and then only when the platform supports an soname flag.
1356
0
  return ((this->GetType() == cmStateEnums::SHARED_LIBRARY) &&
1357
0
          !this->GetPropertyAsBool("NO_SONAME") &&
1358
0
          (this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)) ||
1359
0
           this->IsArchivedAIXSharedLibrary()));
1360
0
}
1361
1362
bool cmGeneratorTarget::NeedRelinkBeforeInstall(
1363
  std::string const& config) const
1364
0
{
1365
  // Only executables and shared libraries can have an rpath and may
1366
  // need relinking.
1367
0
  if (this->GetType() != cmStateEnums::EXECUTABLE &&
1368
0
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
1369
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY) {
1370
0
    return false;
1371
0
  }
1372
1373
  // If there is no install location this target will not be installed
1374
  // and therefore does not need relinking.
1375
0
  if (!this->Target->GetHaveInstallRule()) {
1376
0
    return false;
1377
0
  }
1378
1379
  // If skipping all rpaths completely then no relinking is needed.
1380
0
  if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
1381
0
    return false;
1382
0
  }
1383
1384
  // If building with the install-tree rpath no relinking is needed.
1385
0
  if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
1386
0
    return false;
1387
0
  }
1388
1389
  // If chrpath is going to be used no relinking is needed.
1390
0
  if (this->IsChrpathUsed(config)) {
1391
0
    return false;
1392
0
  }
1393
1394
  // Check for rpath support on this platform.
1395
0
  std::string ll = this->GetLinkerLanguage(config);
1396
0
  if (!ll.empty()) {
1397
0
    std::string flagVar =
1398
0
      cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG");
1399
0
    if (!this->Makefile->IsSet(flagVar)) {
1400
      // There is no rpath support on this platform so nothing needs
1401
      // relinking.
1402
0
      return false;
1403
0
    }
1404
0
  } else {
1405
    // No linker language is known.  This error will be reported by
1406
    // other code.
1407
0
    return false;
1408
0
  }
1409
1410
  // If either a build or install tree rpath is set then the rpath
1411
  // will likely change between the build tree and install tree and
1412
  // this target must be relinked.
1413
0
  bool have_rpath =
1414
0
    this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
1415
0
  bool is_ninja = this->LocalGenerator->GetGlobalGenerator()->IsNinja();
1416
1417
0
  if (have_rpath && is_ninja) {
1418
0
    std::ostringstream w;
1419
    /* clang-format off */
1420
0
    w <<
1421
0
      "The install of the " << this->GetName() << " target requires changing "
1422
0
      "an RPATH from the build tree, but this is not supported with the Ninja "
1423
0
      "generator unless on an ELF-based or XCOFF-based platform.  "
1424
0
      "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
1425
0
      "relinking step."
1426
0
      ;
1427
    /* clang-format on */
1428
1429
0
    cmake* cm = this->LocalGenerator->GetCMakeInstance();
1430
0
    cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
1431
0
  }
1432
1433
0
  return have_rpath;
1434
0
}
1435
1436
bool cmGeneratorTarget::IsChrpathUsed(std::string const& config) const
1437
0
{
1438
  // Only certain target types have an rpath.
1439
0
  if (!(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
1440
0
        this->GetType() == cmStateEnums::MODULE_LIBRARY ||
1441
0
        this->GetType() == cmStateEnums::EXECUTABLE)) {
1442
0
    return false;
1443
0
  }
1444
1445
  // If the target will not be installed we do not need to change its
1446
  // rpath.
1447
0
  if (!this->Target->GetHaveInstallRule()) {
1448
0
    return false;
1449
0
  }
1450
1451
  // Skip chrpath if skipping rpath altogether.
1452
0
  if (this->Makefile->IsOn("CMAKE_SKIP_RPATH")) {
1453
0
    return false;
1454
0
  }
1455
1456
  // Skip chrpath if it does not need to be changed at install time.
1457
0
  if (this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) {
1458
0
    return false;
1459
0
  }
1460
1461
  // Allow the user to disable builtin chrpath explicitly.
1462
0
  if (this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) {
1463
0
    return false;
1464
0
  }
1465
1466
0
  if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
1467
0
    return true;
1468
0
  }
1469
1470
  // Enable if the rpath flag uses a separator and the target uses
1471
  // binaries we know how to edit.
1472
0
  std::string ll = this->GetLinkerLanguage(config);
1473
0
  if (!ll.empty()) {
1474
0
    std::string sepVar =
1475
0
      cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
1476
0
    cmValue sep = this->Makefile->GetDefinition(sepVar);
1477
0
    if (cmNonempty(sep)) {
1478
      // TODO: Add binary format check to ABI detection and get rid of
1479
      // CMAKE_EXECUTABLE_FORMAT.
1480
0
      if (cmValue fmt =
1481
0
            this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
1482
0
        if (*fmt == "ELF") {
1483
0
          return true;
1484
0
        }
1485
#if defined(CMake_USE_XCOFF_PARSER)
1486
        if (*fmt == "XCOFF") {
1487
          return true;
1488
        }
1489
#endif
1490
0
      }
1491
0
    }
1492
0
  }
1493
0
  return false;
1494
0
}
1495
1496
bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
1497
  std::string const& config) const
1498
0
{
1499
0
  if (this->IsImported() && this->GetType() == cmStateEnums::SHARED_LIBRARY) {
1500
0
    if (cmGeneratorTarget::ImportInfo const* info =
1501
0
          this->GetImportInfo(config)) {
1502
0
      return info->NoSOName;
1503
0
    }
1504
0
  }
1505
0
  return false;
1506
0
}
1507
1508
bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
1509
  std::string const& config) const
1510
0
{
1511
0
  TargetPtrToBoolMap& cache = this->MacOSXRpathInstallNameDirCache[config];
1512
0
  auto const lookup = cache.find(this->Target);
1513
1514
0
  if (lookup != cache.cend()) {
1515
0
    return lookup->second;
1516
0
  }
1517
1518
0
  bool const result = this->DetermineHasMacOSXRpathInstallNameDir(config);
1519
0
  cache[this->Target] = result;
1520
0
  return result;
1521
0
}
1522
1523
bool cmGeneratorTarget::DetermineHasMacOSXRpathInstallNameDir(
1524
  std::string const& config) const
1525
0
{
1526
0
  bool install_name_is_rpath = false;
1527
0
  bool macosx_rpath = false;
1528
1529
0
  if (!this->IsImported()) {
1530
0
    if (this->GetType() != cmStateEnums::SHARED_LIBRARY) {
1531
0
      return false;
1532
0
    }
1533
0
    cmValue install_name = this->GetProperty("INSTALL_NAME_DIR");
1534
0
    bool use_install_name = this->MacOSXUseInstallNameDir();
1535
0
    if (install_name && use_install_name && *install_name == "@rpath") {
1536
0
      install_name_is_rpath = true;
1537
0
    } else if (install_name && use_install_name) {
1538
0
      return false;
1539
0
    }
1540
0
    if (!install_name_is_rpath) {
1541
0
      macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
1542
0
    }
1543
0
  } else {
1544
    // Lookup the imported soname.
1545
0
    if (cmGeneratorTarget::ImportInfo const* info =
1546
0
          this->GetImportInfo(config)) {
1547
0
      if (!info->NoSOName && !info->SOName.empty()) {
1548
0
        if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
1549
0
          install_name_is_rpath = true;
1550
0
        }
1551
0
      } else {
1552
0
        std::string install_name;
1553
0
        cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
1554
0
        if (install_name.find("@rpath") != std::string::npos) {
1555
0
          install_name_is_rpath = true;
1556
0
        }
1557
0
      }
1558
0
    }
1559
0
  }
1560
1561
0
  if (!install_name_is_rpath && !macosx_rpath) {
1562
0
    return false;
1563
0
  }
1564
1565
0
  if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
1566
0
    std::ostringstream w;
1567
0
    w << "Attempting to use ";
1568
0
    if (macosx_rpath) {
1569
0
      w << "MACOSX_RPATH";
1570
0
    } else {
1571
0
      w << "@rpath";
1572
0
    }
1573
0
    w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
1574
0
    w << "  This could be because you are using a Mac OS X version";
1575
0
    w << " less than 10.5 or because CMake's platform configuration is";
1576
0
    w << " corrupt.";
1577
0
    cmake* cm = this->LocalGenerator->GetCMakeInstance();
1578
0
    cm->IssueMessage(MessageType::FATAL_ERROR, w.str(), this->GetBacktrace());
1579
0
  }
1580
1581
0
  return true;
1582
0
}
1583
1584
bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
1585
0
{
1586
  // we can't do rpaths when unsupported
1587
0
  if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) {
1588
0
    return false;
1589
0
  }
1590
1591
0
  cmValue macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
1592
0
  if (macosx_rpath_str) {
1593
0
    return this->GetPropertyAsBool("MACOSX_RPATH");
1594
0
  }
1595
1596
0
  return true;
1597
0
}
1598
1599
bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
1600
0
{
1601
0
  cmValue build_with_install_name =
1602
0
    this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
1603
0
  if (build_with_install_name) {
1604
0
    return build_with_install_name.IsOn();
1605
0
  }
1606
1607
0
  cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
1608
0
  if (cmp0068 == cmPolicies::NEW) {
1609
0
    return false;
1610
0
  }
1611
1612
0
  bool use_install_name = this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
1613
1614
0
  if (use_install_name && cmp0068 == cmPolicies::WARN) {
1615
0
    this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
1616
0
      this->GetName());
1617
0
  }
1618
1619
0
  return use_install_name;
1620
0
}
1621
1622
bool cmGeneratorTarget::CanGenerateInstallNameDir(
1623
  InstallNameType name_type) const
1624
0
{
1625
0
  cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068();
1626
1627
0
  if (cmp0068 == cmPolicies::NEW) {
1628
0
    return true;
1629
0
  }
1630
1631
0
  bool skip = this->Makefile->IsOn("CMAKE_SKIP_RPATH");
1632
0
  if (name_type == INSTALL_NAME_FOR_INSTALL) {
1633
0
    skip |= this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
1634
0
  } else {
1635
0
    skip |= this->GetPropertyAsBool("SKIP_BUILD_RPATH");
1636
0
  }
1637
1638
0
  if (skip && cmp0068 == cmPolicies::WARN) {
1639
0
    this->LocalGenerator->GetGlobalGenerator()->AddCMP0068WarnTarget(
1640
0
      this->GetName());
1641
0
  }
1642
1643
0
  return !skip;
1644
0
}
1645
1646
std::string cmGeneratorTarget::GetSOName(
1647
  std::string const& config, cmStateEnums::ArtifactType artifact) const
1648
0
{
1649
0
  if (this->IsImported()) {
1650
    // Lookup the imported soname.
1651
0
    if (cmGeneratorTarget::ImportInfo const* info =
1652
0
          this->GetImportInfo(config)) {
1653
0
      if (info->NoSOName) {
1654
        // The imported library has no builtin soname so the name
1655
        // searched at runtime will be just the filename.
1656
0
        return cmSystemTools::GetFilenameName(info->Location);
1657
0
      }
1658
      // Use the soname given if any.
1659
0
      if (this->IsFrameworkOnApple()) {
1660
0
        auto fwDescriptor = this->GetGlobalGenerator()->SplitFrameworkPath(
1661
0
          info->SOName, cmGlobalGenerator::FrameworkFormat::Strict);
1662
0
        if (fwDescriptor) {
1663
0
          return fwDescriptor->GetVersionedName();
1664
0
        }
1665
0
      }
1666
0
      if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
1667
0
        return info->SOName.substr(cmStrLen("@rpath/"));
1668
0
      }
1669
0
      return info->SOName;
1670
0
    }
1671
0
    return "";
1672
0
  }
1673
  // Compute the soname that will be built.
1674
0
  return artifact == cmStateEnums::RuntimeBinaryArtifact
1675
0
    ? this->GetLibraryNames(config).SharedObject
1676
0
    : this->GetLibraryNames(config).ImportLibrary;
1677
0
}
1678
1679
namespace {
1680
bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
1681
0
{
1682
0
  return level == cmGeneratorTarget::FullLevel;
1683
0
}
1684
1685
bool shouldAddContentLevel(cmGeneratorTarget::BundleDirectoryLevel level)
1686
0
{
1687
0
  return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level);
1688
0
}
1689
}
1690
1691
std::string cmGeneratorTarget::GetAppBundleDirectory(
1692
  std::string const& config, BundleDirectoryLevel level) const
1693
0
{
1694
0
  std::string fpath = cmStrCat(
1695
0
    this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
1696
0
  cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
1697
0
  fpath += (ext ? *ext : "app");
1698
0
  if (shouldAddContentLevel(level) &&
1699
0
      !this->Makefile->PlatformIsAppleEmbedded()) {
1700
0
    fpath += "/Contents";
1701
0
    if (shouldAddFullLevel(level)) {
1702
0
      fpath += "/MacOS";
1703
0
    }
1704
0
  }
1705
0
  return fpath;
1706
0
}
1707
1708
bool cmGeneratorTarget::IsBundleOnApple() const
1709
0
{
1710
0
  return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
1711
0
    this->IsCFBundleOnApple();
1712
0
}
1713
1714
bool cmGeneratorTarget::IsWin32Executable(std::string const& config) const
1715
0
{
1716
0
  return cmIsOn(cmGeneratorExpression::Evaluate(
1717
0
    this->GetSafeProperty("WIN32_EXECUTABLE"), this->LocalGenerator, config));
1718
0
}
1719
1720
std::string cmGeneratorTarget::GetCFBundleDirectory(
1721
  std::string const& config, BundleDirectoryLevel level) const
1722
0
{
1723
0
  std::string fpath = cmStrCat(
1724
0
    this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
1725
0
  std::string ext;
1726
0
  if (cmValue p = this->GetProperty("BUNDLE_EXTENSION")) {
1727
0
    ext = *p;
1728
0
  } else {
1729
0
    if (this->IsXCTestOnApple()) {
1730
0
      ext = "xctest";
1731
0
    } else {
1732
0
      ext = "bundle";
1733
0
    }
1734
0
  }
1735
0
  fpath += ext;
1736
0
  if (shouldAddContentLevel(level) &&
1737
0
      !this->Makefile->PlatformIsAppleEmbedded()) {
1738
0
    fpath += "/Contents";
1739
0
    if (shouldAddFullLevel(level)) {
1740
0
      fpath += "/MacOS";
1741
0
    }
1742
0
  }
1743
0
  return fpath;
1744
0
}
1745
1746
std::string cmGeneratorTarget::GetFrameworkDirectory(
1747
  std::string const& config, BundleDirectoryLevel level) const
1748
0
{
1749
0
  std::string fpath = cmStrCat(
1750
0
    this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
1751
0
  cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
1752
0
  fpath += (ext ? *ext : "framework");
1753
0
  if (shouldAddFullLevel(level) &&
1754
0
      !this->Makefile->PlatformIsAppleEmbedded()) {
1755
0
    fpath += "/Versions/";
1756
0
    fpath += this->GetFrameworkVersion();
1757
0
  }
1758
0
  return fpath;
1759
0
}
1760
1761
std::string cmGeneratorTarget::GetFullName(
1762
  std::string const& config, cmStateEnums::ArtifactType artifact) const
1763
0
{
1764
0
  if (this->IsImported()) {
1765
0
    return this->GetFullNameImported(config, artifact);
1766
0
  }
1767
0
  return this->GetFullNameInternal(config, artifact);
1768
0
}
1769
1770
std::string cmGeneratorTarget::GetInstallNameDirForBuildTree(
1771
  std::string const& config) const
1772
0
{
1773
0
  if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
1774
1775
    // If building directly for installation then the build tree install_name
1776
    // is the same as the install tree.
1777
0
    if (this->MacOSXUseInstallNameDir()) {
1778
0
      std::string installPrefix =
1779
0
        this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
1780
0
      return this->GetInstallNameDirForInstallTree(config, installPrefix);
1781
0
    }
1782
1783
    // Use the build tree directory for the target.
1784
0
    if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_BUILD)) {
1785
0
      std::string dir;
1786
0
      if (this->MacOSXRpathInstallNameDirDefault()) {
1787
0
        dir = "@rpath";
1788
0
      } else {
1789
0
        dir = this->GetDirectory(config);
1790
0
      }
1791
0
      dir += "/";
1792
0
      return dir;
1793
0
    }
1794
0
  }
1795
0
  return "";
1796
0
}
1797
1798
std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
1799
  std::string const& config, std::string const& installPrefix) const
1800
0
{
1801
0
  if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
1802
0
    std::string dir;
1803
0
    cmValue install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
1804
1805
0
    if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
1806
0
      if (cmNonempty(install_name_dir)) {
1807
0
        dir = *install_name_dir;
1808
0
        cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
1809
0
        dir =
1810
0
          cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config);
1811
0
        if (!dir.empty()) {
1812
0
          dir = cmStrCat(dir, '/');
1813
0
        }
1814
0
      }
1815
0
    }
1816
0
    if (!install_name_dir) {
1817
0
      if (this->MacOSXRpathInstallNameDirDefault()) {
1818
0
        dir = "@rpath/";
1819
0
      }
1820
0
    }
1821
0
    return dir;
1822
0
  }
1823
0
  return "";
1824
0
}
1825
1826
cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
1827
0
{
1828
0
  return this->Target->GetBacktrace();
1829
0
}
1830
1831
std::set<BT<std::pair<std::string, bool>>> const&
1832
cmGeneratorTarget::GetUtilities() const
1833
0
{
1834
0
  return this->Target->GetUtilities();
1835
0
}
1836
1837
bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
1838
0
{
1839
0
  return this->GetType() == cmStateEnums::STATIC_LIBRARY ||
1840
0
    this->GetType() == cmStateEnums::SHARED_LIBRARY ||
1841
0
    this->GetType() == cmStateEnums::MODULE_LIBRARY ||
1842
0
    this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
1843
0
    this->GetType() == cmStateEnums::EXECUTABLE;
1844
0
}
1845
1846
std::string const* cmGeneratorTarget::GetExportMacro() const
1847
0
{
1848
  // Define the symbol for targets that export symbols.
1849
0
  if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
1850
0
      this->GetType() == cmStateEnums::MODULE_LIBRARY ||
1851
0
      this->IsExecutableWithExports()) {
1852
0
    if (cmValue custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
1853
0
      this->ExportMacro = *custom_export_name;
1854
0
    } else {
1855
0
      std::string in = cmStrCat(this->GetName(), "_EXPORTS");
1856
0
      this->ExportMacro = cmSystemTools::MakeCidentifier(in);
1857
0
    }
1858
0
    return &this->ExportMacro;
1859
0
  }
1860
0
  return nullptr;
1861
0
}
1862
1863
cmList const& cmGeneratorTarget::GetSharedLibraryCompileDefs(
1864
  std::string const& config) const
1865
0
{
1866
0
  {
1867
0
    auto it = this->SharedLibraryCompileDefs.find(config);
1868
0
    if (it != this->SharedLibraryCompileDefs.end()) {
1869
0
      return it->second;
1870
0
    }
1871
0
  }
1872
1873
0
  auto emplaceResult =
1874
0
    this->SharedLibraryCompileDefs.emplace(config, cmList{});
1875
0
  auto& defs = emplaceResult.first->second;
1876
0
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
1877
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY) {
1878
0
    return defs;
1879
0
  }
1880
1881
0
  if (this->GetPolicyStatusCMP0203() != cmPolicies::NEW) {
1882
0
    return defs;
1883
0
  }
1884
1885
0
  auto linkerLang = this->GetLinkerLanguage(config);
1886
0
  auto definitionVar =
1887
0
    cmStrCat("CMAKE_", linkerLang, "_SHARED_LIBRARY_COMPILE_DEFINITIONS");
1888
0
  defs = this->Makefile->GetSafeDefinition(definitionVar);
1889
1890
0
  return defs;
1891
0
}
1892
1893
cmGeneratorTarget::NameComponents const&
1894
cmGeneratorTarget::GetFullNameComponents(
1895
  std::string const& config, cmStateEnums::ArtifactType artifact) const
1896
0
{
1897
0
  return this->GetFullNameInternalComponents(config, artifact);
1898
0
}
1899
1900
std::string cmGeneratorTarget::BuildBundleDirectory(
1901
  std::string const& base, std::string const& config,
1902
  BundleDirectoryLevel level) const
1903
0
{
1904
0
  std::string fpath = base;
1905
0
  if (this->IsAppBundleOnApple()) {
1906
0
    fpath += this->GetAppBundleDirectory(config, level);
1907
0
  }
1908
0
  if (this->IsFrameworkOnApple()) {
1909
0
    fpath += this->GetFrameworkDirectory(config, level);
1910
0
  }
1911
0
  if (this->IsCFBundleOnApple()) {
1912
0
    fpath += this->GetCFBundleDirectory(config, level);
1913
0
  }
1914
0
  return fpath;
1915
0
}
1916
1917
std::string cmGeneratorTarget::GetMacContentDirectory(
1918
  std::string const& config, cmStateEnums::ArtifactType artifact) const
1919
0
{
1920
  // Start with the output directory for the target.
1921
0
  std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
1922
0
  BundleDirectoryLevel level = ContentLevel;
1923
0
  if (this->IsFrameworkOnApple()) {
1924
    // additional files with a framework go into the version specific
1925
    // directory
1926
0
    level = FullLevel;
1927
0
  }
1928
0
  fpath = this->BuildBundleDirectory(fpath, config, level);
1929
0
  return fpath;
1930
0
}
1931
1932
std::string cmGeneratorTarget::GetEffectiveFolderName() const
1933
0
{
1934
0
  std::string effectiveFolder;
1935
1936
0
  if (!this->GlobalGenerator->UseFolderProperty()) {
1937
0
    return effectiveFolder;
1938
0
  }
1939
1940
0
  cmValue targetFolder = this->GetProperty("FOLDER");
1941
0
  if (targetFolder) {
1942
0
    effectiveFolder += *targetFolder;
1943
0
  }
1944
1945
0
  return effectiveFolder;
1946
0
}
1947
1948
cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
1949
  std::string const& config) const
1950
0
{
1951
  // There is no compile information for imported targets.
1952
0
  if (this->IsImported()) {
1953
0
    return nullptr;
1954
0
  }
1955
1956
0
  if (this->GetType() > cmStateEnums::OBJECT_LIBRARY) {
1957
0
    std::string msg = cmStrCat("cmTarget::GetCompileInfo called for ",
1958
0
                               this->GetName(), " which has type ",
1959
0
                               cmState::GetTargetTypeName(this->GetType()));
1960
0
    this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
1961
0
    return nullptr;
1962
0
  }
1963
1964
  // Lookup/compute/cache the compile information for this configuration.
1965
0
  std::string config_upper;
1966
0
  if (!config.empty()) {
1967
0
    config_upper = cmSystemTools::UpperCase(config);
1968
0
  }
1969
0
  auto i = this->CompileInfoMap.find(config_upper);
1970
0
  if (i == this->CompileInfoMap.end()) {
1971
0
    CompileInfo info;
1972
0
    this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
1973
0
    CompileInfoMapType::value_type entry(config_upper, info);
1974
0
    i = this->CompileInfoMap.insert(entry).first;
1975
0
  }
1976
0
  return &i->second;
1977
0
}
1978
1979
cmGeneratorTarget::ModuleDefinitionInfo const*
1980
cmGeneratorTarget::GetModuleDefinitionInfo(std::string const& config) const
1981
0
{
1982
  // A module definition file only makes sense on certain target types.
1983
0
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
1984
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
1985
0
      !this->IsExecutableWithExports()) {
1986
0
    return nullptr;
1987
0
  }
1988
1989
  // Lookup/compute/cache the compile information for this configuration.
1990
0
  std::string config_upper;
1991
0
  if (!config.empty()) {
1992
0
    config_upper = cmSystemTools::UpperCase(config);
1993
0
  }
1994
0
  auto i = this->ModuleDefinitionInfoMap.find(config_upper);
1995
0
  if (i == this->ModuleDefinitionInfoMap.end()) {
1996
0
    ModuleDefinitionInfo info;
1997
0
    this->ComputeModuleDefinitionInfo(config, info);
1998
0
    ModuleDefinitionInfoMapType::value_type entry(config_upper, info);
1999
0
    i = this->ModuleDefinitionInfoMap.insert(entry).first;
2000
0
  }
2001
0
  return &i->second;
2002
0
}
2003
2004
void cmGeneratorTarget::ComputeModuleDefinitionInfo(
2005
  std::string const& config, ModuleDefinitionInfo& info) const
2006
0
{
2007
0
  this->GetModuleDefinitionSources(info.Sources, config);
2008
0
  info.WindowsExportAllSymbols =
2009
0
    this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
2010
0
    this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
2011
0
#if !defined(CMAKE_BOOTSTRAP)
2012
0
  info.DefFileGenerated =
2013
0
    info.WindowsExportAllSymbols || info.Sources.size() > 1;
2014
#else
2015
  // Our __create_def helper is not available during CMake bootstrap.
2016
  info.DefFileGenerated = false;
2017
#endif
2018
0
  if (info.DefFileGenerated) {
2019
0
    info.DefFile =
2020
0
      this->GetObjectDirectory(config) /* has slash */ + "exports.def";
2021
0
  } else if (!info.Sources.empty()) {
2022
0
    info.DefFile = info.Sources.front()->GetFullPath();
2023
0
  }
2024
0
}
2025
2026
bool cmGeneratorTarget::IsAIX() const
2027
0
{
2028
0
  return this->Target->IsAIX();
2029
0
}
2030
2031
bool cmGeneratorTarget::IsApple() const
2032
0
{
2033
0
  return this->Target->IsApple();
2034
0
}
2035
2036
bool cmGeneratorTarget::IsDLLPlatform() const
2037
0
{
2038
0
  return this->Target->IsDLLPlatform();
2039
0
}
2040
2041
void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
2042
                                          std::string const& config) const
2043
0
{
2044
0
  char const* prop =
2045
0
    this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", config);
2046
0
  if (!prop) {
2047
0
    return;
2048
0
  }
2049
2050
0
  cm::GenEx::Context context(this->LocalGenerator, config);
2051
0
  cmGeneratorExpressionDAGChecker dagChecker{
2052
0
    this, "AUTOUIC_OPTIONS", nullptr, nullptr, context,
2053
0
  };
2054
0
  cmExpandList(cmGeneratorExpression::Evaluate(
2055
0
                 prop, context.LG, context.Config, this, &dagChecker),
2056
0
               result);
2057
0
}
2058
2059
void cmGeneratorTarget::TraceDependencies()
2060
0
{
2061
  // CMake-generated targets have no dependencies to trace.  Normally tracing
2062
  // would find nothing anyway, but when building CMake itself the "install"
2063
  // target command ends up referencing the "cmake" target but we do not
2064
  // really want the dependency because "install" depend on "all" anyway.
2065
0
  if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
2066
0
    return;
2067
0
  }
2068
2069
  // Use a helper object to trace the dependencies.
2070
0
  cmTargetTraceDependencies tracer(this);
2071
0
  tracer.Trace();
2072
0
}
2073
2074
std::string cmGeneratorTarget::GetCompilePDBDirectory(
2075
  std::string const& config) const
2076
0
{
2077
0
  if (CompileInfo const* info = this->GetCompileInfo(config)) {
2078
0
    return info->CompilePdbDir;
2079
0
  }
2080
0
  return "";
2081
0
}
2082
2083
std::vector<std::string> cmGeneratorTarget::GetAppleArchs(
2084
  std::string const& config, cm::optional<std::string> lang) const
2085
0
{
2086
0
  cmList archList;
2087
0
  if (!this->IsApple()) {
2088
0
    return std::move(archList.data());
2089
0
  }
2090
0
  cmValue archs = nullptr;
2091
0
  if (!config.empty()) {
2092
0
    std::string defVarName =
2093
0
      cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config));
2094
0
    archs = this->GetProperty(defVarName);
2095
0
  }
2096
0
  if (!archs) {
2097
0
    archs = this->GetProperty("OSX_ARCHITECTURES");
2098
0
  }
2099
0
  if (archs) {
2100
0
    archList.assign(*archs);
2101
0
  }
2102
0
  if (archList.empty() &&
2103
      // Fall back to a default architecture if no compiler target is set.
2104
0
      (!lang ||
2105
0
       this->Makefile
2106
0
         ->GetDefinition(cmStrCat("CMAKE_", *lang, "_COMPILER_TARGET"))
2107
0
         .IsEmpty())) {
2108
0
    archList.assign(
2109
0
      this->Makefile->GetDefinition("_CMAKE_APPLE_ARCHS_DEFAULT"));
2110
0
  }
2111
0
  return std::move(archList.data());
2112
0
}
2113
2114
namespace {
2115
2116
bool IsSupportedClassifiedFlagsLanguage(std::string const& lang)
2117
0
{
2118
0
  return lang == "CXX"_s;
2119
0
}
2120
2121
bool CanUseCompilerLauncher(std::string const& lang)
2122
0
{
2123
  // Also found in `cmCommonTargetGenerator::GetCompilerLauncher`.
2124
0
  return lang == "C"_s || lang == "CXX"_s || lang == "Fortran"_s ||
2125
0
    lang == "CUDA"_s || lang == "HIP"_s || lang == "ISPC"_s ||
2126
0
    lang == "OBJC"_s || lang == "OBJCXX"_s;
2127
0
}
2128
2129
// FIXME: return a vector of `cm::string_view` instead to avoid lots of tiny
2130
// allocations.
2131
std::vector<std::string> SplitFlags(std::string const& flags)
2132
0
{
2133
0
  std::vector<std::string> options;
2134
2135
#ifdef _WIN32
2136
  cmSystemTools::ParseWindowsCommandLine(flags.c_str(), options);
2137
#else
2138
0
  cmSystemTools::ParseUnixCommandLine(flags.c_str(), options);
2139
0
#endif
2140
2141
0
  return options;
2142
0
}
2143
2144
}
2145
2146
cmGeneratorTarget::ClassifiedFlags
2147
cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
2148
                                               std::string const& config)
2149
0
{
2150
0
  auto& sourceFlagsCache = this->Configs[config].SourceFlags;
2151
0
  auto cacheEntry = sourceFlagsCache.lower_bound(sf);
2152
0
  if (cacheEntry != sourceFlagsCache.end() && cacheEntry->first == sf) {
2153
0
    return cacheEntry->second;
2154
0
  }
2155
2156
0
  ClassifiedFlags flags;
2157
0
  std::string const& lang = sf->GetLanguage();
2158
2159
0
  if (!IsSupportedClassifiedFlagsLanguage(lang)) {
2160
0
    return flags;
2161
0
  }
2162
2163
0
  auto* const lg = this->GetLocalGenerator();
2164
0
  auto const* const mf = this->Makefile;
2165
2166
  // Compute the compiler launcher flags.
2167
0
  if (CanUseCompilerLauncher(lang)) {
2168
    // Compiler launchers are all execution flags and should not be relevant to
2169
    // the actual compilation.
2170
0
    FlagClassification cls = FlagClassification::ExecutionFlag;
2171
0
    FlagKind kind = FlagKind::NotAFlag;
2172
2173
0
    std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
2174
0
    cmValue clauncher = this->GetProperty(clauncher_prop);
2175
0
    std::string const evaluatedClauncher = cmGeneratorExpression::Evaluate(
2176
0
      *clauncher, lg, config, this, nullptr, this, lang);
2177
2178
0
    for (auto const& flag : SplitFlags(evaluatedClauncher)) {
2179
0
      flags.emplace_back(cls, kind, flag);
2180
0
    }
2181
0
  }
2182
2183
0
  ClassifiedFlags define_flags;
2184
0
  ClassifiedFlags include_flags;
2185
0
  ClassifiedFlags compile_flags;
2186
2187
0
  SourceVariables sfVars = this->GetSourceVariables(sf, config);
2188
2189
  // Compute language flags.
2190
0
  {
2191
0
    FlagClassification cls = FlagClassification::BaselineFlag;
2192
0
    FlagKind kind = FlagKind::Compile;
2193
2194
0
    std::string mfFlags;
2195
    // Explicitly add the explicit language flag before any other flag
2196
    // so user flags can override it.
2197
0
    this->AddExplicitLanguageFlags(mfFlags, *sf);
2198
2199
0
    for (auto const& flag : SplitFlags(mfFlags)) {
2200
0
      flags.emplace_back(cls, kind, flag);
2201
0
    }
2202
0
  }
2203
2204
0
  std::unordered_map<std::string, std::string> pchSources;
2205
0
  std::string filterArch;
2206
2207
0
  {
2208
0
    std::vector<std::string> pchArchs = this->GetPchArchs(config, lang);
2209
2210
0
    for (std::string const& arch : pchArchs) {
2211
0
      std::string const pchSource = this->GetPchSource(config, lang, arch);
2212
0
      if (pchSource == sf->GetFullPath()) {
2213
0
        filterArch = arch;
2214
0
      }
2215
0
      if (!pchSource.empty()) {
2216
0
        pchSources.insert(std::make_pair(pchSource, arch));
2217
0
      }
2218
0
    }
2219
0
  }
2220
2221
  // Compute target-wide flags.
2222
0
  {
2223
0
    FlagClassification cls = FlagClassification::BaselineFlag;
2224
2225
    // Compile flags
2226
0
    {
2227
0
      FlagKind kind = FlagKind::Compile;
2228
0
      std::string targetFlags;
2229
2230
0
      lg->GetTargetCompileFlags(this, config, lang, targetFlags, filterArch);
2231
2232
0
      for (auto&& flag : SplitFlags(targetFlags)) {
2233
0
        compile_flags.emplace_back(cls, kind, std::move(flag));
2234
0
      }
2235
0
    }
2236
2237
    // Define flags
2238
0
    {
2239
0
      FlagKind kind = FlagKind::Definition;
2240
0
      std::set<std::string> defines;
2241
2242
0
      lg->GetTargetDefines(this, config, lang, defines);
2243
2244
0
      std::string defineFlags;
2245
0
      lg->JoinDefines(defines, defineFlags, lang);
2246
2247
0
      for (auto&& flag : SplitFlags(defineFlags)) {
2248
0
        define_flags.emplace_back(cls, kind, std::move(flag));
2249
0
      }
2250
0
    }
2251
2252
    // Include flags
2253
0
    {
2254
0
      FlagKind kind = FlagKind::Include;
2255
0
      std::vector<std::string> includes;
2256
2257
0
      lg->GetIncludeDirectories(includes, this, lang, config);
2258
0
      auto includeFlags =
2259
0
        lg->GetIncludeFlags(includes, this, lang, config, false);
2260
2261
0
      for (auto&& flag : SplitFlags(includeFlags)) {
2262
0
        include_flags.emplace_back(cls, kind, std::move(flag));
2263
0
      }
2264
0
    }
2265
0
  }
2266
2267
0
  std::string const COMPILE_FLAGS("COMPILE_FLAGS");
2268
0
  std::string const COMPILE_OPTIONS("COMPILE_OPTIONS");
2269
2270
0
  cmGeneratorExpressionInterpreter genexInterpreter(lg, config, this, lang);
2271
2272
  // Source-specific flags.
2273
0
  {
2274
0
    FlagClassification cls = FlagClassification::PrivateFlag;
2275
0
    FlagKind kind = FlagKind::Compile;
2276
2277
0
    std::string sourceFlags;
2278
2279
0
    if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
2280
0
      lg->AppendFlags(sourceFlags,
2281
0
                      genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
2282
0
    }
2283
2284
0
    if (cmValue coptions = sf->GetProperty(COMPILE_OPTIONS)) {
2285
0
      lg->AppendCompileOptions(
2286
0
        sourceFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
2287
0
    }
2288
2289
0
    for (auto&& flag : SplitFlags(sourceFlags)) {
2290
0
      compile_flags.emplace_back(cls, kind, std::move(flag));
2291
0
    }
2292
2293
    // Dependency tracking flags.
2294
0
    {
2295
0
      if (!sfVars.DependencyFlags.empty()) {
2296
0
        cmRulePlaceholderExpander::RuleVariables vars;
2297
0
        auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
2298
2299
0
        vars.DependencyFile = sfVars.DependencyFile.c_str();
2300
0
        vars.DependencyTarget = sfVars.DependencyTarget.c_str();
2301
2302
0
        std::string depfileFlags = sfVars.DependencyFlags;
2303
0
        rulePlaceholderExpander->ExpandRuleVariables(lg, depfileFlags, vars);
2304
0
        for (auto&& flag : SplitFlags(depfileFlags)) {
2305
0
          compile_flags.emplace_back(FlagClassification::LocationFlag,
2306
0
                                     FlagKind::BuildSystem, std::move(flag));
2307
0
        }
2308
0
      }
2309
0
    }
2310
0
  }
2311
2312
  // Precompiled headers.
2313
0
  {
2314
0
    FlagClassification cls = FlagClassification::PrivateFlag;
2315
0
    FlagKind kind = FlagKind::Compile;
2316
2317
0
    std::string pchFlags;
2318
2319
    // Add precompile headers compile options.
2320
0
    if (!sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
2321
0
      if (!pchSources.empty()) {
2322
0
        std::string pchOptions;
2323
0
        auto pchIt = pchSources.find(sf->GetFullPath());
2324
0
        if (pchIt != pchSources.end()) {
2325
0
          pchOptions =
2326
0
            this->GetPchCreateCompileOptions(config, lang, pchIt->second);
2327
0
        } else {
2328
0
          pchOptions = this->GetPchUseCompileOptions(config, lang);
2329
0
        }
2330
2331
0
        this->LocalGenerator->AppendCompileOptions(
2332
0
          pchFlags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
2333
0
      }
2334
0
    }
2335
2336
0
    for (auto&& flag : SplitFlags(pchFlags)) {
2337
0
      compile_flags.emplace_back(cls, kind, std::move(flag));
2338
0
    }
2339
0
  }
2340
2341
  // C++ module flags.
2342
0
  if (lang == "CXX"_s) {
2343
0
    FlagClassification cls = FlagClassification::LocationFlag;
2344
0
    FlagKind kind = FlagKind::BuildSystem;
2345
2346
0
    std::string bmiFlags;
2347
2348
0
    auto const* fs = this->GetFileSetForSource(config, sf);
2349
0
    if (fs && fs->GetType() == cm::FileSetMetadata::CXX_MODULES) {
2350
0
      if (lang != "CXX"_s) {
2351
0
        mf->IssueMessage(
2352
0
          MessageType::FATAL_ERROR,
2353
0
          cmStrCat(
2354
0
            "Target \"", this->Target->GetName(), "\" contains the source\n  ",
2355
0
            sf->GetFullPath(), "\nin a file set of type \"", fs->GetType(),
2356
0
            R"(" but the source is not classified as a "CXX" source.)"));
2357
0
      }
2358
2359
0
      if (!this->Target->IsNormal()) {
2360
0
        auto flag = mf->GetSafeDefinition("CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
2361
0
        cmRulePlaceholderExpander::RuleVariables compileObjectVars;
2362
0
        compileObjectVars.Object = sfVars.ObjectFileDir.c_str();
2363
0
        auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
2364
0
        rulePlaceholderExpander->ExpandRuleVariables(lg, flag,
2365
0
                                                     compileObjectVars);
2366
0
        lg->AppendCompileOptions(bmiFlags, flag);
2367
0
      }
2368
0
    }
2369
2370
0
    for (auto&& flag : SplitFlags(bmiFlags)) {
2371
0
      compile_flags.emplace_back(cls, kind, std::move(flag));
2372
0
    }
2373
0
  }
2374
2375
0
  cmRulePlaceholderExpander::RuleVariables vars;
2376
0
  vars.CMTargetName = this->GetName().c_str();
2377
0
  vars.CMTargetType = cmState::GetTargetTypeName(this->GetType()).c_str();
2378
0
  vars.Language = lang.c_str();
2379
2380
0
  auto const sfPath = this->LocalGenerator->ConvertToOutputFormat(
2381
0
    sf->GetFullPath(), cmOutputConverter::SHELL);
2382
2383
  // Compute the base compiler command line. We'll find placeholders and
2384
  // replace them with arguments later in this function.
2385
0
  {
2386
0
    FlagClassification cls = FlagClassification::ExecutionFlag;
2387
0
    FlagKind kind = FlagKind::NotAFlag;
2388
2389
0
    std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
2390
0
    std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar);
2391
0
    cmList compileCmds(compileCmd); // FIXME: which command to use?
2392
0
    std::string& cmd = compileCmds[0];
2393
0
    auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
2394
2395
0
    static std::string const PlaceholderDefines = "__CMAKE_DEFINES";
2396
0
    static std::string const PlaceholderIncludes = "__CMAKE_INCLUDES";
2397
0
    static std::string const PlaceholderFlags = "__CMAKE_FLAGS";
2398
0
    static std::string const PlaceholderSource = "__CMAKE_SOURCE";
2399
2400
0
    vars.Defines = PlaceholderDefines.c_str();
2401
0
    vars.Includes = PlaceholderIncludes.c_str();
2402
0
    vars.TargetPDB = sfVars.TargetPDB.c_str();
2403
0
    vars.TargetCompilePDB = sfVars.TargetCompilePDB.c_str();
2404
0
    vars.Object = sfVars.ObjectFileDir.c_str();
2405
0
    vars.ObjectDir = sfVars.ObjectDir.c_str();
2406
0
    vars.ObjectFileDir = sfVars.ObjectFileDir.c_str();
2407
0
    vars.TargetSupportDir = sfVars.TargetSupportDir.c_str();
2408
0
    vars.Flags = PlaceholderFlags.c_str();
2409
0
    vars.DependencyFile = sfVars.DependencyFile.c_str();
2410
0
    vars.DependencyTarget = sfVars.DependencyTarget.c_str();
2411
0
    vars.Source = PlaceholderSource.c_str();
2412
2413
0
    rulePlaceholderExpander->ExpandRuleVariables(lg, cmd, vars);
2414
0
    for (auto&& flag : SplitFlags(cmd)) {
2415
0
      if (flag == PlaceholderDefines) {
2416
0
        flags.insert(flags.end(), define_flags.begin(), define_flags.end());
2417
0
      } else if (flag == PlaceholderIncludes) {
2418
0
        flags.insert(flags.end(), include_flags.begin(), include_flags.end());
2419
0
      } else if (flag == PlaceholderFlags) {
2420
0
        flags.insert(flags.end(), compile_flags.begin(), compile_flags.end());
2421
0
      } else if (flag == PlaceholderSource) {
2422
0
        flags.emplace_back(FlagClassification::LocationFlag,
2423
0
                           FlagKind::BuildSystem, sfPath);
2424
0
      } else {
2425
0
        flags.emplace_back(cls, kind, std::move(flag));
2426
        // All remaining flags here are build system flags.
2427
0
        kind = FlagKind::BuildSystem;
2428
0
      }
2429
0
    }
2430
0
  }
2431
2432
0
  cacheEntry = sourceFlagsCache.emplace_hint(cacheEntry, sf, std::move(flags));
2433
0
  return cacheEntry->second;
2434
0
}
2435
2436
cmGeneratorTarget::SourceVariables cmGeneratorTarget::GetSourceVariables(
2437
  cmSourceFile const* sf, std::string const& config)
2438
0
{
2439
0
  SourceVariables vars;
2440
0
  auto const language = sf->GetLanguage();
2441
0
  auto const targetType = this->GetType();
2442
0
  auto const* const lg = this->GetLocalGenerator();
2443
0
  auto const* const gg = this->GetGlobalGenerator();
2444
0
  auto const* const mf = this->Makefile;
2445
2446
  // PDB settings.
2447
0
  {
2448
0
    if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
2449
0
        mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") ||
2450
0
        mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) {
2451
0
      std::string pdbPath;
2452
0
      std::string compilePdbPath;
2453
0
      if (targetType <= cmStateEnums::OBJECT_LIBRARY) {
2454
0
        compilePdbPath = this->GetCompilePDBPath(config);
2455
0
        if (compilePdbPath.empty()) {
2456
          // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`.
2457
          // A trailing slash tells the toolchain to add its default file name.
2458
0
          compilePdbPath = this->GetSupportDirectory();
2459
0
          if (gg->IsMultiConfig()) {
2460
0
            compilePdbPath = cmStrCat(compilePdbPath, '/', config);
2461
0
          }
2462
0
          compilePdbPath += '/';
2463
0
          if (targetType == cmStateEnums::STATIC_LIBRARY) {
2464
            // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`.
2465
0
            compilePdbPath = cmStrCat(compilePdbPath, this->GetName(), ".pdb");
2466
0
          }
2467
0
        }
2468
0
      }
2469
2470
0
      if (targetType == cmStateEnums::EXECUTABLE ||
2471
0
          targetType == cmStateEnums::STATIC_LIBRARY ||
2472
0
          targetType == cmStateEnums::SHARED_LIBRARY ||
2473
0
          targetType == cmStateEnums::MODULE_LIBRARY) {
2474
0
        pdbPath = cmStrCat(this->GetPDBDirectory(config), '/',
2475
0
                           this->GetPDBName(config));
2476
0
      }
2477
2478
0
      vars.TargetPDB = lg->ConvertToOutputFormat(
2479
0
        gg->ConvertToOutputPath(std::move(pdbPath)), cmOutputConverter::SHELL);
2480
0
      vars.TargetCompilePDB = lg->ConvertToOutputFormat(
2481
0
        gg->ConvertToOutputPath(std::move(compilePdbPath)),
2482
0
        cmOutputConverter::SHELL);
2483
0
    }
2484
0
  }
2485
2486
  // Object settings.
2487
0
  {
2488
0
    std::string const targetSupportDir = lg->MaybeRelativeToTopBinDir(
2489
0
      gg->ConvertToOutputPath(this->GetCMFSupportDirectory()));
2490
0
    std::string const objectDir = gg->ConvertToOutputPath(
2491
0
      cmStrCat(this->GetSupportDirectory(), gg->GetConfigDirectory(config)));
2492
0
    std::string const objectFileName = this->GetObjectName(sf);
2493
0
    std::string const objectFilePath =
2494
0
      cmStrCat(objectDir, '/', objectFileName);
2495
2496
0
    vars.TargetSupportDir =
2497
0
      lg->ConvertToOutputFormat(targetSupportDir, cmOutputConverter::SHELL);
2498
0
    vars.ObjectDir =
2499
0
      lg->ConvertToOutputFormat(objectDir, cmOutputConverter::SHELL);
2500
0
    vars.ObjectFileDir =
2501
0
      lg->ConvertToOutputFormat(objectFilePath, cmOutputConverter::SHELL);
2502
2503
    // Dependency settings.
2504
0
    {
2505
0
      std::string const depfileFormatName =
2506
0
        cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT");
2507
0
      std::string const depfileFormat =
2508
0
        mf->GetSafeDefinition(depfileFormatName);
2509
0
      if (depfileFormat != "msvc"_s) {
2510
0
        std::string const flagsName =
2511
0
          cmStrCat("CMAKE_DEPFILE_FLAGS_", language);
2512
0
        std::string const depfileFlags = mf->GetSafeDefinition(flagsName);
2513
0
        if (!depfileFlags.empty()) {
2514
0
          bool replaceExt = false;
2515
0
          if (!language.empty()) {
2516
0
            std::string const repVar =
2517
0
              cmStrCat("CMAKE_", language, "_DEPFILE_EXTENSION_REPLACE");
2518
0
            replaceExt = mf->IsOn(repVar);
2519
0
          }
2520
0
          std::string const depfilePath = cmStrCat(
2521
0
            objectDir, '/',
2522
0
            replaceExt
2523
0
              ? cmSystemTools::GetFilenameWithoutLastExtension(objectFileName)
2524
0
              : objectFileName,
2525
0
            ".d");
2526
2527
0
          vars.DependencyFlags = depfileFlags;
2528
0
          vars.DependencyTarget = vars.ObjectFileDir;
2529
0
          vars.DependencyFile =
2530
0
            lg->ConvertToOutputFormat(depfilePath, cmOutputConverter::SHELL);
2531
0
        }
2532
0
      }
2533
0
    }
2534
0
  }
2535
2536
0
  return vars;
2537
0
}
2538
2539
void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
2540
                                                 cmSourceFile const& sf) const
2541
0
{
2542
0
  cmValue lang = sf.GetProperty("LANGUAGE");
2543
0
  if (!lang) {
2544
0
    return;
2545
0
  }
2546
2547
0
  switch (this->GetPolicyStatusCMP0119()) {
2548
0
    case cmPolicies::WARN:
2549
0
      CM_FALLTHROUGH;
2550
0
    case cmPolicies::OLD:
2551
      // The OLD behavior is to not add explicit language flags.
2552
0
      return;
2553
0
    case cmPolicies::NEW:
2554
      // The NEW behavior is to add explicit language flags.
2555
0
      break;
2556
0
  }
2557
2558
0
  this->LocalGenerator->AppendFeatureOptions(flags, *lang,
2559
0
                                             "EXPLICIT_LANGUAGE");
2560
0
}
2561
2562
void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
2563
                                                 std::string const& config,
2564
                                                 std::string& flags) const
2565
0
{
2566
0
  std::string arch = this->GetSafeProperty("CUDA_ARCHITECTURES");
2567
2568
0
  if (arch.empty()) {
2569
0
    switch (this->GetPolicyStatusCMP0104()) {
2570
0
      case cmPolicies::WARN:
2571
0
        if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) {
2572
0
          this->Makefile->IssueMessage(
2573
0
            MessageType::AUTHOR_WARNING,
2574
0
            cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) +
2575
0
              "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
2576
0
              "\".");
2577
0
        }
2578
0
        CM_FALLTHROUGH;
2579
0
      case cmPolicies::OLD:
2580
0
        break;
2581
0
      default:
2582
0
        this->Makefile->IssueMessage(
2583
0
          MessageType::FATAL_ERROR,
2584
0
          "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() +
2585
0
            "\".");
2586
0
    }
2587
0
  }
2588
2589
  // If CUDA_ARCHITECTURES is false we don't add any architectures.
2590
0
  if (cmIsOff(arch)) {
2591
0
    return;
2592
0
  }
2593
2594
0
  this->AddCUDAArchitectureFlagsImpl(compileOrLink, config, "CUDA",
2595
0
                                     std::move(arch), flags);
2596
0
}
2597
2598
void cmGeneratorTarget::AddCUDAArchitectureFlagsImpl(cmBuildStep compileOrLink,
2599
                                                     std::string const& config,
2600
                                                     std::string const& lang,
2601
                                                     std::string arch,
2602
                                                     std::string& flags) const
2603
0
{
2604
0
  std::string const& compiler = this->Makefile->GetSafeDefinition(
2605
0
    cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
2606
0
  bool const ipoEnabled = this->IsIPOEnabled(lang, config);
2607
2608
  // Check for special modes: `all`, `all-major`.
2609
0
  if (arch == "all" || arch == "all-major") {
2610
0
    if (compiler == "NVIDIA" &&
2611
0
        cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
2612
0
                                      this->Makefile->GetDefinition(cmStrCat(
2613
0
                                        "CMAKE_", lang, "_COMPILER_VERSION")),
2614
0
                                      "11.5")) {
2615
0
      flags = cmStrCat(flags, " -arch=", arch);
2616
0
      return;
2617
0
    }
2618
0
    if (arch == "all") {
2619
0
      arch = *this->Makefile->GetDefinition(
2620
0
        cmStrCat("CMAKE_", lang, "_ARCHITECTURES_ALL"));
2621
0
    } else if (arch == "all-major") {
2622
0
      arch = *this->Makefile->GetDefinition(
2623
0
        cmStrCat("CMAKE_", lang, "_ARCHITECTURES_ALL_MAJOR"));
2624
0
    }
2625
0
  } else if (arch == "native") {
2626
0
    cmValue native = this->Makefile->GetDefinition(
2627
0
      cmStrCat("CMAKE_", lang, "_ARCHITECTURES_NATIVE"));
2628
0
    if (native.IsEmpty()) {
2629
0
      this->Makefile->IssueMessage(
2630
0
        MessageType::FATAL_ERROR,
2631
0
        cmStrCat(lang,
2632
0
                 "_ARCHITECTURES is set to \"native\", but no NVIDIA GPU was "
2633
0
                 "detected."));
2634
0
    }
2635
0
    if (compiler == "NVIDIA" &&
2636
0
        cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
2637
0
                                      this->Makefile->GetDefinition(cmStrCat(
2638
0
                                        "CMAKE_", lang, "_COMPILER_VERSION")),
2639
0
                                      "11.6")) {
2640
0
      flags = cmStrCat(flags, " -arch=", arch);
2641
0
      return;
2642
0
    }
2643
0
    arch = *native;
2644
0
  }
2645
2646
0
  struct CudaArchitecture
2647
0
  {
2648
0
    std::string name;
2649
0
    bool real{ true };
2650
0
    bool virtual_{ true };
2651
0
  };
2652
0
  std::vector<CudaArchitecture> architectures;
2653
2654
0
  {
2655
0
    cmList options(arch);
2656
2657
0
    for (auto& option : options) {
2658
0
      CudaArchitecture architecture;
2659
2660
      // Architecture name is up to the first specifier.
2661
0
      std::size_t pos = option.find_first_of('-');
2662
0
      architecture.name = option.substr(0, pos);
2663
2664
0
      if (pos != std::string::npos) {
2665
0
        cm::string_view specifier{ option.c_str() + pos + 1,
2666
0
                                   option.length() - pos - 1 };
2667
2668
0
        if (specifier == "real") {
2669
0
          architecture.real = true;
2670
0
          architecture.virtual_ = false;
2671
0
        } else if (specifier == "virtual") {
2672
0
          architecture.real = false;
2673
0
          architecture.virtual_ = true;
2674
0
        } else {
2675
0
          this->Makefile->IssueMessage(
2676
0
            MessageType::FATAL_ERROR,
2677
0
            "Unknown CUDA architecture specifier \"" + std::string(specifier) +
2678
0
              "\".");
2679
0
        }
2680
0
      }
2681
2682
0
      architectures.emplace_back(architecture);
2683
0
    }
2684
0
  }
2685
2686
0
  if (compiler == "NVIDIA") {
2687
0
    if (ipoEnabled && compileOrLink == cmBuildStep::Link) {
2688
0
      if (cmValue cudaIPOFlags = this->Makefile->GetDefinition(
2689
0
            cmStrCat("CMAKE_", lang, "_LINK_OPTIONS_IPO"))) {
2690
0
        flags += *cudaIPOFlags;
2691
0
      }
2692
0
    }
2693
2694
0
    for (CudaArchitecture& architecture : architectures) {
2695
0
      flags = cmStrCat(std::move(flags), " \"--generate-code=arch=compute_",
2696
0
                       architecture.name, ",code=[");
2697
2698
0
      if (architecture.virtual_) {
2699
0
        flags = cmStrCat(std::move(flags), "compute_", architecture.name);
2700
2701
0
        if (ipoEnabled || architecture.real) {
2702
0
          flags += ',';
2703
0
        }
2704
0
      }
2705
2706
0
      if (ipoEnabled) {
2707
0
        if (compileOrLink == cmBuildStep::Compile) {
2708
0
          flags = cmStrCat(std::move(flags), "lto_", architecture.name);
2709
0
        } else if (compileOrLink == cmBuildStep::Link) {
2710
0
          flags = cmStrCat(std::move(flags), "sm_", architecture.name);
2711
0
        }
2712
0
      } else if (architecture.real) {
2713
0
        flags = cmStrCat(std::move(flags), "sm_", architecture.name);
2714
0
      }
2715
2716
0
      flags += "]\"";
2717
0
    }
2718
0
  } else if (compiler == "Clang" && compileOrLink == cmBuildStep::Compile) {
2719
0
    for (CudaArchitecture& architecture : architectures) {
2720
0
      flags =
2721
0
        cmStrCat(std::move(flags), " --cuda-gpu-arch=sm_", architecture.name);
2722
2723
0
      if (!architecture.real) {
2724
0
        this->Makefile->IssueMessage(
2725
0
          MessageType::WARNING,
2726
0
          "Clang doesn't support disabling CUDA real code generation.");
2727
0
      }
2728
2729
0
      if (!architecture.virtual_) {
2730
0
        flags = cmStrCat(std::move(flags), " --no-cuda-include-ptx=sm_",
2731
0
                         architecture.name);
2732
0
      }
2733
0
    }
2734
0
  }
2735
0
}
2736
2737
void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const
2738
0
{
2739
0
  std::string const& arch = this->GetSafeProperty("ISPC_INSTRUCTION_SETS");
2740
2741
  // If ISPC_TARGET is false we don't add any architectures.
2742
0
  if (cmIsOff(arch)) {
2743
0
    return;
2744
0
  }
2745
2746
0
  std::string const& compiler =
2747
0
    this->Makefile->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID");
2748
2749
0
  if (compiler == "Intel") {
2750
0
    cmList targets(arch);
2751
0
    if (!targets.empty()) {
2752
0
      flags += cmStrCat(" --target=", cmWrap("", targets, "", ","));
2753
0
    }
2754
0
  }
2755
0
}
2756
2757
void cmGeneratorTarget::AddHIPArchitectureFlags(cmBuildStep compileOrLink,
2758
                                                std::string const& config,
2759
                                                std::string& flags) const
2760
0
{
2761
0
  std::string arch = this->GetSafeProperty("HIP_ARCHITECTURES");
2762
2763
0
  if (arch.empty()) {
2764
0
    this->Makefile->IssueMessage(
2765
0
      MessageType::FATAL_ERROR,
2766
0
      cmStrCat("HIP_ARCHITECTURES is empty for target \"", this->GetName(),
2767
0
               "\"."));
2768
0
  }
2769
2770
  // If HIP_ARCHITECTURES is false we don't add any architectures.
2771
0
  if (cmIsOff(arch)) {
2772
0
    return;
2773
0
  }
2774
2775
0
  if (this->Makefile->GetSafeDefinition("CMAKE_HIP_PLATFORM") == "nvidia") {
2776
0
    this->AddCUDAArchitectureFlagsImpl(compileOrLink, config, "HIP",
2777
0
                                       std::move(arch), flags);
2778
0
    return;
2779
0
  }
2780
2781
  // For spirv platform, chipStar handles targeting via the hip package
2782
0
  if (this->Makefile->GetSafeDefinition("CMAKE_HIP_PLATFORM") == "spirv") {
2783
0
    return;
2784
0
  }
2785
2786
0
  cmList options(arch);
2787
2788
0
  for (std::string& option : options) {
2789
0
    flags += " --offload-arch=" + option;
2790
0
  }
2791
0
}
2792
2793
void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
2794
0
{
2795
0
  std::string const& compiler =
2796
0
    this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
2797
2798
0
  if (compiler == "Clang") {
2799
    // Pass CUDA toolkit explicitly to Clang.
2800
    // Clang's searching for the system CUDA toolkit isn't very good and it's
2801
    // expected the user will explicitly pass the toolkit path.
2802
    // This also avoids Clang having to search for the toolkit on every
2803
    // invocation.
2804
0
    std::string toolkitRoot =
2805
0
      this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT");
2806
2807
0
    if (!toolkitRoot.empty()) {
2808
0
      flags += " --cuda-path=" +
2809
0
        this->LocalGenerator->ConvertToOutputFormat(toolkitRoot,
2810
0
                                                    cmOutputConverter::SHELL);
2811
0
    }
2812
0
  }
2813
0
}
2814
2815
//----------------------------------------------------------------------------
2816
std::string cmGeneratorTarget::GetFeatureSpecificLinkRuleVariable(
2817
  std::string const& var, std::string const& lang,
2818
  std::string const& config) const
2819
0
{
2820
0
  if (this->IsIPOEnabled(lang, config)) {
2821
0
    std::string varIPO = var + "_IPO";
2822
0
    if (this->Makefile->IsDefinitionSet(varIPO)) {
2823
0
      return varIPO;
2824
0
    }
2825
0
  }
2826
2827
0
  return var;
2828
0
}
2829
2830
//----------------------------------------------------------------------------
2831
std::string cmGeneratorTarget::GetCreateRuleVariable(
2832
  std::string const& lang, std::string const& config) const
2833
0
{
2834
0
  switch (this->GetType()) {
2835
0
    case cmStateEnums::STATIC_LIBRARY: {
2836
0
      std::string var = cmStrCat("CMAKE_", lang, "_CREATE_STATIC_LIBRARY");
2837
0
      return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
2838
0
    }
2839
0
    case cmStateEnums::SHARED_LIBRARY:
2840
0
      if (this->IsArchivedAIXSharedLibrary()) {
2841
0
        return cmStrCat("CMAKE_", lang, "_CREATE_SHARED_LIBRARY_ARCHIVE");
2842
0
      }
2843
0
      return cmStrCat("CMAKE_", lang, "_CREATE_SHARED_LIBRARY");
2844
0
    case cmStateEnums::MODULE_LIBRARY:
2845
0
      return cmStrCat("CMAKE_", lang, "_CREATE_SHARED_MODULE");
2846
0
    case cmStateEnums::EXECUTABLE:
2847
0
      if (this->IsExecutableWithExports()) {
2848
0
        std::string linkExeWithExports =
2849
0
          cmStrCat("CMAKE_", lang, "_LINK_EXECUTABLE_WITH_EXPORTS");
2850
0
        if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
2851
0
          return linkExeWithExports;
2852
0
        }
2853
0
      }
2854
0
      return cmStrCat("CMAKE_", lang, "_LINK_EXECUTABLE");
2855
0
    default:
2856
0
      break;
2857
0
  }
2858
0
  return {};
2859
0
}
2860
2861
//----------------------------------------------------------------------------
2862
std::string cmGeneratorTarget::GetClangTidyExportFixesDirectory(
2863
  std::string const& lang) const
2864
0
{
2865
0
  cmValue val =
2866
0
    this->GetProperty(cmStrCat(lang, "_CLANG_TIDY_EXPORT_FIXES_DIR"));
2867
0
  if (!cmNonempty(val)) {
2868
0
    return {};
2869
0
  }
2870
2871
0
  std::string path = *val;
2872
0
  if (!cmSystemTools::FileIsFullPath(path)) {
2873
0
    path =
2874
0
      cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', path);
2875
0
  }
2876
0
  return cmSystemTools::CollapseFullPath(path);
2877
0
}
2878
2879
struct CycleWatcher
2880
{
2881
  CycleWatcher(bool& flag)
2882
0
    : Flag(flag)
2883
0
  {
2884
0
    this->Flag = true;
2885
0
  }
2886
0
  ~CycleWatcher() { this->Flag = false; }
2887
  bool& Flag;
2888
};
2889
2890
cmGeneratorTarget const* cmGeneratorTarget::GetPchReuseTarget() const
2891
0
{
2892
0
  if (this->ComputingPchReuse) {
2893
    // TODO: Get the full cycle.
2894
0
    if (!this->PchReuseCycleDetected) {
2895
0
      this->Makefile->IssueMessage(
2896
0
        MessageType::FATAL_ERROR,
2897
0
        cmStrCat("Circular PCH reuse target involving '", this->GetName(),
2898
0
                 '\''));
2899
0
    }
2900
0
    this->PchReuseCycleDetected = true;
2901
0
    return nullptr;
2902
0
  }
2903
0
  CycleWatcher watch(this->ComputingPchReuse);
2904
0
  (void)watch;
2905
0
  cmValue pchReuseFrom = this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
2906
0
  if (!pchReuseFrom) {
2907
0
    return nullptr;
2908
0
  }
2909
0
  cmGeneratorTarget const* generatorTarget =
2910
0
    this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
2911
0
  if (!generatorTarget) {
2912
0
    this->Makefile->IssueMessage(
2913
0
      MessageType::FATAL_ERROR,
2914
0
      cmStrCat(
2915
0
        "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
2916
0
        R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property does not exist.)"));
2917
0
  }
2918
0
  if (this->GetProperty("PRECOMPILE_HEADERS").IsOn()) {
2919
0
    this->Makefile->IssueMessage(
2920
0
      MessageType::FATAL_ERROR,
2921
0
      cmStrCat("PRECOMPILE_HEADERS property is already set on target (\"",
2922
0
               this->GetName(), "\")\n"));
2923
0
  }
2924
2925
0
  if (generatorTarget) {
2926
0
    if (generatorTarget->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
2927
0
      this->Makefile->IssueMessage(
2928
0
        MessageType::WARNING,
2929
0
        cmStrCat(
2930
0
          "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
2931
0
          R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property has set "DISABLE_PRECOMPILE_HEADERS"; ignoring.)"));
2932
0
      return nullptr;
2933
0
    }
2934
2935
0
    if (auto const* recurseReuseTarget =
2936
0
          generatorTarget->GetPchReuseTarget()) {
2937
0
      return recurseReuseTarget;
2938
0
    }
2939
0
  }
2940
0
  return generatorTarget;
2941
0
}
2942
2943
cmGeneratorTarget* cmGeneratorTarget::GetPchReuseTarget()
2944
0
{
2945
0
  if (this->ComputingPchReuse) {
2946
    // TODO: Get the full cycle.
2947
0
    if (!this->PchReuseCycleDetected) {
2948
0
      this->Makefile->IssueMessage(
2949
0
        MessageType::FATAL_ERROR,
2950
0
        cmStrCat("Circular PCH reuse target involving '", this->GetName(),
2951
0
                 '\''));
2952
0
    }
2953
0
    this->PchReuseCycleDetected = true;
2954
0
    return nullptr;
2955
0
  }
2956
0
  CycleWatcher watch(this->ComputingPchReuse);
2957
0
  (void)watch;
2958
0
  cmValue pchReuseFrom = this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
2959
0
  if (!pchReuseFrom) {
2960
0
    return nullptr;
2961
0
  }
2962
0
  cmGeneratorTarget* generatorTarget =
2963
0
    this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
2964
0
  if (!generatorTarget) {
2965
0
    this->Makefile->IssueMessage(
2966
0
      MessageType::FATAL_ERROR,
2967
0
      cmStrCat(
2968
0
        "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
2969
0
        R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property does not exist.)"));
2970
0
  }
2971
0
  if (this->GetProperty("PRECOMPILE_HEADERS").IsOn()) {
2972
0
    this->Makefile->IssueMessage(
2973
0
      MessageType::FATAL_ERROR,
2974
0
      cmStrCat("PRECOMPILE_HEADERS property is already set on target (\"",
2975
0
               this->GetName(), "\")\n"));
2976
0
  }
2977
2978
0
  if (generatorTarget) {
2979
0
    if (generatorTarget->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
2980
0
      this->Makefile->IssueMessage(
2981
0
        MessageType::WARNING,
2982
0
        cmStrCat(
2983
0
          "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
2984
0
          R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property has set "DISABLE_PRECOMPILE_HEADERS"; ignoring.)"));
2985
0
      return nullptr;
2986
0
    }
2987
2988
0
    if (auto* recurseReuseTarget = generatorTarget->GetPchReuseTarget()) {
2989
0
      return recurseReuseTarget;
2990
0
    }
2991
0
  }
2992
0
  return generatorTarget;
2993
0
}
2994
2995
std::vector<std::string> cmGeneratorTarget::GetPchArchs(
2996
  std::string const& config, std::string const& lang) const
2997
0
{
2998
0
  std::vector<std::string> pchArchs;
2999
0
  if (!this->GetGlobalGenerator()->IsXcode()) {
3000
0
    pchArchs = this->GetAppleArchs(config, lang);
3001
0
  }
3002
0
  if (pchArchs.size() < 2) {
3003
    // We do not need per-arch PCH files when building for one architecture.
3004
0
    pchArchs = { {} };
3005
0
  }
3006
0
  return pchArchs;
3007
0
}
3008
3009
std::string cmGeneratorTarget::GetPchHeader(std::string const& config,
3010
                                            std::string const& language,
3011
                                            std::string const& arch) const
3012
0
{
3013
0
  if (language != "C" && language != "CXX" && language != "OBJC" &&
3014
0
      language != "OBJCXX") {
3015
0
    return std::string();
3016
0
  }
3017
3018
0
  if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
3019
0
    return std::string();
3020
0
  }
3021
0
  cmGeneratorTarget const* generatorTarget = this;
3022
0
  cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget();
3023
0
  bool const haveReuseTarget = reuseTarget && reuseTarget != this;
3024
0
  if (reuseTarget) {
3025
0
    generatorTarget = reuseTarget;
3026
0
  }
3027
3028
0
  auto const inserted =
3029
0
    this->PchHeaders.insert(std::make_pair(language + config + arch, ""));
3030
0
  if (inserted.second) {
3031
0
    std::vector<BT<std::string>> const headers =
3032
0
      this->GetPrecompileHeaders(config, language);
3033
0
    if (headers.empty() && !haveReuseTarget) {
3034
0
      return std::string();
3035
0
    }
3036
0
    std::string& filename = inserted.first->second;
3037
3038
0
    std::map<std::string, std::string> const languageToExtension = {
3039
0
      { "C", ".h" },
3040
0
      { "CXX", ".hxx" },
3041
0
      { "OBJC", ".objc.h" },
3042
0
      { "OBJCXX", ".objcxx.hxx" }
3043
0
    };
3044
3045
0
    filename = generatorTarget->GetCMFSupportDirectory();
3046
3047
0
    if (this->GetGlobalGenerator()->IsMultiConfig()) {
3048
0
      filename = cmStrCat(filename, '/', config);
3049
0
    }
3050
3051
    // This is acceptable as its the source file, won't have a rename/hash
3052
0
    filename =
3053
0
      cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat('_', arch),
3054
0
               languageToExtension.at(language));
3055
3056
0
    std::string const filename_tmp = cmStrCat(filename, ".tmp");
3057
0
    if (!haveReuseTarget) {
3058
0
      cmValue pchPrologue =
3059
0
        this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
3060
0
      cmValue pchEpilogue =
3061
0
        this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
3062
3063
0
      std::string firstHeaderOnDisk;
3064
0
      {
3065
0
        cmGeneratedFileStream file(
3066
0
          filename_tmp, false,
3067
0
          this->GetGlobalGenerator()->GetMakefileEncoding());
3068
0
        file << "/* generated by CMake */\n\n";
3069
0
        if (pchPrologue) {
3070
0
          file << *pchPrologue << "\n";
3071
0
        }
3072
0
        if (this->GetGlobalGenerator()->IsXcode()) {
3073
0
          file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
3074
0
        }
3075
0
        if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
3076
0
          file << "#ifdef __cplusplus\n";
3077
0
        }
3078
0
        for (auto const& header_bt : headers) {
3079
0
          if (header_bt.Value.empty()) {
3080
0
            continue;
3081
0
          }
3082
0
          if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
3083
0
            file << "#include " << header_bt.Value << "\n";
3084
0
          } else {
3085
0
            file << "#include \"" << header_bt.Value << "\"\n";
3086
0
          }
3087
3088
0
          if (cmSystemTools::FileExists(header_bt.Value) &&
3089
0
              firstHeaderOnDisk.empty()) {
3090
0
            firstHeaderOnDisk = header_bt.Value;
3091
0
          }
3092
0
        }
3093
0
        if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
3094
0
          file << "#endif // __cplusplus\n";
3095
0
        }
3096
0
        if (this->GetGlobalGenerator()->IsXcode()) {
3097
0
          file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
3098
0
        }
3099
0
        if (pchEpilogue) {
3100
0
          file << *pchEpilogue << "\n";
3101
0
        }
3102
0
      }
3103
3104
0
      if (!firstHeaderOnDisk.empty()) {
3105
0
        cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
3106
0
      }
3107
3108
0
      cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
3109
0
    }
3110
0
  }
3111
0
  return inserted.first->second;
3112
0
}
3113
3114
std::string cmGeneratorTarget::GetPchSource(std::string const& config,
3115
                                            std::string const& language,
3116
                                            std::string const& arch) const
3117
0
{
3118
0
  if (language != "C" && language != "CXX" && language != "OBJC" &&
3119
0
      language != "OBJCXX") {
3120
0
    return std::string();
3121
0
  }
3122
0
  auto const inserted =
3123
0
    this->PchSources.insert(std::make_pair(language + config + arch, ""));
3124
0
  if (inserted.second) {
3125
0
    std::string const pchHeader = this->GetPchHeader(config, language, arch);
3126
0
    if (pchHeader.empty()) {
3127
0
      return std::string();
3128
0
    }
3129
0
    std::string& filename = inserted.first->second;
3130
3131
0
    cmGeneratorTarget const* generatorTarget = this;
3132
0
    cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget();
3133
0
    bool const haveReuseTarget = reuseTarget && reuseTarget != this;
3134
0
    if (reuseTarget) {
3135
0
      generatorTarget = reuseTarget;
3136
0
    }
3137
3138
0
    filename =
3139
0
      cmStrCat(generatorTarget->GetCMFSupportDirectory(), "/cmake_pch");
3140
3141
    // For GCC the source extension will be transformed into .h[xx].gch
3142
0
    if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
3143
0
      std::map<std::string, std::string> const languageToExtension = {
3144
0
        { "C", ".h.c" },
3145
0
        { "CXX", ".hxx.cxx" },
3146
0
        { "OBJC", ".objc.h.m" },
3147
0
        { "OBJCXX", ".objcxx.hxx.mm" }
3148
0
      };
3149
3150
0
      filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat('_', arch),
3151
0
                          languageToExtension.at(language));
3152
0
    } else {
3153
0
      std::map<std::string, std::string> const languageToExtension = {
3154
0
        { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" }
3155
0
      };
3156
3157
0
      filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat('_', arch),
3158
0
                          languageToExtension.at(language));
3159
0
    }
3160
3161
0
    std::string const filename_tmp = cmStrCat(filename, ".tmp");
3162
0
    if (!haveReuseTarget) {
3163
0
      {
3164
0
        cmGeneratedFileStream file(filename_tmp);
3165
0
        file << "/* generated by CMake */\n";
3166
0
      }
3167
0
      cmFileTimes::Copy(pchHeader, filename_tmp);
3168
0
      cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
3169
0
    }
3170
0
  }
3171
0
  return inserted.first->second;
3172
0
}
3173
3174
std::string cmGeneratorTarget::GetPchFileObject(std::string const& config,
3175
                                                std::string const& language,
3176
                                                std::string const& arch)
3177
0
{
3178
0
  if (language != "C" && language != "CXX" && language != "OBJC" &&
3179
0
      language != "OBJCXX") {
3180
0
    return std::string();
3181
0
  }
3182
0
  auto const inserted =
3183
0
    this->PchObjectFiles.insert(std::make_pair(language + config + arch, ""));
3184
0
  if (inserted.second) {
3185
0
    std::string const pchSource = this->GetPchSource(config, language, arch);
3186
0
    if (pchSource.empty()) {
3187
0
      return std::string();
3188
0
    }
3189
0
    std::string& filename = inserted.first->second;
3190
3191
0
    auto* pchSf = this->Makefile->GetOrCreateSource(
3192
0
      pchSource, false, cmSourceFileLocationKind::Known);
3193
0
    pchSf->SetSpecialSourceType(cmSourceFile::SpecialSourceType::PchSource);
3194
0
    pchSf->ResolveFullPath();
3195
0
    filename = cmStrCat(this->GetObjectDirectory(config), '/',
3196
0
                        this->GetObjectName(pchSf));
3197
0
  }
3198
0
  return inserted.first->second;
3199
0
}
3200
3201
std::string cmGeneratorTarget::GetPchFile(std::string const& config,
3202
                                          std::string const& language,
3203
                                          std::string const& arch)
3204
0
{
3205
0
  auto const inserted =
3206
0
    this->PchFiles.insert(std::make_pair(language + config + arch, ""));
3207
0
  if (inserted.second) {
3208
0
    std::string& pchFile = inserted.first->second;
3209
3210
0
    std::string const pchExtension =
3211
0
      this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
3212
3213
0
    if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
3214
0
      auto replaceExtension = [](std::string const& str,
3215
0
                                 std::string const& ext) -> std::string {
3216
0
        auto dot_pos = str.rfind('.');
3217
0
        std::string result;
3218
0
        if (dot_pos != std::string::npos) {
3219
0
          result = str.substr(0, dot_pos);
3220
0
        }
3221
0
        result += ext;
3222
0
        return result;
3223
0
      };
3224
3225
0
      cmGeneratorTarget* generatorTarget = this;
3226
0
      cmGeneratorTarget* reuseTarget = this->GetPchReuseTarget();
3227
0
      if (reuseTarget) {
3228
0
        generatorTarget = reuseTarget;
3229
0
      }
3230
3231
0
      std::string const pchFileObject =
3232
0
        generatorTarget->GetPchFileObject(config, language, arch);
3233
0
      if (!pchExtension.empty()) {
3234
0
        pchFile = replaceExtension(pchFileObject, pchExtension);
3235
0
      }
3236
0
    } else {
3237
0
      if (this->GetUseShortObjectNames() && !pchExtension.empty()) {
3238
0
        auto pchSource = this->GetPchSource(config, language, arch);
3239
0
        auto* pchSf = this->Makefile->GetOrCreateSource(
3240
0
          pchSource, false, cmSourceFileLocationKind::Known);
3241
0
        pchSf->SetSpecialSourceType(
3242
0
          cmSourceFile::SpecialSourceType::PchSource);
3243
0
        pchSf->ResolveFullPath();
3244
0
        std::string cfgSubdir;
3245
0
        if (this->GetGlobalGenerator()->IsMultiConfig()) {
3246
0
          cfgSubdir = cmStrCat(config, '/');
3247
0
        }
3248
0
        pchFile = cmStrCat(
3249
0
          this->GetSupportDirectory(), '/', cfgSubdir,
3250
0
          this->LocalGenerator->GetShortObjectFileName(*pchSf), pchExtension);
3251
0
      } else {
3252
0
        pchFile =
3253
0
          cmStrCat(this->GetPchHeader(config, language, arch), pchExtension);
3254
0
      }
3255
0
    }
3256
0
  }
3257
0
  return inserted.first->second;
3258
0
}
3259
3260
std::string cmGeneratorTarget::GetPchCreateCompileOptions(
3261
  std::string const& config, std::string const& language,
3262
  std::string const& arch)
3263
0
{
3264
0
  auto const inserted = this->PchCreateCompileOptions.insert(
3265
0
    std::make_pair(language + config + arch, ""));
3266
0
  if (inserted.second) {
3267
0
    std::string& createOptionList = inserted.first->second;
3268
3269
0
    if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
3270
0
      createOptionList = this->Makefile->GetSafeDefinition(
3271
0
        cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
3272
0
    }
3273
3274
0
    if (this->GetPropertyAsBool("PCH_INSTANTIATE_TEMPLATES")) {
3275
0
      std::string varName = cmStrCat(
3276
0
        "CMAKE_", language, "_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH");
3277
0
      std::string instantiateOption =
3278
0
        this->Makefile->GetSafeDefinition(varName);
3279
0
      if (!instantiateOption.empty()) {
3280
0
        createOptionList = cmStrCat(createOptionList, ';', instantiateOption);
3281
0
      }
3282
0
    }
3283
3284
0
    std::string const createOptVar =
3285
0
      cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH");
3286
3287
0
    createOptionList = cmStrCat(
3288
0
      createOptionList, ';', this->Makefile->GetSafeDefinition(createOptVar));
3289
3290
0
    std::string const pchHeader = this->GetPchHeader(config, language, arch);
3291
0
    std::string const pchFile = this->GetPchFile(config, language, arch);
3292
3293
0
    if (GlobalGenerator->IsFastbuild()) {
3294
      // Account for potential spaces in a shell-friendly way.
3295
0
      cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>",
3296
0
                                   cmStrCat('"', pchHeader, '"'));
3297
0
      cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>",
3298
0
                                   cmStrCat('"', pchFile, '"'));
3299
0
    } else {
3300
0
      cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>",
3301
0
                                   pchHeader);
3302
0
      cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile);
3303
0
    }
3304
0
  }
3305
0
  return inserted.first->second;
3306
0
}
3307
3308
std::string cmGeneratorTarget::GetPchUseCompileOptions(
3309
  std::string const& config, std::string const& language,
3310
  std::string const& arch)
3311
0
{
3312
0
  auto const inserted = this->PchUseCompileOptions.insert(
3313
0
    std::make_pair(language + config + arch, ""));
3314
0
  if (inserted.second) {
3315
0
    std::string& useOptionList = inserted.first->second;
3316
3317
0
    if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
3318
0
      useOptionList = this->Makefile->GetSafeDefinition(
3319
0
        cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
3320
0
    }
3321
3322
0
    std::string const useOptVar =
3323
0
      cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH");
3324
3325
0
    std::string const& useOptionListProperty =
3326
0
      this->GetSafeProperty(useOptVar);
3327
3328
0
    useOptionList = cmStrCat(
3329
0
      useOptionList, ';',
3330
0
      useOptionListProperty.empty()
3331
0
        ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar))
3332
0
        : useOptionListProperty);
3333
3334
0
    std::string const pchHeader = this->GetPchHeader(config, language, arch);
3335
0
    std::string const pchFile = this->GetPchFile(config, language, arch);
3336
3337
0
    if (GlobalGenerator->IsFastbuild()) {
3338
      // Account for potential spaces in a shell-friendly way.
3339
0
      cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>",
3340
0
                                   cmStrCat('"', pchHeader, '"'));
3341
0
      cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>",
3342
0
                                   cmStrCat('"', pchFile, '"'));
3343
0
    } else {
3344
0
      cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader);
3345
0
      cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile);
3346
0
    }
3347
0
  }
3348
0
  return inserted.first->second;
3349
0
}
3350
3351
void cmGeneratorTarget::AddSourceFileToUnityBatch(
3352
  std::string const& sourceFilename)
3353
0
{
3354
0
  this->UnityBatchedSourceFiles.insert(sourceFilename);
3355
0
}
3356
3357
bool cmGeneratorTarget::IsSourceFilePartOfUnityBatch(
3358
  std::string const& sourceFilename) const
3359
0
{
3360
0
  if (!this->GetPropertyAsBool("UNITY_BUILD")) {
3361
0
    return false;
3362
0
  }
3363
3364
0
  return this->UnityBatchedSourceFiles.find(sourceFilename) !=
3365
0
    this->UnityBatchedSourceFiles.end();
3366
0
}
3367
3368
void cmGeneratorTarget::ComputeTargetManifest(std::string const& config) const
3369
0
{
3370
0
  if (this->IsImported()) {
3371
0
    return;
3372
0
  }
3373
0
  cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
3374
3375
  // Get the names.
3376
0
  cmGeneratorTarget::Names targetNames;
3377
0
  if (this->GetType() == cmStateEnums::EXECUTABLE) {
3378
0
    targetNames = this->GetExecutableNames(config);
3379
0
  } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
3380
0
             this->GetType() == cmStateEnums::SHARED_LIBRARY ||
3381
0
             this->GetType() == cmStateEnums::MODULE_LIBRARY) {
3382
0
    targetNames = this->GetLibraryNames(config);
3383
0
  } else {
3384
0
    return;
3385
0
  }
3386
3387
  // Get the directory.
3388
0
  std::string dir =
3389
0
    this->GetDirectory(config, cmStateEnums::RuntimeBinaryArtifact);
3390
3391
  // Add each name.
3392
0
  std::string f;
3393
0
  if (!targetNames.Output.empty()) {
3394
0
    f = cmStrCat(dir, '/', targetNames.Output);
3395
0
    gg->AddToManifest(f);
3396
0
  }
3397
0
  if (!targetNames.SharedObject.empty()) {
3398
0
    f = cmStrCat(dir, '/', targetNames.SharedObject);
3399
0
    gg->AddToManifest(f);
3400
0
  }
3401
0
  if (!targetNames.Real.empty()) {
3402
0
    f = cmStrCat(dir, '/', targetNames.Real);
3403
0
    gg->AddToManifest(f);
3404
0
  }
3405
0
  if (!targetNames.PDB.empty()) {
3406
0
    f = cmStrCat(dir, '/', targetNames.PDB);
3407
0
    gg->AddToManifest(f);
3408
0
  }
3409
3410
0
  dir = this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
3411
0
  if (!targetNames.ImportOutput.empty()) {
3412
0
    f = cmStrCat(dir, '/', targetNames.ImportOutput);
3413
0
    gg->AddToManifest(f);
3414
0
  }
3415
0
  if (!targetNames.ImportLibrary.empty()) {
3416
0
    f = cmStrCat(dir, '/', targetNames.ImportLibrary);
3417
0
    gg->AddToManifest(f);
3418
0
  }
3419
0
  if (!targetNames.ImportReal.empty()) {
3420
0
    f = cmStrCat(dir, '/', targetNames.ImportReal);
3421
0
    gg->AddToManifest(f);
3422
0
  }
3423
0
}
3424
3425
cm::optional<cmStandardLevel> cmGeneratorTarget::GetExplicitStandardLevel(
3426
  std::string const& lang, std::string const& config) const
3427
0
{
3428
0
  cm::optional<cmStandardLevel> level;
3429
0
  std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
3430
0
  auto i = this->ExplicitStandardLevel.find(key);
3431
0
  if (i != this->ExplicitStandardLevel.end()) {
3432
0
    level = i->second;
3433
0
  }
3434
0
  return level;
3435
0
}
3436
3437
void cmGeneratorTarget::UpdateExplicitStandardLevel(std::string const& lang,
3438
                                                    std::string const& config,
3439
                                                    cmStandardLevel level)
3440
0
{
3441
0
  auto e = this->ExplicitStandardLevel.emplace(
3442
0
    cmStrCat(cmSystemTools::UpperCase(config), '-', lang), level);
3443
0
  if (!e.second && e.first->second < level) {
3444
0
    e.first->second = level;
3445
0
  }
3446
0
}
3447
3448
bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config)
3449
0
{
3450
0
  cmStandardLevelResolver standardResolver(this->Makefile);
3451
3452
0
  for (std::string const& lang :
3453
0
       this->Makefile->GetState()->GetEnabledLanguages()) {
3454
0
    if (cmValue languageStd = this->GetLanguageStandard(lang, config)) {
3455
0
      if (cm::optional<cmStandardLevel> langLevel =
3456
0
            standardResolver.LanguageStandardLevel(lang, *languageStd)) {
3457
0
        this->UpdateExplicitStandardLevel(lang, config, *langLevel);
3458
0
      }
3459
0
    }
3460
0
  }
3461
3462
  // Compute the language standard based on the compile features.
3463
0
  std::vector<BT<std::string>> features = this->GetCompileFeatures(config);
3464
0
  for (BT<std::string> const& f : features) {
3465
0
    std::string lang;
3466
0
    if (!standardResolver.CompileFeatureKnown(this->Target->GetName(), f.Value,
3467
0
                                              lang, nullptr)) {
3468
0
      return false;
3469
0
    }
3470
3471
0
    std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
3472
0
    cmValue currentLanguageStandard = this->GetLanguageStandard(lang, config);
3473
3474
0
    cm::optional<cmStandardLevel> featureLevel;
3475
0
    std::string newRequiredStandard;
3476
0
    if (!standardResolver.GetNewRequiredStandard(
3477
0
          this->Target->GetName(), f.Value, currentLanguageStandard,
3478
0
          featureLevel, newRequiredStandard)) {
3479
0
      return false;
3480
0
    }
3481
3482
0
    if (featureLevel) {
3483
0
      this->UpdateExplicitStandardLevel(lang, config, *featureLevel);
3484
0
    }
3485
3486
0
    if (!newRequiredStandard.empty()) {
3487
0
      BTs<std::string>& languageStandardProperty =
3488
0
        this->LanguageStandardMap[key];
3489
0
      if (languageStandardProperty.Value != newRequiredStandard) {
3490
0
        languageStandardProperty.Value = newRequiredStandard;
3491
0
        languageStandardProperty.Backtraces.clear();
3492
0
      }
3493
0
      languageStandardProperty.Backtraces.emplace_back(f.Backtrace);
3494
0
    }
3495
0
  }
3496
3497
0
  return true;
3498
0
}
3499
3500
bool cmGeneratorTarget::ComputeCompileFeatures(
3501
  std::string const& config, std::set<LanguagePair> const& languagePairs)
3502
0
{
3503
0
  for (auto const& language : languagePairs) {
3504
0
    BTs<std::string> const* generatorTargetLanguageStandard =
3505
0
      this->GetLanguageStandardProperty(language.first, config);
3506
0
    if (!generatorTargetLanguageStandard) {
3507
      // If the standard isn't explicitly set we copy it over from the
3508
      // specified paired language.
3509
0
      std::string key =
3510
0
        cmStrCat(cmSystemTools::UpperCase(config), '-', language.first);
3511
0
      BTs<std::string> const* standardToCopy =
3512
0
        this->GetLanguageStandardProperty(language.second, config);
3513
0
      if (standardToCopy) {
3514
0
        this->LanguageStandardMap[key] = *standardToCopy;
3515
0
        generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
3516
0
      } else {
3517
0
        cmValue defaultStandard = this->Makefile->GetDefinition(
3518
0
          cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT"));
3519
0
        if (defaultStandard) {
3520
0
          this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard);
3521
0
          generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
3522
0
        }
3523
0
      }
3524
3525
      // Custom updates for the CUDA standard.
3526
0
      if (generatorTargetLanguageStandard && (language.first == "CUDA")) {
3527
0
        if (generatorTargetLanguageStandard->Value == "98") {
3528
0
          this->LanguageStandardMap[key].Value = "03";
3529
0
        }
3530
0
      }
3531
0
    }
3532
0
  }
3533
3534
0
  return true;
3535
0
}
3536
3537
std::string cmGeneratorTarget::GetImportedLibName(
3538
  std::string const& config) const
3539
0
{
3540
0
  if (cmGeneratorTarget::ImportInfo const* info =
3541
0
        this->GetImportInfo(config)) {
3542
0
    return info->LibName;
3543
0
  }
3544
0
  return std::string();
3545
0
}
3546
3547
std::string cmGeneratorTarget::GetFullPath(std::string const& config,
3548
                                           cmStateEnums::ArtifactType artifact,
3549
                                           bool realname) const
3550
0
{
3551
0
  if (this->IsImported()) {
3552
0
    return this->Target->ImportedGetFullPath(config, artifact);
3553
0
  }
3554
0
  return this->NormalGetFullPath(config, artifact, realname);
3555
0
}
3556
3557
std::string cmGeneratorTarget::NormalGetFullPath(
3558
  std::string const& config, cmStateEnums::ArtifactType artifact,
3559
  bool realname) const
3560
0
{
3561
0
  std::string fpath = cmStrCat(this->GetDirectory(config, artifact), '/');
3562
0
  if (this->IsAppBundleOnApple()) {
3563
0
    fpath =
3564
0
      cmStrCat(this->BuildBundleDirectory(fpath, config, FullLevel), '/');
3565
0
  }
3566
3567
  // Add the full name of the target.
3568
0
  switch (artifact) {
3569
0
    case cmStateEnums::RuntimeBinaryArtifact:
3570
0
      if (realname) {
3571
0
        fpath += this->NormalGetRealName(config);
3572
0
      } else {
3573
0
        fpath +=
3574
0
          this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact);
3575
0
      }
3576
0
      break;
3577
0
    case cmStateEnums::ImportLibraryArtifact:
3578
0
      if (realname) {
3579
0
        fpath +=
3580
0
          this->NormalGetRealName(config, cmStateEnums::ImportLibraryArtifact);
3581
0
      } else {
3582
0
        fpath +=
3583
0
          this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
3584
0
      }
3585
0
      break;
3586
0
  }
3587
0
  return fpath;
3588
0
}
3589
3590
std::string cmGeneratorTarget::NormalGetRealName(
3591
  std::string const& config, cmStateEnums::ArtifactType artifact) const
3592
0
{
3593
  // This should not be called for imported targets.
3594
  // TODO: Split cmTarget into a class hierarchy to get compile-time
3595
  // enforcement of the limited imported target API.
3596
0
  if (this->IsImported()) {
3597
0
    std::string msg = cmStrCat("NormalGetRealName called on imported target: ",
3598
0
                               this->GetName());
3599
0
    this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
3600
0
  }
3601
3602
0
  Names names = this->GetType() == cmStateEnums::EXECUTABLE
3603
0
    ? this->GetExecutableNames(config)
3604
0
    : this->GetLibraryNames(config);
3605
3606
  // Compute the real name that will be built.
3607
0
  return artifact == cmStateEnums::RuntimeBinaryArtifact ? names.Real
3608
0
                                                         : names.ImportReal;
3609
0
}
3610
3611
cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
3612
  std::string const& config) const
3613
0
{
3614
0
  cmGeneratorTarget::Names targetNames;
3615
3616
  // This should not be called for imported targets.
3617
  // TODO: Split cmTarget into a class hierarchy to get compile-time
3618
  // enforcement of the limited imported target API.
3619
0
  if (this->IsImported()) {
3620
0
    std::string msg =
3621
0
      cmStrCat("GetLibraryNames called on imported target: ", this->GetName());
3622
0
    this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
3623
0
  }
3624
3625
  // Check for library version properties.
3626
0
  cmValue version = this->GetProperty("VERSION");
3627
0
  cmValue soversion = this->GetProperty("SOVERSION");
3628
0
  if (!this->HasSOName(config) ||
3629
0
      this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
3630
0
      this->IsFrameworkOnApple()) {
3631
    // Versioning is supported only for shared libraries and modules,
3632
    // and then only when the platform supports an soname flag.
3633
0
    version = nullptr;
3634
0
    soversion = nullptr;
3635
0
  }
3636
0
  if (version && !soversion) {
3637
    // The soversion must be set if the library version is set.  Use
3638
    // the library version as the soversion.
3639
0
    soversion = version;
3640
0
  }
3641
0
  if (!version && soversion) {
3642
    // Use the soversion as the library version.
3643
0
    version = soversion;
3644
0
  }
3645
3646
  // Get the components of the library name.
3647
0
  NameComponents const& components = this->GetFullNameInternalComponents(
3648
0
    config, cmStateEnums::RuntimeBinaryArtifact);
3649
3650
  // The library name.
3651
0
  targetNames.Base = components.base;
3652
0
  targetNames.Output =
3653
0
    cmStrCat(components.prefix, targetNames.Base, components.suffix);
3654
3655
0
  if (this->IsFrameworkOnApple()) {
3656
0
    targetNames.Real = components.prefix;
3657
0
    if (!this->Makefile->PlatformIsAppleEmbedded()) {
3658
0
      targetNames.Real +=
3659
0
        cmStrCat("Versions/", this->GetFrameworkVersion(), '/');
3660
0
    }
3661
0
    targetNames.Real += cmStrCat(targetNames.Base, components.suffix);
3662
0
    targetNames.SharedObject = targetNames.Real;
3663
0
  } else if (this->IsArchivedAIXSharedLibrary()) {
3664
0
    targetNames.SharedObject =
3665
0
      cmStrCat(components.prefix, targetNames.Base, ".so");
3666
0
    if (soversion) {
3667
0
      targetNames.SharedObject += ".";
3668
0
      targetNames.SharedObject += *soversion;
3669
0
    }
3670
0
    targetNames.Real = targetNames.Output;
3671
0
  } else {
3672
    // The library's soname.
3673
0
    targetNames.SharedObject = this->ComputeVersionedName(
3674
0
      components.prefix, targetNames.Base, components.suffix,
3675
0
      targetNames.Output, soversion);
3676
3677
    // The library's real name on disk.
3678
0
    targetNames.Real = this->ComputeVersionedName(
3679
0
      components.prefix, targetNames.Base, components.suffix,
3680
0
      targetNames.Output, version);
3681
0
  }
3682
3683
  // The import library names.
3684
0
  if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
3685
0
      this->GetType() == cmStateEnums::MODULE_LIBRARY) {
3686
0
    NameComponents const& importComponents =
3687
0
      this->GetFullNameInternalComponents(config,
3688
0
                                          cmStateEnums::ImportLibraryArtifact);
3689
0
    targetNames.ImportOutput = cmStrCat(
3690
0
      importComponents.prefix, importComponents.base, importComponents.suffix);
3691
3692
0
    if (this->IsFrameworkOnApple() && this->IsSharedLibraryWithExports()) {
3693
0
      targetNames.ImportReal = components.prefix;
3694
0
      if (!this->Makefile->PlatformIsAppleEmbedded()) {
3695
0
        targetNames.ImportReal +=
3696
0
          cmStrCat("Versions/", this->GetFrameworkVersion(), '/');
3697
0
      }
3698
0
      targetNames.ImportReal +=
3699
0
        cmStrCat(importComponents.base, importComponents.suffix);
3700
0
      targetNames.ImportLibrary = targetNames.ImportOutput;
3701
0
    } else {
3702
      // The import library's soname.
3703
0
      targetNames.ImportLibrary = this->ComputeVersionedName(
3704
0
        importComponents.prefix, importComponents.base,
3705
0
        importComponents.suffix, targetNames.ImportOutput, soversion);
3706
3707
      // The import library's real name on disk.
3708
0
      targetNames.ImportReal = this->ComputeVersionedName(
3709
0
        importComponents.prefix, importComponents.base,
3710
0
        importComponents.suffix, targetNames.ImportOutput, version);
3711
0
    }
3712
0
  }
3713
3714
  // The program database file name.
3715
0
  targetNames.PDB = this->GetPDBName(config);
3716
3717
0
  return targetNames;
3718
0
}
3719
3720
cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
3721
  std::string const& config) const
3722
0
{
3723
0
  cmGeneratorTarget::Names targetNames;
3724
3725
  // This should not be called for imported targets.
3726
  // TODO: Split cmTarget into a class hierarchy to get compile-time
3727
  // enforcement of the limited imported target API.
3728
0
  if (this->IsImported()) {
3729
0
    std::string msg = cmStrCat(
3730
0
      "GetExecutableNames called on imported target: ", this->GetName());
3731
0
    this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
3732
0
  }
3733
3734
// This versioning is supported only for executables and then only
3735
// when the platform supports symbolic links.
3736
#if defined(_WIN32) && !defined(__CYGWIN__)
3737
  cmValue version;
3738
#else
3739
  // Check for executable version properties.
3740
0
  cmValue version = this->GetProperty("VERSION");
3741
0
  if (this->GetType() != cmStateEnums::EXECUTABLE ||
3742
0
      this->Makefile->IsOn("XCODE")) {
3743
0
    version = nullptr;
3744
0
  }
3745
0
#endif
3746
3747
  // Get the components of the executable name.
3748
0
  NameComponents const& components = this->GetFullNameInternalComponents(
3749
0
    config, cmStateEnums::RuntimeBinaryArtifact);
3750
3751
  // The executable name.
3752
0
  targetNames.Base = components.base;
3753
3754
0
  if (this->IsArchivedAIXSharedLibrary()) {
3755
0
    targetNames.Output = components.prefix + targetNames.Base;
3756
0
  } else {
3757
0
    targetNames.Output =
3758
0
      components.prefix + targetNames.Base + components.suffix;
3759
0
  }
3760
3761
// The executable's real name on disk.
3762
#if defined(__CYGWIN__)
3763
  targetNames.Real = components.prefix + targetNames.Base;
3764
#else
3765
0
  targetNames.Real = targetNames.Output;
3766
0
#endif
3767
0
  if (version) {
3768
0
    targetNames.Real += "-";
3769
0
    targetNames.Real += *version;
3770
0
  }
3771
#if defined(__CYGWIN__)
3772
  targetNames.Real += components.suffix;
3773
#endif
3774
3775
  // The import library name.
3776
0
  targetNames.ImportLibrary =
3777
0
    this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
3778
0
  targetNames.ImportReal = targetNames.ImportLibrary;
3779
0
  targetNames.ImportOutput = targetNames.ImportLibrary;
3780
3781
  // The program database file name.
3782
0
  targetNames.PDB = this->GetPDBName(config);
3783
3784
0
  return targetNames;
3785
0
}
3786
3787
std::string cmGeneratorTarget::GetFullNameInternal(
3788
  std::string const& config, cmStateEnums::ArtifactType artifact) const
3789
0
{
3790
0
  NameComponents const& components =
3791
0
    this->GetFullNameInternalComponents(config, artifact);
3792
0
  return components.prefix + components.base + components.suffix;
3793
0
}
3794
3795
std::string cmGeneratorTarget::ImportedGetLocation(
3796
  std::string const& config) const
3797
0
{
3798
0
  assert(this->IsImported());
3799
0
  return this->Target->ImportedGetFullPath(
3800
0
    config, cmStateEnums::RuntimeBinaryArtifact);
3801
0
}
3802
3803
std::string cmGeneratorTarget::GetFullNameImported(
3804
  std::string const& config, cmStateEnums::ArtifactType artifact) const
3805
0
{
3806
0
  return cmSystemTools::GetFilenameName(
3807
0
    this->Target->ImportedGetFullPath(config, artifact));
3808
0
}
3809
3810
cmGeneratorTarget::NameComponents const&
3811
cmGeneratorTarget::GetFullNameInternalComponents(
3812
  std::string const& config, cmStateEnums::ArtifactType artifact) const
3813
0
{
3814
0
  assert(artifact == cmStateEnums::RuntimeBinaryArtifact ||
3815
0
         artifact == cmStateEnums::ImportLibraryArtifact);
3816
0
  FullNameCache& cache = artifact == cmStateEnums::RuntimeBinaryArtifact
3817
0
    ? RuntimeBinaryFullNameCache
3818
0
    : ImportLibraryFullNameCache;
3819
0
  auto search = cache.find(config);
3820
0
  if (search != cache.end()) {
3821
0
    return search->second;
3822
0
  }
3823
  // Use just the target name for non-main target types.
3824
0
  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
3825
0
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
3826
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
3827
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
3828
0
    NameComponents components;
3829
0
    components.base = this->GetName();
3830
0
    return cache.emplace(config, std::move(components)).first->second;
3831
0
  }
3832
3833
0
  bool const isImportedLibraryArtifact =
3834
0
    (artifact == cmStateEnums::ImportLibraryArtifact);
3835
3836
  // Return an empty name for the import library if this platform
3837
  // does not support import libraries.
3838
0
  if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
3839
0
    return cache.emplace(config, NameComponents()).first->second;
3840
0
  }
3841
3842
0
  NameComponents parts;
3843
0
  std::string& outPrefix = parts.prefix;
3844
0
  std::string& outBase = parts.base;
3845
0
  std::string& outSuffix = parts.suffix;
3846
3847
  // retrieve prefix and suffix
3848
0
  std::string ll = this->GetLinkerLanguage(config);
3849
0
  cmValue targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
3850
0
  cmValue targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
3851
3852
  // The implib option is only allowed for shared libraries, module
3853
  // libraries, and executables.
3854
0
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
3855
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
3856
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
3857
0
    artifact = cmStateEnums::RuntimeBinaryArtifact;
3858
0
  }
3859
3860
  // Compute the full name for main target types.
3861
0
  std::string configPostfix = this->GetFilePostfix(config);
3862
3863
  // frameworks have directory prefix
3864
0
  std::string fw_prefix;
3865
0
  if (this->IsFrameworkOnApple()) {
3866
0
    fw_prefix =
3867
0
      cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
3868
0
    targetPrefix = cmValue(fw_prefix);
3869
0
    if (!isImportedLibraryArtifact) {
3870
      // no suffix
3871
0
      targetSuffix = nullptr;
3872
0
    }
3873
0
  }
3874
3875
0
  if (this->IsCFBundleOnApple()) {
3876
0
    fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
3877
0
    targetPrefix = cmValue(fw_prefix);
3878
0
    targetSuffix = nullptr;
3879
0
  }
3880
3881
  // Begin the final name with the prefix.
3882
0
  outPrefix = targetPrefix ? *targetPrefix : "";
3883
3884
  // Append the target name or property-specified name.
3885
0
  outBase += this->GetOutputName(config, artifact);
3886
3887
  // Append the per-configuration postfix.
3888
  // When using Xcode, the postfix should be part of the suffix rather than
3889
  // the base, because the suffix ends up being used in Xcode's
3890
  // EXECUTABLE_SUFFIX attribute.
3891
0
  if (this->IsFrameworkOnApple() && this->GetGlobalGenerator()->IsXcode()) {
3892
0
    configPostfix += *targetSuffix;
3893
0
    targetSuffix = cmValue(configPostfix);
3894
0
  } else {
3895
0
    outBase += configPostfix;
3896
0
  }
3897
3898
  // Name shared libraries with their version number on some platforms.
3899
0
  if (cmValue soversion = this->GetProperty("SOVERSION")) {
3900
0
    cmValue dllProp;
3901
0
    if (this->IsDLLPlatform()) {
3902
0
      dllProp = this->GetProperty("DLL_NAME_WITH_SOVERSION");
3903
0
    }
3904
0
    if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
3905
0
        !isImportedLibraryArtifact &&
3906
0
        (dllProp.IsOn() ||
3907
0
         (!dllProp.IsSet() &&
3908
0
          this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")))) {
3909
0
      outBase += "-";
3910
0
      outBase += *soversion;
3911
0
    }
3912
0
  }
3913
3914
  // Append the suffix.
3915
0
  outSuffix = targetSuffix ? *targetSuffix : "";
3916
3917
0
  return cache.emplace(config, std::move(parts)).first->second;
3918
0
}
3919
3920
std::string cmGeneratorTarget::GetLinkerLanguage(
3921
  std::string const& config) const
3922
0
{
3923
0
  return this->GetLinkClosure(config)->LinkerLanguage;
3924
0
}
3925
3926
std::string cmGeneratorTarget::GetLinkerTool(std::string const& config) const
3927
0
{
3928
0
  return this->GetLinkerTool(this->GetLinkerLanguage(config), config);
3929
0
}
3930
3931
std::string cmGeneratorTarget::GetLinkerTool(std::string const& lang,
3932
                                             std::string const& config) const
3933
0
{
3934
0
  auto linkMode = cmStrCat(
3935
0
    "CMAKE_", lang, this->IsDeviceLink() ? "_DEVICE_" : "_", "LINK_MODE");
3936
0
  auto mode = this->Makefile->GetDefinition(linkMode);
3937
0
  if (!mode || mode != "LINKER"_s) {
3938
0
    return this->Makefile->GetDefinition("CMAKE_LINKER");
3939
0
  }
3940
3941
0
  auto linkerType = this->GetLinkerTypeProperty(lang, config);
3942
0
  if (linkerType.empty()) {
3943
0
    linkerType = "DEFAULT";
3944
0
  }
3945
0
  auto usingLinker =
3946
0
    cmStrCat("CMAKE_", lang, "_USING_", this->IsDeviceLink() ? "DEVICE_" : "",
3947
0
             "LINKER_", linkerType);
3948
0
  auto linkerTool = this->Makefile->GetDefinition(usingLinker);
3949
3950
0
  if (!linkerTool) {
3951
0
    if (this->GetGlobalGenerator()->IsVisualStudio() &&
3952
0
        linkerType == "DEFAULT"_s) {
3953
0
      return std::string{};
3954
0
    }
3955
3956
    // fall-back to generic definition
3957
0
    linkerTool = this->Makefile->GetDefinition("CMAKE_LINKER");
3958
3959
0
    if (linkerType != "DEFAULT"_s) {
3960
0
      auto isCMakeLinkerType = [](std::string const& type) -> bool {
3961
0
        return std::all_of(type.cbegin(), type.cend(), cmsysString_isupper);
3962
0
      };
3963
0
      if (isCMakeLinkerType(linkerType)) {
3964
0
        this->LocalGenerator->IssueMessage(
3965
0
          MessageType::FATAL_ERROR,
3966
0
          cmStrCat("LINKER_TYPE '", linkerType,
3967
0
                   "' is unknown or not supported by this toolchain."));
3968
0
      } else {
3969
0
        this->LocalGenerator->IssueMessage(
3970
0
          MessageType::FATAL_ERROR,
3971
0
          cmStrCat("LINKER_TYPE '", linkerType,
3972
0
                   "' is unknown. Did you forget to define the '", usingLinker,
3973
0
                   "' variable?"));
3974
0
      }
3975
0
    }
3976
0
  }
3977
3978
0
  return linkerTool;
3979
0
}
3980
3981
bool cmGeneratorTarget::LinkerEnforcesNoAllowShLibUndefined(
3982
  std::string const& config) const
3983
0
{
3984
  // FIXME(#25486): Account for the LINKER_TYPE target property.
3985
  // Also factor out the hard-coded list below into a platform
3986
  // information table based on the linker id.
3987
0
  std::string ll = this->GetLinkerLanguage(config);
3988
0
  std::string linkerIdVar = cmStrCat("CMAKE_", ll, "_COMPILER_LINKER_ID");
3989
0
  cmValue linkerId = this->Makefile->GetDefinition(linkerIdVar);
3990
  // The GNU bfd-based linker may enforce '--no-allow-shlib-undefined'
3991
  // recursively by default.  The Solaris linker has similar behavior.
3992
0
  return linkerId && (*linkerId == "GNU" || *linkerId == "Solaris");
3993
0
}
3994
3995
std::string cmGeneratorTarget::GetPDBOutputName(
3996
  std::string const& config) const
3997
0
{
3998
  // Lookup/compute/cache the pdb output name for this configuration.
3999
0
  auto i = this->PdbOutputNameMap.find(config);
4000
0
  if (i == this->PdbOutputNameMap.end()) {
4001
    // Add empty name in map to detect potential recursion.
4002
0
    PdbOutputNameMapType::value_type entry(config, "");
4003
0
    i = this->PdbOutputNameMap.insert(entry).first;
4004
4005
    // Compute output name.
4006
0
    std::vector<std::string> props;
4007
0
    std::string configUpper = cmSystemTools::UpperCase(config);
4008
0
    if (!configUpper.empty()) {
4009
      // PDB_NAME_<CONFIG>
4010
0
      props.push_back("PDB_NAME_" + configUpper);
4011
0
    }
4012
4013
    // PDB_NAME
4014
0
    props.emplace_back("PDB_NAME");
4015
4016
0
    std::string outName;
4017
0
    for (std::string const& p : props) {
4018
0
      if (cmValue outNameProp = this->GetProperty(p)) {
4019
0
        outName = *outNameProp;
4020
0
        break;
4021
0
      }
4022
0
    }
4023
4024
    // Now evaluate genex and update the previously-prepared map entry.
4025
0
    if (outName.empty()) {
4026
0
      i->second = cmStrCat(
4027
0
        this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact),
4028
0
        this->GetPolicyStatusCMP0202() != cmPolicies::NEW
4029
0
          ? this->GetFilePostfix(config)
4030
0
          : "");
4031
0
    } else {
4032
0
      i->second =
4033
0
        cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
4034
0
    }
4035
0
  } else if (i->second.empty()) {
4036
    // An empty map entry indicates we have been called recursively
4037
    // from the above block.
4038
0
    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
4039
0
      MessageType::FATAL_ERROR,
4040
0
      cmStrCat("Target '", this->GetName(), "' PDB_NAME depends on itself."),
4041
0
      this->GetBacktrace());
4042
0
  }
4043
0
  return i->second;
4044
0
}
4045
4046
std::string cmGeneratorTarget::GetPDBName(std::string const& config) const
4047
0
{
4048
0
  NameComponents const& parts = this->GetFullNameInternalComponents(
4049
0
    config, cmStateEnums::RuntimeBinaryArtifact);
4050
4051
0
  std::string base = this->GetPDBOutputName(config);
4052
4053
0
  return cmStrCat(parts.prefix, base,
4054
0
                  this->GetPolicyStatusCMP0202() == cmPolicies::NEW
4055
0
                    ? this->GetFilePostfix(config)
4056
0
                    : "",
4057
0
                  ".pdb");
4058
0
}
4059
4060
std::string cmGeneratorTarget::GetObjectDirectory(
4061
  std::string const& config) const
4062
0
{
4063
0
  std::string obj_dir =
4064
0
    this->GlobalGenerator->ExpandCFGIntDir(this->ObjectDirectory, config);
4065
#if defined(__APPLE__)
4066
  // Replace Xcode's placeholder for the object file directory since
4067
  // installation and export scripts need to know the real directory.
4068
  // Xcode has build-time settings (e.g. for sanitizers) that affect this,
4069
  // but we use the default here.  Users that want to enable sanitizers
4070
  // will do so at the cost of object library installation and export.
4071
  cmSystemTools::ReplaceString(obj_dir, "$(OBJECT_FILE_DIR_normal:base)",
4072
                               "Objects-normal");
4073
#endif
4074
0
  return obj_dir;
4075
0
}
4076
4077
void cmGeneratorTarget::GetTargetObjectNames(
4078
  std::string const& config, std::vector<std::string>& objects) const
4079
0
{
4080
0
  this->GetTargetObjectNames(
4081
0
    config, [](cmSourceFile const&) -> bool { return true; }, objects);
4082
0
}
4083
4084
void cmGeneratorTarget::GetTargetObjectNames(
4085
  std::string const& config, std::function<bool(cmSourceFile const&)> filter,
4086
  std::vector<std::string>& objects) const
4087
0
{
4088
0
  this->GetTargetObjectLocations(
4089
0
    config, filter,
4090
0
    [&objects](cmObjectLocation const& buildLoc, cmObjectLocation const&) {
4091
0
      objects.push_back(buildLoc.GetPath());
4092
0
    });
4093
0
}
4094
4095
void cmGeneratorTarget::GetTargetObjectLocations(
4096
  std::string const& config,
4097
  std::function<void(cmObjectLocation const&, cmObjectLocation const&)> cb)
4098
  const
4099
0
{
4100
0
  this->GetTargetObjectLocations(
4101
0
    config, [](cmSourceFile const&) -> bool { return true; }, cb);
4102
0
}
4103
4104
void cmGeneratorTarget::GetTargetObjectLocations(
4105
  std::string const& config, std::function<bool(cmSourceFile const&)> filter,
4106
  std::function<void(cmObjectLocation const&, cmObjectLocation const&)> cb)
4107
  const
4108
0
{
4109
0
  std::vector<cmSourceFile const*> objectSources;
4110
0
  this->GetObjectSources(objectSources, config);
4111
0
  std::map<cmSourceFile const*, cmObjectLocations> mapping;
4112
4113
0
  for (cmSourceFile const* sf : objectSources) {
4114
0
    mapping[sf];
4115
0
  }
4116
4117
0
  this->LocalGenerator->ComputeObjectFilenames(mapping, config, this);
4118
4119
0
  auto const buildUseShortPaths = this->GetUseShortObjectNames()
4120
0
    ? cmObjectLocations::UseShortPath::Yes
4121
0
    : cmObjectLocations::UseShortPath::No;
4122
0
  auto const installUseShortPaths = this->GetUseShortObjectNamesForInstall();
4123
4124
0
  for (cmSourceFile const* src : objectSources) {
4125
0
    if (filter(*src)) {
4126
      // Find the object file name corresponding to this source file.
4127
0
      auto map_it = mapping.find(src);
4128
0
      auto const& buildLoc = map_it->second.GetLocation(buildUseShortPaths);
4129
0
      auto const& installLoc =
4130
0
        map_it->second.GetInstallLocation(installUseShortPaths, config);
4131
      // It must exist because we populated the mapping just above.
4132
0
      assert(!buildLoc.GetPath().empty());
4133
0
      assert(!installLoc.GetPath().empty());
4134
0
      cb(buildLoc, installLoc);
4135
0
    }
4136
0
  }
4137
4138
  // We need to compute the relative path from the root of
4139
  // of the object directory to handle subdirectory paths
4140
0
  std::string rootObjectDir = this->GetObjectDirectory(config);
4141
0
  rootObjectDir = cmSystemTools::CollapseFullPath(rootObjectDir);
4142
0
  auto ispcObjects = this->GetGeneratedISPCObjects(config);
4143
0
  for (auto const& output : ispcObjects) {
4144
0
    if (filter(*output.first)) {
4145
0
      auto relativePathFromObjectDir =
4146
0
        output.second.substr(rootObjectDir.size());
4147
0
      cmObjectLocation ispcLoc(relativePathFromObjectDir);
4148
      // FIXME: apply short path to this object if needed.
4149
0
      cb(ispcLoc, ispcLoc);
4150
0
    }
4151
0
  }
4152
0
}
4153
4154
bool cmGeneratorTarget::StrictTargetComparison::operator()(
4155
  cmGeneratorTarget const* t1, cmGeneratorTarget const* t2) const
4156
0
{
4157
0
  int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
4158
0
  if (nameResult == 0) {
4159
0
    return strcmp(
4160
0
             t1->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str(),
4161
0
             t2->GetLocalGenerator()->GetCurrentBinaryDirectory().c_str()) < 0;
4162
0
  }
4163
0
  return nameResult < 0;
4164
0
}
4165
4166
struct cmGeneratorTarget::SourceFileFlags
4167
cmGeneratorTarget::GetTargetSourceFileFlags(cmSourceFile const* sf) const
4168
0
{
4169
0
  struct SourceFileFlags flags;
4170
0
  this->ConstructSourceFileFlags();
4171
0
  auto si = this->SourceFlagsMap.find(sf);
4172
0
  if (si != this->SourceFlagsMap.end()) {
4173
0
    flags = si->second;
4174
0
  } else {
4175
    // Handle the MACOSX_PACKAGE_LOCATION property on source files that
4176
    // were not listed in one of the other lists.
4177
0
    if (cmValue location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
4178
0
      flags.MacFolder = location->c_str();
4179
0
      bool const stripResources =
4180
0
        this->GlobalGenerator->ShouldStripResourcePath(this->Makefile);
4181
0
      if (*location == "Resources") {
4182
0
        flags.Type = cmGeneratorTarget::SourceFileTypeResource;
4183
0
        if (stripResources) {
4184
0
          flags.MacFolder = "";
4185
0
        }
4186
0
      } else if (cmHasLiteralPrefix(*location, "Resources/")) {
4187
0
        flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
4188
0
        if (stripResources) {
4189
0
          flags.MacFolder += cmStrLen("Resources/");
4190
0
        }
4191
0
      } else {
4192
0
        flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
4193
0
      }
4194
0
    }
4195
0
  }
4196
0
  return flags;
4197
0
}
4198
4199
void cmGeneratorTarget::ConstructSourceFileFlags() const
4200
0
{
4201
0
  if (this->SourceFileFlagsConstructed) {
4202
0
    return;
4203
0
  }
4204
0
  this->SourceFileFlagsConstructed = true;
4205
4206
  // Process public headers to mark the source files.
4207
0
  if (cmValue files = this->GetProperty("PUBLIC_HEADER")) {
4208
0
    cmList relFiles{ *files };
4209
0
    for (auto const& relFile : relFiles) {
4210
0
      if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
4211
0
        SourceFileFlags& flags = this->SourceFlagsMap[sf];
4212
0
        flags.MacFolder = "Headers";
4213
0
        flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
4214
0
      }
4215
0
    }
4216
0
  }
4217
4218
  // Process private headers after public headers so that they take
4219
  // precedence if a file is listed in both.
4220
0
  if (cmValue files = this->GetProperty("PRIVATE_HEADER")) {
4221
0
    cmList relFiles{ *files };
4222
0
    for (auto const& relFile : relFiles) {
4223
0
      if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
4224
0
        SourceFileFlags& flags = this->SourceFlagsMap[sf];
4225
0
        flags.MacFolder = "PrivateHeaders";
4226
0
        flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
4227
0
      }
4228
0
    }
4229
0
  }
4230
4231
  // Mark sources listed as resources.
4232
0
  if (cmValue files = this->GetProperty("RESOURCE")) {
4233
0
    cmList relFiles{ *files };
4234
0
    for (auto const& relFile : relFiles) {
4235
0
      if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
4236
0
        SourceFileFlags& flags = this->SourceFlagsMap[sf];
4237
0
        flags.MacFolder = "";
4238
0
        if (!this->GlobalGenerator->ShouldStripResourcePath(this->Makefile)) {
4239
0
          flags.MacFolder = "Resources";
4240
0
        }
4241
0
        flags.Type = cmGeneratorTarget::SourceFileTypeResource;
4242
0
      }
4243
0
    }
4244
0
  }
4245
0
}
4246
4247
bool cmGeneratorTarget::SetDeviceLink(bool deviceLink)
4248
0
{
4249
0
  bool previous = this->DeviceLink;
4250
0
  this->DeviceLink = deviceLink;
4251
0
  return previous;
4252
0
}
4253
4254
void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
4255
0
{
4256
0
  int patch;
4257
0
  this->GetTargetVersion("VERSION", major, minor, patch);
4258
0
}
4259
4260
void cmGeneratorTarget::GetTargetVersionFallback(
4261
  std::string const& property, std::string const& fallback_property,
4262
  int& major, int& minor, int& patch) const
4263
0
{
4264
0
  if (this->GetProperty(property)) {
4265
0
    this->GetTargetVersion(property, major, minor, patch);
4266
0
  } else {
4267
0
    this->GetTargetVersion(fallback_property, major, minor, patch);
4268
0
  }
4269
0
}
4270
4271
void cmGeneratorTarget::GetTargetVersion(std::string const& property,
4272
                                         int& major, int& minor,
4273
                                         int& patch) const
4274
0
{
4275
  // Set the default values.
4276
0
  major = 0;
4277
0
  minor = 0;
4278
0
  patch = 0;
4279
4280
0
  assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
4281
4282
0
  if (cmValue version = this->GetProperty(property)) {
4283
    // Try to parse the version number and store the results that were
4284
    // successfully parsed.
4285
0
    int parsed_major;
4286
0
    int parsed_minor;
4287
0
    int parsed_patch;
4288
0
    switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor,
4289
0
                   &parsed_patch)) {
4290
0
      case 3:
4291
0
        patch = parsed_patch;
4292
0
        CM_FALLTHROUGH;
4293
0
      case 2:
4294
0
        minor = parsed_minor;
4295
0
        CM_FALLTHROUGH;
4296
0
      case 1:
4297
0
        major = parsed_major;
4298
0
        CM_FALLTHROUGH;
4299
0
      default:
4300
0
        break;
4301
0
    }
4302
0
  }
4303
0
}
4304
4305
std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
4306
  std::string const& lang, std::string const& config) const
4307
0
{
4308
  // This is activated by the presence of a default selection whether or
4309
  // not it is overridden by a property.
4310
0
  cmValue runtimeLibraryDefault = this->Makefile->GetDefinition(
4311
0
    cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
4312
0
  if (!cmNonempty(runtimeLibraryDefault)) {
4313
0
    return std::string();
4314
0
  }
4315
0
  cmValue runtimeLibraryValue =
4316
0
    this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
4317
0
  if (!runtimeLibraryValue) {
4318
0
    runtimeLibraryValue = runtimeLibraryDefault;
4319
0
  }
4320
0
  return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
4321
0
    *runtimeLibraryValue, this->LocalGenerator, config, this));
4322
0
}
4323
4324
std::string cmGeneratorTarget::GetFortranModuleDirectory(
4325
  std::string const& working_dir) const
4326
0
{
4327
0
  if (!this->FortranModuleDirectoryCreated) {
4328
0
    this->FortranModuleDirectory =
4329
0
      this->CreateFortranModuleDirectory(working_dir);
4330
0
    this->FortranModuleDirectoryCreated = true;
4331
0
  }
4332
4333
0
  return this->FortranModuleDirectory;
4334
0
}
4335
4336
bool cmGeneratorTarget::IsFortranBuildingIntrinsicModules() const
4337
0
{
4338
  // ATTENTION Before 4.0 the property name was misspelled.
4339
  // Check the correct name first and than the old name.
4340
0
  if (cmValue prop = this->GetProperty("Fortran_BUILDING_INTRINSIC_MODULES")) {
4341
0
    return prop.IsOn();
4342
0
  }
4343
0
  if (cmValue prop =
4344
0
        this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) {
4345
0
    return prop.IsOn();
4346
0
  }
4347
0
  return false;
4348
0
}
4349
4350
std::string cmGeneratorTarget::CreateFortranModuleDirectory(
4351
  std::string const& working_dir) const
4352
0
{
4353
0
  std::string mod_dir;
4354
0
  std::string target_mod_dir;
4355
0
  if (cmValue prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
4356
0
    target_mod_dir = *prop;
4357
0
  } else {
4358
0
    std::string const& default_mod_dir =
4359
0
      this->LocalGenerator->GetCurrentBinaryDirectory();
4360
0
    if (default_mod_dir != working_dir) {
4361
0
      target_mod_dir = default_mod_dir;
4362
0
    }
4363
0
  }
4364
0
  cmValue moddir_flag =
4365
0
    this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
4366
0
  if (!target_mod_dir.empty() && moddir_flag) {
4367
    // Compute the full path to the module directory.
4368
0
    if (cmSystemTools::FileIsFullPath(target_mod_dir)) {
4369
      // Already a full path.
4370
0
      mod_dir = target_mod_dir;
4371
0
    } else {
4372
      // Interpret relative to the current output directory.
4373
0
      mod_dir = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
4374
0
                         '/', target_mod_dir);
4375
0
    }
4376
4377
    // Make sure the module output directory exists.
4378
0
    cmSystemTools::MakeDirectory(mod_dir);
4379
0
  }
4380
0
  return mod_dir;
4381
0
}
4382
4383
void cmGeneratorTarget::AddISPCGeneratedHeader(std::string const& header,
4384
                                               std::string const& config)
4385
0
{
4386
0
  std::string config_upper;
4387
0
  if (!config.empty()) {
4388
0
    config_upper = cmSystemTools::UpperCase(config);
4389
0
  }
4390
0
  auto iter = this->ISPCGeneratedHeaders.find(config_upper);
4391
0
  if (iter == this->ISPCGeneratedHeaders.end()) {
4392
0
    std::vector<std::string> headers;
4393
0
    headers.emplace_back(header);
4394
0
    this->ISPCGeneratedHeaders.insert({ config_upper, headers });
4395
0
  } else {
4396
0
    iter->second.emplace_back(header);
4397
0
  }
4398
0
}
4399
4400
std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
4401
  std::string const& config) const
4402
0
{
4403
0
  std::string config_upper;
4404
0
  if (!config.empty()) {
4405
0
    config_upper = cmSystemTools::UpperCase(config);
4406
0
  }
4407
0
  auto iter = this->ISPCGeneratedHeaders.find(config_upper);
4408
0
  if (iter == this->ISPCGeneratedHeaders.end()) {
4409
0
    return std::vector<std::string>{};
4410
0
  }
4411
0
  return iter->second;
4412
0
}
4413
4414
void cmGeneratorTarget::AddISPCGeneratedObject(
4415
  std::vector<std::pair<cmSourceFile const*, std::string>>&& objs,
4416
  std::string const& config)
4417
0
{
4418
0
  std::string config_upper;
4419
0
  if (!config.empty()) {
4420
0
    config_upper = cmSystemTools::UpperCase(config);
4421
0
  }
4422
0
  auto iter = this->ISPCGeneratedObjects.find(config_upper);
4423
0
  if (iter == this->ISPCGeneratedObjects.end()) {
4424
0
    this->ISPCGeneratedObjects.insert({ config_upper, objs });
4425
0
  } else {
4426
0
    iter->second.insert(iter->second.end(), objs.begin(), objs.end());
4427
0
  }
4428
0
}
4429
4430
std::vector<std::pair<cmSourceFile const*, std::string>>
4431
cmGeneratorTarget::GetGeneratedISPCObjects(std::string const& config) const
4432
0
{
4433
0
  std::string config_upper;
4434
0
  if (!config.empty()) {
4435
0
    config_upper = cmSystemTools::UpperCase(config);
4436
0
  }
4437
0
  auto iter = this->ISPCGeneratedObjects.find(config_upper);
4438
0
  if (iter == this->ISPCGeneratedObjects.end()) {
4439
0
    return std::vector<std::pair<cmSourceFile const*, std::string>>{};
4440
0
  }
4441
0
  return iter->second;
4442
0
}
4443
4444
std::string cmGeneratorTarget::GetFrameworkVersion() const
4445
0
{
4446
0
  assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
4447
4448
0
  if (cmValue fversion = this->GetProperty("FRAMEWORK_VERSION")) {
4449
0
    return *fversion;
4450
0
  }
4451
0
  if (cmValue tversion = this->GetProperty("VERSION")) {
4452
0
    return *tversion;
4453
0
  }
4454
0
  return "A";
4455
0
}
4456
4457
std::string cmGeneratorTarget::ComputeVersionedName(std::string const& prefix,
4458
                                                    std::string const& base,
4459
                                                    std::string const& suffix,
4460
                                                    std::string const& name,
4461
                                                    cmValue version) const
4462
0
{
4463
0
  std::string vName = this->IsApple() ? (prefix + base) : name;
4464
0
  if (version) {
4465
0
    vName += ".";
4466
0
    vName += *version;
4467
0
  }
4468
0
  vName += this->IsApple() ? suffix : std::string();
4469
0
  return vName;
4470
0
}
4471
4472
std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
4473
0
{
4474
0
  return this->Target->GetProperties().GetKeys();
4475
0
}
4476
4477
void cmGeneratorTarget::ReportPropertyOrigin(
4478
  std::string const& p, std::string const& result, std::string const& report,
4479
  std::string const& compatibilityType) const
4480
0
{
4481
0
  cmList debugProperties{ this->Target->GetMakefile()->GetDefinition(
4482
0
    "CMAKE_DEBUG_TARGET_PROPERTIES") };
4483
0
  bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] &&
4484
0
    cm::contains(debugProperties, p);
4485
4486
0
  this->DebugCompatiblePropertiesDone[p] = true;
4487
0
  if (!debugOrigin) {
4488
0
    return;
4489
0
  }
4490
4491
0
  std::string areport =
4492
0
    cmStrCat(compatibilityType, " of property \"", p, "\" for target \"",
4493
0
             this->GetName(), "\" (result: \"", result, "\"):\n", report);
4494
4495
0
  this->LocalGenerator->GetCMakeInstance()->IssueMessage(MessageType::LOG,
4496
0
                                                         areport);
4497
0
}
4498
4499
std::string cmGeneratorTarget::GetDirectory(
4500
  std::string const& config, cmStateEnums::ArtifactType artifact) const
4501
0
{
4502
0
  if (this->IsImported()) {
4503
0
    auto fullPath = this->Target->ImportedGetFullPath(config, artifact);
4504
0
    if (this->IsFrameworkOnApple()) {
4505
0
      auto fwDescriptor = this->GetGlobalGenerator()->SplitFrameworkPath(
4506
0
        fullPath, cmGlobalGenerator::FrameworkFormat::Strict);
4507
0
      if (fwDescriptor) {
4508
0
        return fwDescriptor->Directory;
4509
0
      }
4510
0
    }
4511
    // Return the directory from which the target is imported.
4512
0
    return cmSystemTools::GetFilenamePath(fullPath);
4513
0
  }
4514
0
  if (OutputInfo const* info = this->GetOutputInfo(config)) {
4515
    // Return the directory in which the target will be built.
4516
0
    switch (artifact) {
4517
0
      case cmStateEnums::RuntimeBinaryArtifact:
4518
0
        return info->OutDir;
4519
0
      case cmStateEnums::ImportLibraryArtifact:
4520
0
        return info->ImpDir;
4521
0
    }
4522
0
  }
4523
0
  return "";
4524
0
}
4525
4526
bool cmGeneratorTarget::UsesDefaultOutputDir(
4527
  std::string const& config, cmStateEnums::ArtifactType artifact) const
4528
0
{
4529
0
  std::string dir;
4530
0
  return this->ComputeOutputDir(config, artifact, dir);
4531
0
}
4532
4533
cmGeneratorTarget::OutputInfo const* cmGeneratorTarget::GetOutputInfo(
4534
  std::string const& config) const
4535
0
{
4536
  // There is no output information for imported targets.
4537
0
  if (this->IsImported()) {
4538
0
    return nullptr;
4539
0
  }
4540
4541
  // Synthetic targets don't have output.
4542
0
  if (this->IsSynthetic()) {
4543
0
    return nullptr;
4544
0
  }
4545
4546
  // Only libraries and executables have well-defined output files.
4547
0
  if (!this->HaveWellDefinedOutputFiles()) {
4548
0
    std::string msg = cmStrCat("cmGeneratorTarget::GetOutputInfo called for ",
4549
0
                               this->GetName(), " which has type ",
4550
0
                               cmState::GetTargetTypeName(this->GetType()));
4551
0
    this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
4552
0
    return nullptr;
4553
0
  }
4554
4555
  // Lookup/compute/cache the output information for this configuration.
4556
0
  std::string config_upper;
4557
0
  if (!config.empty()) {
4558
0
    config_upper = cmSystemTools::UpperCase(config);
4559
0
  }
4560
0
  auto i = this->OutputInfoMap.find(config_upper);
4561
0
  if (i == this->OutputInfoMap.end()) {
4562
    // Add empty info in map to detect potential recursion.
4563
0
    OutputInfo info;
4564
0
    OutputInfoMapType::value_type entry(config_upper, info);
4565
0
    i = this->OutputInfoMap.insert(entry).first;
4566
4567
    // Compute output directories.
4568
0
    this->ComputeOutputDir(config, cmStateEnums::RuntimeBinaryArtifact,
4569
0
                           info.OutDir);
4570
0
    this->ComputeOutputDir(config, cmStateEnums::ImportLibraryArtifact,
4571
0
                           info.ImpDir);
4572
0
    if (!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) {
4573
0
      info.PdbDir = info.OutDir;
4574
0
    }
4575
4576
    // Now update the previously-prepared map entry.
4577
0
    i->second = info;
4578
0
  } else if (i->second.empty()) {
4579
    // An empty map entry indicates we have been called recursively
4580
    // from the above block.
4581
0
    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
4582
0
      MessageType::FATAL_ERROR,
4583
0
      cmStrCat("Target '", this->GetName(),
4584
0
               "' OUTPUT_DIRECTORY depends on itself."),
4585
0
      this->GetBacktrace());
4586
0
    return nullptr;
4587
0
  }
4588
0
  return &i->second;
4589
0
}
4590
4591
bool cmGeneratorTarget::ComputeOutputDir(std::string const& config,
4592
                                         cmStateEnums::ArtifactType artifact,
4593
                                         std::string& out) const
4594
0
{
4595
0
  bool usesDefaultOutputDir = false;
4596
0
  std::string conf = config;
4597
4598
  // Look for a target property defining the target output directory
4599
  // based on the target type.
4600
0
  std::string targetTypeName = this->GetOutputTargetType(artifact);
4601
0
  std::string propertyName;
4602
0
  if (!targetTypeName.empty()) {
4603
0
    propertyName = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY");
4604
0
  }
4605
4606
  // Check for a per-configuration output directory target property.
4607
0
  std::string configUpper = cmSystemTools::UpperCase(conf);
4608
0
  std::string configProp;
4609
0
  if (!targetTypeName.empty()) {
4610
0
    configProp = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY_", configUpper);
4611
0
  }
4612
4613
  // Select an output directory.
4614
0
  if (cmValue config_outdir = this->GetProperty(configProp)) {
4615
    // Use the user-specified per-configuration output directory.
4616
0
    out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
4617
0
                                          config, this);
4618
4619
    // Skip per-configuration subdirectory.
4620
0
    conf.clear();
4621
0
  } else if (cmValue outdir = this->GetProperty(propertyName)) {
4622
    // Use the user-specified output directory.
4623
0
    out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator,
4624
0
                                          config, this);
4625
    // Skip per-configuration subdirectory if the value contained a
4626
    // generator expression.
4627
0
    if (out != *outdir) {
4628
0
      conf.clear();
4629
0
    }
4630
0
  } else if (this->GetType() == cmStateEnums::EXECUTABLE) {
4631
    // Lookup the output path for executables.
4632
0
    out = this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
4633
0
  } else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
4634
0
             this->GetType() == cmStateEnums::SHARED_LIBRARY ||
4635
0
             this->GetType() == cmStateEnums::MODULE_LIBRARY) {
4636
    // Lookup the output path for libraries.
4637
0
    out = this->Makefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
4638
0
  }
4639
0
  if (out.empty()) {
4640
    // Default to the current output directory.
4641
0
    usesDefaultOutputDir = true;
4642
0
    out = ".";
4643
0
  }
4644
4645
  // Convert the output path to a full path in case it is
4646
  // specified as a relative path.  Treat a relative path as
4647
  // relative to the current output directory for this makefile.
4648
0
  out = (cmSystemTools::CollapseFullPath(
4649
0
    out, this->LocalGenerator->GetCurrentBinaryDirectory()));
4650
4651
  // The generator may add the configuration's subdirectory.
4652
0
  if (!conf.empty()) {
4653
0
    bool useEPN =
4654
0
      this->GlobalGenerator->UseEffectivePlatformName(this->Makefile);
4655
0
    std::string suffix =
4656
0
      usesDefaultOutputDir && useEPN ? "${EFFECTIVE_PLATFORM_NAME}" : "";
4657
0
    this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
4658
0
      "/", conf, suffix, out);
4659
0
  }
4660
4661
0
  return usesDefaultOutputDir;
4662
0
}
4663
4664
bool cmGeneratorTarget::ComputePDBOutputDir(std::string const& kind,
4665
                                            std::string const& config,
4666
                                            std::string& out) const
4667
0
{
4668
  // Look for a target property defining the target output directory
4669
  // based on the target type.
4670
0
  std::string propertyName;
4671
0
  if (!kind.empty()) {
4672
0
    propertyName = cmStrCat(kind, "_OUTPUT_DIRECTORY");
4673
0
  }
4674
0
  std::string conf = config;
4675
4676
  // Check for a per-configuration output directory target property.
4677
0
  std::string configUpper = cmSystemTools::UpperCase(conf);
4678
0
  std::string configProp;
4679
0
  if (!kind.empty()) {
4680
0
    configProp = cmStrCat(kind, "_OUTPUT_DIRECTORY_", configUpper);
4681
0
  }
4682
4683
  // Select an output directory.
4684
0
  if (cmValue config_outdir = this->GetProperty(configProp)) {
4685
    // Use the user-specified per-configuration output directory.
4686
0
    out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
4687
0
                                          config);
4688
4689
    // Skip per-configuration subdirectory.
4690
0
    conf.clear();
4691
0
  } else if (cmValue outdir = this->GetProperty(propertyName)) {
4692
    // Use the user-specified output directory.
4693
0
    out =
4694
0
      cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
4695
4696
    // Skip per-configuration subdirectory if the value contained a
4697
    // generator expression.
4698
0
    if (out != *outdir) {
4699
0
      conf.clear();
4700
0
    }
4701
0
  }
4702
0
  if (out.empty()) {
4703
0
    cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget();
4704
0
    bool const hasReuse = reuseTarget && reuseTarget != this;
4705
    // Compiler-generated PDB output always needed for REUSE_FROM.
4706
0
    if (kind == "COMPILE_PDB"_s && (this->PchReused || hasReuse)) {
4707
0
      out = this->GetSupportDirectory();
4708
0
    } else {
4709
0
      return false;
4710
0
    }
4711
0
  }
4712
4713
  // Convert the output path to a full path in case it is
4714
  // specified as a relative path.  Treat a relative path as
4715
  // relative to the current output directory for this makefile.
4716
0
  out = (cmSystemTools::CollapseFullPath(
4717
0
    out, this->LocalGenerator->GetCurrentBinaryDirectory()));
4718
4719
  // The generator may add the configuration's subdirectory.
4720
0
  if (!conf.empty()) {
4721
0
    this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
4722
0
      "/", conf, "", out);
4723
0
  }
4724
0
  return true;
4725
0
}
4726
4727
bool cmGeneratorTarget::HaveInstallTreeRPATH(std::string const& config) const
4728
0
{
4729
0
  std::string install_rpath;
4730
0
  this->GetInstallRPATH(config, install_rpath);
4731
0
  return !install_rpath.empty() &&
4732
0
    !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
4733
0
}
4734
4735
bool cmGeneratorTarget::GetBuildRPATH(std::string const& config,
4736
                                      std::string& rpath) const
4737
0
{
4738
0
  return this->GetRPATH(config, "BUILD_RPATH", rpath);
4739
0
}
4740
4741
bool cmGeneratorTarget::GetInstallRPATH(std::string const& config,
4742
                                        std::string& rpath) const
4743
0
{
4744
0
  return this->GetRPATH(config, "INSTALL_RPATH", rpath);
4745
0
}
4746
4747
bool cmGeneratorTarget::GetRPATH(std::string const& config,
4748
                                 std::string const& prop,
4749
                                 std::string& rpath) const
4750
0
{
4751
0
  cmValue value = this->GetProperty(prop);
4752
0
  if (!value) {
4753
0
    return false;
4754
0
  }
4755
4756
0
  rpath =
4757
0
    cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config);
4758
4759
0
  return true;
4760
0
}
4761
4762
cmGeneratorTarget::ImportInfo const* cmGeneratorTarget::GetImportInfo(
4763
  std::string const& config) const
4764
0
{
4765
  // There is no imported information for non-imported targets.
4766
0
  if (!this->IsImported()) {
4767
0
    return nullptr;
4768
0
  }
4769
4770
  // Lookup/compute/cache the import information for this
4771
  // configuration.
4772
0
  std::string config_upper;
4773
0
  if (!config.empty()) {
4774
0
    config_upper = cmSystemTools::UpperCase(config);
4775
0
  } else {
4776
0
    config_upper = "NOCONFIG";
4777
0
  }
4778
4779
0
  auto i = this->ImportInfoMap.find(config_upper);
4780
0
  if (i == this->ImportInfoMap.end()) {
4781
0
    ImportInfo info;
4782
0
    this->ComputeImportInfo(config_upper, info);
4783
0
    ImportInfoMapType::value_type entry(config_upper, info);
4784
0
    i = this->ImportInfoMap.insert(entry).first;
4785
0
  }
4786
4787
0
  if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
4788
0
    return &i->second;
4789
0
  }
4790
  // If the location is empty then the target is not available for
4791
  // this configuration.
4792
0
  if (i->second.Location.empty() && i->second.ImportLibrary.empty()) {
4793
0
    return nullptr;
4794
0
  }
4795
4796
  // Return the import information.
4797
0
  return &i->second;
4798
0
}
4799
4800
void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
4801
                                          ImportInfo& info) const
4802
0
{
4803
  // This method finds information about an imported target from its
4804
  // properties.  The "IMPORTED_" namespace is reserved for properties
4805
  // defined by the project exporting the target.
4806
4807
  // Initialize members.
4808
0
  info.NoSOName = false;
4809
4810
0
  cmValue loc = nullptr;
4811
0
  cmValue imp = nullptr;
4812
0
  std::string suffix;
4813
0
  if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) {
4814
0
    return;
4815
0
  }
4816
4817
  // Get the link interface.
4818
0
  {
4819
    // Use the INTERFACE_LINK_LIBRARIES special representation directly
4820
    // to get backtraces.
4821
0
    cmBTStringRange entries = this->Target->GetLinkInterfaceEntries();
4822
0
    if (!entries.empty()) {
4823
0
      info.LibrariesProp = "INTERFACE_LINK_LIBRARIES";
4824
0
      for (BT<std::string> const& entry : entries) {
4825
0
        info.Libraries.emplace_back(entry);
4826
0
      }
4827
0
    } else if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
4828
0
      std::string linkProp =
4829
0
        cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix);
4830
0
      cmValue propertyLibs = this->GetProperty(linkProp);
4831
0
      if (!propertyLibs) {
4832
0
        linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
4833
0
        propertyLibs = this->GetProperty(linkProp);
4834
0
      }
4835
0
      if (propertyLibs) {
4836
0
        info.LibrariesProp = linkProp;
4837
0
        info.Libraries.emplace_back(*propertyLibs);
4838
0
      }
4839
0
    }
4840
0
  }
4841
0
  for (BT<std::string> const& entry :
4842
0
       this->Target->GetLinkInterfaceDirectEntries()) {
4843
0
    info.LibrariesHeadInclude.emplace_back(entry);
4844
0
  }
4845
0
  for (BT<std::string> const& entry :
4846
0
       this->Target->GetLinkInterfaceDirectExcludeEntries()) {
4847
0
    info.LibrariesHeadExclude.emplace_back(entry);
4848
0
  }
4849
0
  if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
4850
0
    if (loc) {
4851
0
      info.LibName = *loc;
4852
0
    }
4853
0
    return;
4854
0
  }
4855
4856
  // A provided configuration has been chosen.  Load the
4857
  // configuration's properties.
4858
4859
  // Get the location.
4860
0
  if (loc) {
4861
0
    info.Location = *loc;
4862
0
  } else {
4863
0
    std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
4864
0
    if (cmValue config_location = this->GetProperty(impProp)) {
4865
0
      info.Location = *config_location;
4866
0
    } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) {
4867
0
      info.Location = *location;
4868
0
    }
4869
0
  }
4870
4871
  // Get the soname.
4872
0
  if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
4873
0
    std::string soProp = cmStrCat("IMPORTED_SONAME", suffix);
4874
0
    if (cmValue config_soname = this->GetProperty(soProp)) {
4875
0
      info.SOName = *config_soname;
4876
0
    } else if (cmValue soname = this->GetProperty("IMPORTED_SONAME")) {
4877
0
      info.SOName = *soname;
4878
0
    }
4879
0
  }
4880
4881
  // Get the "no-soname" mark.
4882
0
  if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
4883
0
    std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix);
4884
0
    if (cmValue config_no_soname = this->GetProperty(soProp)) {
4885
0
      info.NoSOName = config_no_soname.IsOn();
4886
0
    } else if (cmValue no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
4887
0
      info.NoSOName = no_soname.IsOn();
4888
0
    }
4889
0
  }
4890
4891
  // Get the import library.
4892
0
  if (imp) {
4893
0
    info.ImportLibrary = *imp;
4894
0
  } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
4895
0
             this->IsExecutableWithExports()) {
4896
0
    std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
4897
0
    if (cmValue config_implib = this->GetProperty(impProp)) {
4898
0
      info.ImportLibrary = *config_implib;
4899
0
    } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
4900
0
      info.ImportLibrary = *implib;
4901
0
    }
4902
0
  }
4903
4904
  // Get the link dependencies.
4905
0
  {
4906
0
    std::string linkProp =
4907
0
      cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix);
4908
0
    if (cmValue config_libs = this->GetProperty(linkProp)) {
4909
0
      info.SharedDeps = *config_libs;
4910
0
    } else if (cmValue libs =
4911
0
                 this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
4912
0
      info.SharedDeps = *libs;
4913
0
    }
4914
0
  }
4915
4916
  // Get the link languages.
4917
0
  if (this->LinkLanguagePropagatesToDependents()) {
4918
0
    std::string linkProp =
4919
0
      cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix);
4920
0
    if (cmValue config_libs = this->GetProperty(linkProp)) {
4921
0
      info.Languages = *config_libs;
4922
0
    } else if (cmValue libs =
4923
0
                 this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
4924
0
      info.Languages = *libs;
4925
0
    }
4926
0
  }
4927
4928
  // Get information if target is managed assembly.
4929
0
  {
4930
0
    std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
4931
0
    if (cmValue pc = this->GetProperty(linkProp + suffix)) {
4932
0
      info.Managed = this->CheckManagedType(*pc);
4933
0
    } else if (cmValue p = this->GetProperty(linkProp)) {
4934
0
      info.Managed = this->CheckManagedType(*p);
4935
0
    }
4936
0
  }
4937
4938
  // Get the cyclic repetition count.
4939
0
  if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
4940
0
    std::string linkProp =
4941
0
      cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
4942
0
    if (cmValue config_reps = this->GetProperty(linkProp)) {
4943
0
      sscanf(config_reps->c_str(), "%u", &info.Multiplicity);
4944
0
    } else if (cmValue reps =
4945
0
                 this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
4946
0
      sscanf(reps->c_str(), "%u", &info.Multiplicity);
4947
0
    }
4948
0
  }
4949
0
}
4950
4951
bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
4952
  std::vector<cmSourceFile*>& files) const
4953
0
{
4954
0
  std::vector<std::string> const& configs =
4955
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
4956
4957
0
  auto it = configs.begin();
4958
0
  std::string const& firstConfig = *it;
4959
0
  this->GetSourceFilesWithoutObjectLibraries(files, firstConfig);
4960
4961
0
  for (; it != configs.end(); ++it) {
4962
0
    std::vector<cmSourceFile*> configFiles;
4963
0
    this->GetSourceFilesWithoutObjectLibraries(configFiles, *it);
4964
0
    if (configFiles != files) {
4965
0
      std::string firstConfigFiles;
4966
0
      char const* sep = "";
4967
0
      for (cmSourceFile* f : files) {
4968
0
        firstConfigFiles += sep;
4969
0
        firstConfigFiles += f->ResolveFullPath();
4970
0
        sep = "\n  ";
4971
0
      }
4972
4973
0
      std::string thisConfigFiles;
4974
0
      sep = "";
4975
0
      for (cmSourceFile* f : configFiles) {
4976
0
        thisConfigFiles += sep;
4977
0
        thisConfigFiles += f->ResolveFullPath();
4978
0
        sep = "\n  ";
4979
0
      }
4980
0
      std::ostringstream e;
4981
      /* clang-format off */
4982
0
      e << "Target \"" << this->GetName()
4983
0
        << "\" has source files which vary by "
4984
0
        "configuration. This is not supported by the \""
4985
0
        << this->GlobalGenerator->GetName()
4986
0
        << "\" generator.\n"
4987
0
          "Config \"" << firstConfig << "\":\n"
4988
0
          "  " << firstConfigFiles << "\n"
4989
0
          "Config \"" << *it << "\":\n"
4990
0
          "  " << thisConfigFiles << "\n";
4991
      /* clang-format on */
4992
0
      this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
4993
0
      return false;
4994
0
    }
4995
0
  }
4996
0
  return true;
4997
0
}
4998
4999
void cmGeneratorTarget::GetObjectLibrariesInSources(
5000
  std::vector<BT<cmGeneratorTarget*>>& objlibs) const
5001
0
{
5002
  // FIXME: This searches SOURCES for TARGET_OBJECTS for backwards
5003
  // compatibility with the OLD behavior of CMP0026 since this
5004
  // could be called at configure time.  CMP0026 has been removed,
5005
  // so this should now be called only at generate time.
5006
  // Therefore we should be able to improve the implementation
5007
  // with generate-time information.
5008
0
  cmBTStringRange rng = this->Target->GetSourceEntries();
5009
0
  for (auto const& entry : rng) {
5010
0
    cmList files{ entry.Value };
5011
0
    for (auto const& li : files) {
5012
0
      if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
5013
0
        std::string objLibName = li.substr(17, li.size() - 18);
5014
5015
0
        if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
5016
0
          continue;
5017
0
        }
5018
0
        cmGeneratorTarget* objLib =
5019
0
          this->LocalGenerator->FindGeneratorTargetToUse(objLibName);
5020
0
        if (objLib) {
5021
0
          objlibs.emplace_back(objLib, entry.Backtrace);
5022
0
        }
5023
0
      }
5024
0
    }
5025
0
  }
5026
0
}
5027
5028
std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
5029
0
{
5030
  // Strip whitespace off the library names because we used to do this
5031
  // in case variables were expanded at generate time.  We no longer
5032
  // do the expansion but users link to libraries like " ${VAR} ".
5033
0
  std::string lib = item;
5034
0
  std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
5035
0
  if (pos != std::string::npos) {
5036
0
    lib = lib.substr(pos);
5037
0
  }
5038
0
  pos = lib.find_last_not_of(" \t\r\n");
5039
0
  if (pos != std::string::npos) {
5040
0
    lib = lib.substr(0, pos + 1);
5041
0
  }
5042
0
  if (lib != item) {
5043
0
    cmake* cm = this->LocalGenerator->GetCMakeInstance();
5044
0
    std::ostringstream e;
5045
0
    e << "Target \"" << this->GetName() << "\" links to item \"" << item
5046
0
      << "\" which has leading or trailing whitespace.  "
5047
0
      << "This is now an error according to policy CMP0004.";
5048
0
    cm->IssueMessage(MessageType::FATAL_ERROR, e.str(), this->GetBacktrace());
5049
0
  }
5050
0
  return lib;
5051
0
}
5052
5053
bool cmGeneratorTarget::IsDeprecated() const
5054
0
{
5055
0
  cmValue deprecation = this->GetProperty("DEPRECATION");
5056
0
  return cmNonempty(deprecation);
5057
0
}
5058
5059
std::string cmGeneratorTarget::GetDeprecation() const
5060
0
{
5061
  // find DEPRECATION property
5062
0
  if (cmValue deprecation = this->GetProperty("DEPRECATION")) {
5063
0
    return *deprecation;
5064
0
  }
5065
0
  return std::string();
5066
0
}
5067
5068
void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
5069
                                     std::string const& config) const
5070
0
{
5071
  // Targets that do not compile anything have no languages.
5072
0
  if (!this->CanCompileSources()) {
5073
0
    return;
5074
0
  }
5075
5076
0
  std::vector<cmSourceFile*> sourceFiles;
5077
0
  this->GetSourceFiles(sourceFiles, config);
5078
0
  for (cmSourceFile* src : sourceFiles) {
5079
0
    std::string const& lang = src->GetOrDetermineLanguage();
5080
0
    if (!lang.empty()) {
5081
0
      languages.insert(lang);
5082
0
    }
5083
0
  }
5084
5085
0
  std::set<cmGeneratorTarget const*> objectLibraries =
5086
0
    this->GetSourceObjectLibraries(config);
5087
0
  for (cmGeneratorTarget const* objLib : objectLibraries) {
5088
0
    objLib->GetLanguages(languages, config);
5089
0
  }
5090
0
}
5091
5092
std::set<cmGeneratorTarget const*> cmGeneratorTarget::GetSourceObjectLibraries(
5093
  std::string const& config) const
5094
0
{
5095
0
  std::set<cmGeneratorTarget const*> objectLibraries;
5096
0
  std::vector<cmSourceFile const*> externalObjects;
5097
0
  this->GetExternalObjects(externalObjects, config);
5098
0
  for (cmSourceFile const* extObj : externalObjects) {
5099
0
    std::string objLib = extObj->GetObjectLibrary();
5100
0
    if (cmGeneratorTarget* tgt =
5101
0
          this->LocalGenerator->FindGeneratorTargetToUse(objLib)) {
5102
0
      objectLibraries.insert(tgt);
5103
0
    }
5104
0
  }
5105
5106
0
  return objectLibraries;
5107
0
}
5108
5109
bool cmGeneratorTarget::IsLanguageUsed(std::string const& language,
5110
                                       std::string const& config) const
5111
0
{
5112
0
  std::set<std::string> languages;
5113
0
  this->GetLanguages(languages, config);
5114
0
  return languages.count(language);
5115
0
}
5116
5117
bool cmGeneratorTarget::IsCSharpOnly() const
5118
0
{
5119
  // Only certain target types may compile CSharp.
5120
0
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5121
0
      this->GetType() != cmStateEnums::STATIC_LIBRARY &&
5122
0
      this->GetType() != cmStateEnums::EXECUTABLE) {
5123
0
    return false;
5124
0
  }
5125
0
  std::set<std::string> languages = this->GetAllConfigCompileLanguages();
5126
  // Consider an explicit linker language property, but *not* the
5127
  // computed linker language that may depend on linked targets.
5128
0
  cmValue linkLang = this->GetProperty("LINKER_LANGUAGE");
5129
0
  if (cmNonempty(linkLang)) {
5130
0
    languages.insert(*linkLang);
5131
0
  }
5132
0
  return languages.size() == 1 && languages.count("CSharp") > 0;
5133
0
}
5134
5135
bool cmGeneratorTarget::IsDotNetSdkTarget() const
5136
0
{
5137
0
  return !this->GetProperty("DOTNET_SDK").IsEmpty();
5138
0
}
5139
5140
void cmGeneratorTarget::ComputeLinkImplementationLanguages(
5141
  std::string const& config, cmOptionalLinkImplementation& impl) const
5142
0
{
5143
  // This target needs runtime libraries for its source languages.
5144
0
  std::set<std::string> languages;
5145
  // Get languages used in our source files.
5146
0
  this->GetLanguages(languages, config);
5147
  // Copy the set of languages to the link implementation.
5148
0
  impl.Languages.insert(impl.Languages.begin(), languages.begin(),
5149
0
                        languages.end());
5150
0
}
5151
5152
bool cmGeneratorTarget::HaveBuildTreeRPATH(std::string const& config) const
5153
0
{
5154
0
  if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
5155
0
    return false;
5156
0
  }
5157
0
  std::string build_rpath;
5158
0
  if (this->GetBuildRPATH(config, build_rpath)) {
5159
0
    return true;
5160
0
  }
5161
0
  if (cmLinkImplementationLibraries const* impl =
5162
0
        this->GetLinkImplementationLibraries(config, UseTo::Link)) {
5163
0
    return !impl->Libraries.empty();
5164
0
  }
5165
0
  return false;
5166
0
}
5167
5168
bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
5169
  std::string const& p) const
5170
0
{
5171
0
  return cm::contains(this->LinkImplicitNullProperties, p);
5172
0
}
5173
5174
namespace {
5175
bool CreateCxxStdlibTarget(cmMakefile* makefile, cmLocalGenerator* lg,
5176
                           std::string const& targetName,
5177
                           std::string const& cxxTargetName,
5178
                           std::string const& stdLevel,
5179
                           std::vector<std::string> const& configs)
5180
0
{
5181
0
#ifndef CMAKE_BOOTSTRAP
5182
5183
0
  static cm::optional<cmCxxModuleMetadata> metadata;
5184
5185
  // Load metadata only when we need to create a target
5186
0
  if (!metadata) {
5187
0
    auto errorMessage =
5188
0
      makefile->GetDefinition("CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE");
5189
0
    if (!errorMessage.IsEmpty()) {
5190
0
      makefile->IssueMessage(
5191
0
        MessageType::FATAL_ERROR,
5192
0
        cmStrCat(R"(The "CXX_MODULE_STD" property on target ")", targetName,
5193
0
                 "\" requires toolchain support, but it was not provided.  "
5194
0
                 "Reason:\n  ",
5195
0
                 *errorMessage));
5196
0
      return false;
5197
0
    }
5198
5199
0
    auto metadataPath =
5200
0
      makefile->GetDefinition("CMAKE_CXX_STDLIB_MODULES_JSON");
5201
0
    if (metadataPath.IsEmpty()) {
5202
0
      makefile->IssueMessage(
5203
0
        MessageType::FATAL_ERROR,
5204
0
        cmStrCat(
5205
0
          R"("The "CXX_MODULE_STD" property on target ")", targetName,
5206
0
          "\" requires CMAKE_CXX_STDLIB_MODULES_JSON be set, but it was not "
5207
0
          "provided by the toolchain."));
5208
0
      return false;
5209
0
    }
5210
5211
0
    auto parseResult = cmCxxModuleMetadata::LoadFromFile(*metadataPath);
5212
0
    if (!parseResult) {
5213
0
      makefile->IssueMessage(
5214
0
        MessageType::FATAL_ERROR,
5215
0
        cmStrCat("Failed to load C++ standard library modules metadata "
5216
0
                 "from \"",
5217
0
                 *metadataPath, "\": ", parseResult.Error));
5218
0
      return false;
5219
0
    }
5220
5221
0
    metadata = std::move(*parseResult.Meta);
5222
0
  }
5223
5224
0
  auto const localTargetName = cmStrCat("__cmake_cxx_std_", stdLevel);
5225
0
  cmStandardLevelResolver standardResolver(makefile);
5226
0
  auto* stdlibTgt = makefile->AddLibrary(
5227
0
    localTargetName, cmStateEnums::STATIC_LIBRARY, {}, true);
5228
0
  cmCxxModuleMetadata::PopulateTarget(*stdlibTgt, *metadata, configs);
5229
0
  standardResolver.AddRequiredTargetFeature(stdlibTgt,
5230
0
                                            cmStrCat("cxx_std_", stdLevel));
5231
0
  auto gt = cm::make_unique<cmGeneratorTarget>(stdlibTgt, lg);
5232
0
  for (auto const& config : configs) {
5233
0
    gt->ComputeCompileFeatures(config);
5234
0
  }
5235
5236
0
  lg->AddGeneratorTarget(std::move(gt));
5237
0
  makefile->AddAlias(cxxTargetName, localTargetName);
5238
5239
0
#endif // CMAKE_BOOTSTRAP
5240
5241
0
  return true;
5242
0
}
5243
} // namespace
5244
5245
bool cmGeneratorTarget::ApplyCXXStdTargets()
5246
0
{
5247
0
  cmStandardLevelResolver standardResolver(this->Makefile);
5248
0
  cmStandardLevel const cxxStd23 =
5249
0
    *standardResolver.LanguageStandardLevel("CXX", "23");
5250
0
  std::vector<std::string> const& configs =
5251
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
5252
0
  auto std_prop = this->GetProperty("CXX_MODULE_STD");
5253
0
  if (!std_prop) {
5254
    // TODO(cxxmodules): Add a target policy to flip the default here. Set
5255
    // `std_prop` based on it.
5256
0
    return true;
5257
0
  }
5258
5259
0
  std::string std_prop_value;
5260
0
  if (std_prop) {
5261
    // Evaluate generator expressions.
5262
0
    cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
5263
0
    auto cge = ge.Parse(*std_prop);
5264
0
    if (!cge) {
5265
0
      this->Makefile->IssueMessage(
5266
0
        MessageType::FATAL_ERROR,
5267
0
        cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
5268
0
                 this->GetName(), "\" is not a valid generator expression."));
5269
0
      return false;
5270
0
    }
5271
    // But do not allow context-sensitive queries. Whether a target uses
5272
    // `import std` should not depend on configuration or properties of the
5273
    // consumer (head target). The link language also shouldn't matter, so ban
5274
    // it as well.
5275
0
    if (cge->GetHadHeadSensitiveCondition()) {
5276
      // Not reachable; all target-sensitive genexes actually fail to parse.
5277
0
      this->Makefile->IssueMessage(
5278
0
        MessageType::FATAL_ERROR,
5279
0
        cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
5280
0
                 this->GetName(),
5281
0
                 "\" contains a condition that queries the "
5282
0
                 "consuming target which is not supported."));
5283
0
      return false;
5284
0
    }
5285
0
    if (cge->GetHadLinkLanguageSensitiveCondition()) {
5286
      // Not reachable; all link language genexes actually fail to parse.
5287
0
      this->Makefile->IssueMessage(
5288
0
        MessageType::FATAL_ERROR,
5289
0
        cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
5290
0
                 this->GetName(),
5291
0
                 "\" contains a condition that queries the "
5292
0
                 "link language which is not supported."));
5293
0
      return false;
5294
0
    }
5295
0
    std_prop_value = cge->Evaluate(this->LocalGenerator, "");
5296
0
    if (cge->GetHadContextSensitiveCondition()) {
5297
0
      this->Makefile->IssueMessage(
5298
0
        MessageType::FATAL_ERROR,
5299
0
        cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
5300
0
                 this->GetName(),
5301
0
                 "\" contains a context-sensitive condition "
5302
0
                 "that is not supported."));
5303
0
      return false;
5304
0
    }
5305
0
  }
5306
0
  auto use_std = cmIsOn(std_prop_value);
5307
5308
  // If we have a value and it is not true, there's nothing to do.
5309
0
  if (std_prop && !use_std) {
5310
0
    return true;
5311
0
  }
5312
5313
0
  for (auto const& config : configs) {
5314
0
    if (this->HaveCxxModuleSupport(config) != Cxx20SupportLevel::Supported) {
5315
0
      continue;
5316
0
    }
5317
5318
0
    cm::optional<cmStandardLevel> explicitLevel =
5319
0
      this->GetExplicitStandardLevel("CXX", config);
5320
0
    if (!explicitLevel || *explicitLevel < cxxStd23) {
5321
0
      continue;
5322
0
    }
5323
5324
0
    auto const stdLevel =
5325
0
      standardResolver.GetLevelString("CXX", *explicitLevel);
5326
0
    auto const cxxTargetName = cmStrCat("__CMAKE::CXX", stdLevel);
5327
5328
    // Create the __CMAKE::CXX## target if it doesn't already exist
5329
0
    if (!this->Makefile->FindTargetToUse(cxxTargetName) &&
5330
0
        !CreateCxxStdlibTarget(this->Makefile, this->LocalGenerator,
5331
0
                               this->GetName(), cxxTargetName, stdLevel,
5332
0
                               configs)) {
5333
0
      return false;
5334
0
    }
5335
5336
0
    this->Target->AppendProperty(
5337
0
      "LINK_LIBRARIES",
5338
0
      cmStrCat("$<BUILD_LOCAL_INTERFACE:$<$<CONFIG:", config,
5339
0
               ">:", cxxTargetName, ">>"));
5340
0
  }
5341
5342
  // Check the experimental feature here. A toolchain may have
5343
  // skipped the check in the toolchain preparation logic.
5344
0
  if (!cmExperimental::HasSupportEnabled(
5345
0
        *this->Makefile, cmExperimental::Feature::CxxImportStd)) {
5346
0
    this->Makefile->IssueMessage(
5347
0
      MessageType::FATAL_ERROR,
5348
0
      "Experimental `import std` support not enabled when detecting "
5349
0
      "toolchain; it must be set before `CXX` is enabled (usually a "
5350
0
      "`project()` call).");
5351
0
    return false;
5352
0
  }
5353
5354
0
  return true;
5355
0
}
5356
5357
bool cmGeneratorTarget::DiscoverSyntheticTargets(
5358
  cmSyntheticTargetCache& cache, std::string const& config,
5359
  cmGeneratorTarget const* bmiConsumer)
5360
0
{
5361
0
  std::vector<std::string> allConfigs =
5362
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
5363
0
  cmOptionalLinkImplementation impl;
5364
0
  this->ComputeLinkImplementationLibraries(config, impl, UseTo::Link);
5365
5366
0
  if (!bmiConsumer) {
5367
0
    bmiConsumer = this;
5368
0
  }
5369
5370
0
  cmCxxModuleUsageEffects usage(bmiConsumer);
5371
5372
0
  auto& SyntheticDeps = this->Configs[config].SyntheticDeps;
5373
5374
0
  for (auto const& entry : impl.Libraries) {
5375
0
    auto const* gt = entry.Target;
5376
0
    if (!gt || !gt->HaveCxx20ModuleSources()) {
5377
0
      continue;
5378
0
    }
5379
5380
    // Visual Studio generators do not currently support BMI-only compilation,
5381
    // so they can't generate synthetic targets. For consuming native modules,
5382
    // skip so that the native target is used directly. For imported modules,
5383
    // create the synth target anyway and diagnose later, in the VS generator.
5384
0
    if (!gt->IsImported() && this->GlobalGenerator->IsVisualStudio()) {
5385
0
      continue;
5386
0
    }
5387
5388
0
    cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
5389
0
    constexpr size_t HASH_TRUNCATION = 12;
5390
0
    auto dirhash =
5391
0
      hasher.HashString(gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
5392
0
    std::string safeName = gt->GetName();
5393
0
    cmSystemTools::ReplaceString(safeName, ":", "_");
5394
0
    auto targetIdent =
5395
0
      hasher.HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash()));
5396
0
    std::string targetName =
5397
0
      cmStrCat(safeName, "@synth_", targetIdent.substr(0, HASH_TRUNCATION));
5398
5399
    // Check the cache to see if this instance of the target has
5400
    // already been created.
5401
0
    auto cached = cache.CxxModuleTargets.find(targetName);
5402
0
    cmGeneratorTarget const* synthDep = nullptr;
5403
0
    if (cached == cache.CxxModuleTargets.end()) {
5404
0
      auto const* model = gt->Target;
5405
0
      auto* mf = gt->Makefile;
5406
0
      auto* lg = gt->GetLocalGenerator();
5407
0
      auto* tgt =
5408
0
        mf->AddSynthesizedTarget(cmStateEnums::INTERFACE_LIBRARY, targetName);
5409
5410
      // Copy relevant information from the existing target.
5411
5412
      // Copy policies to the target.
5413
0
      tgt->CopyPolicyStatuses(model);
5414
5415
      // Copy file sets.
5416
0
      {
5417
0
        for (auto const* gfs : gt->GetAllFileSets()) {
5418
0
          auto* newFs =
5419
0
            tgt
5420
0
              ->GetOrCreateFileSet(gfs->GetName(), gfs->GetType(),
5421
0
                                   cm::FileSetMetadata::Visibility::Public)
5422
0
              .first;
5423
0
          newFs->CopyEntries(gfs->GetFileSet());
5424
0
        }
5425
0
      }
5426
5427
      // Copy C++ module properties.
5428
0
      tgt->CopyCxxModulesEntries(model);
5429
5430
      // Copy other properties which may affect the C++ module BMI
5431
      // generation.
5432
0
      tgt->CopyCxxModulesProperties(model);
5433
5434
0
      tgt->AddLinkLibrary(*mf,
5435
0
                          cmStrCat("$<COMPILE_ONLY:", model->GetName(), '>'),
5436
0
                          GENERAL_LibraryType);
5437
5438
      // Apply usage requirements to the target.
5439
0
      usage.ApplyToTarget(tgt);
5440
5441
      // Create the generator target and attach it to the local generator.
5442
0
      auto gtp = cm::make_unique<cmGeneratorTarget>(tgt, lg);
5443
5444
0
      synthDep = gtp.get();
5445
0
      cache.CxxModuleTargets[targetName] = synthDep;
5446
5447
      // See `localGen->ComputeTargetCompileFeatures()` call in
5448
      // `cmGlobalGenerator::Compute` for where non-synthetic targets resolve
5449
      // this.
5450
0
      for (auto const& innerConfig : allConfigs) {
5451
0
        gtp->ComputeCompileFeatures(innerConfig);
5452
0
      }
5453
      // See `cmGlobalGenerator::ApplyCXXStdTargets` in
5454
      // `cmGlobalGenerator::Compute` for non-synthetic target resolutions.
5455
0
      if (!gtp->ApplyCXXStdTargets()) {
5456
0
        return false;
5457
0
      }
5458
5459
0
      gtp->DiscoverSyntheticTargets(cache, config, bmiConsumer);
5460
5461
0
      lg->AddGeneratorTarget(std::move(gtp));
5462
0
    } else {
5463
0
      synthDep = cached->second;
5464
0
    }
5465
5466
0
    SyntheticDeps[gt].push_back(synthDep);
5467
0
  }
5468
5469
0
  return true;
5470
0
}
5471
5472
cmGeneratorTarget::SyntheticDepsMap const& cmGeneratorTarget::GetSyntheticDeps(
5473
  std::string const& config) const
5474
0
{
5475
0
  return this->Configs[config].SyntheticDeps;
5476
0
}
5477
5478
bool cmGeneratorTarget::HasPackageReferences() const
5479
0
{
5480
0
  return this->IsInBuildSystem() &&
5481
0
    !this->GetProperty("VS_PACKAGE_REFERENCES")->empty();
5482
0
}
5483
5484
std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const
5485
0
{
5486
0
  cmList packageReferences;
5487
5488
0
  if (this->IsInBuildSystem()) {
5489
0
    if (cmValue vsPackageReferences =
5490
0
          this->GetProperty("VS_PACKAGE_REFERENCES")) {
5491
0
      packageReferences.assign(*vsPackageReferences);
5492
0
    }
5493
0
  }
5494
5495
0
  return std::move(packageReferences.data());
5496
0
}
5497
5498
std::string cmGeneratorTarget::GetPDBDirectory(std::string const& config) const
5499
0
{
5500
0
  if (OutputInfo const* info = this->GetOutputInfo(config)) {
5501
    // Return the directory in which the target will be built.
5502
0
    return info->PdbDir;
5503
0
  }
5504
0
  return "";
5505
0
}
5506
5507
bool cmGeneratorTarget::HasImplibGNUtoMS(std::string const& config) const
5508
0
{
5509
0
  return this->HasImportLibrary(config) && this->GetPropertyAsBool("GNUtoMS");
5510
0
}
5511
5512
bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
5513
                                         std::string const& gnuName,
5514
                                         std::string& out,
5515
                                         char const* newExt) const
5516
0
{
5517
0
  if (this->HasImplibGNUtoMS(config) && gnuName.size() > 6 &&
5518
0
      gnuName.substr(gnuName.size() - 6) == ".dll.a") {
5519
0
    out = cmStrCat(cm::string_view(gnuName).substr(0, gnuName.size() - 6),
5520
0
                   newExt ? newExt : ".lib");
5521
0
    return true;
5522
0
  }
5523
0
  return false;
5524
0
}
5525
5526
bool cmGeneratorTarget::HasContextDependentSources() const
5527
0
{
5528
0
  return this->SourcesAreContextDependent == Tribool::True;
5529
0
}
5530
5531
bool cmGeneratorTarget::IsExecutableWithExports() const
5532
0
{
5533
0
  return this->Target->IsExecutableWithExports();
5534
0
}
5535
5536
bool cmGeneratorTarget::IsSharedLibraryWithExports() const
5537
0
{
5538
0
  return this->Target->IsSharedLibraryWithExports();
5539
0
}
5540
5541
bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
5542
0
{
5543
0
  bool generate_Stubs = true;
5544
0
  if (this->GetGlobalGenerator()->IsXcode()) {
5545
    // take care of CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS variable
5546
    // as well as XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS property
5547
0
    if (cmValue propGenStubs =
5548
0
          this->GetProperty("XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) {
5549
0
      generate_Stubs = propGenStubs == "YES";
5550
0
    } else if (cmValue varGenStubs = this->Makefile->GetDefinition(
5551
0
                 "CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) {
5552
0
      generate_Stubs = varGenStubs == "YES";
5553
0
    }
5554
0
  }
5555
5556
0
  return (this->IsDLLPlatform() &&
5557
0
          (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
5558
0
           this->IsExecutableWithExports()) &&
5559
          // Assemblies which have only managed code do not have
5560
          // import libraries.
5561
0
          this->GetManagedType(config) != ManagedType::Managed) ||
5562
0
    (this->IsAIX() && this->IsExecutableWithExports()) ||
5563
0
    (this->Makefile->PlatformSupportsAppleTextStubs() &&
5564
0
     this->IsSharedLibraryWithExports() && generate_Stubs);
5565
0
}
5566
5567
bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const
5568
0
{
5569
0
  return this->HasImportLibrary(config) ||
5570
    // On DLL platforms we always generate the import library name
5571
    // just in case the sources have export markup.
5572
0
    (this->IsDLLPlatform() &&
5573
0
     (this->GetType() == cmStateEnums::EXECUTABLE ||
5574
0
      this->GetType() == cmStateEnums::MODULE_LIBRARY));
5575
0
}
5576
5577
bool cmGeneratorTarget::GetUseShortObjectNames(
5578
  cmStateEnums::IntermediateDirKind kind) const
5579
0
{
5580
0
  return this->LocalGenerator->UseShortObjectNames(kind);
5581
0
}
5582
5583
cmObjectLocations::UseShortPath
5584
cmGeneratorTarget::GetUseShortObjectNamesForInstall() const
5585
0
{
5586
0
  auto prop = this->Target->GetProperty("INSTALL_OBJECT_NAME_STRATEGY");
5587
0
  if (prop == "SHORT"_s) {
5588
0
    return cmObjectLocations::UseShortPath::Yes;
5589
0
  }
5590
0
  if (prop == "FULL"_s) {
5591
0
    return cmObjectLocations::UseShortPath::No;
5592
0
  }
5593
0
  if (prop.IsSet()) {
5594
0
    this->Makefile->IssueMessage(
5595
0
      MessageType::FATAL_ERROR,
5596
0
      cmStrCat("Property INSTALL_OBJECT_NAME_STRATEGY of target \"",
5597
0
               this->GetName(), "\" set to the unsupported strategy ", prop));
5598
0
  }
5599
0
  return cmObjectLocations::UseShortPath::No;
5600
0
}
5601
5602
std::string cmGeneratorTarget::GetSupportDirectory(
5603
  cmStateEnums::IntermediateDirKind kind) const
5604
0
{
5605
0
  cmLocalGenerator* lg = this->GetLocalGenerator();
5606
0
  auto targetDir = cmStrCat(lg->GetObjectOutputRoot(kind), '/',
5607
0
                            lg->GetTargetDirectory(this, kind));
5608
5609
0
#ifndef CMAKE_BOOTSTRAP
5610
0
  auto& tdr =
5611
0
    this->GetGlobalGenerator()->RegisterTargetDirectory(this, targetDir);
5612
0
  if (tdr.CollidesWith && !tdr.Warned) {
5613
0
    this->Makefile->IssueMessage(
5614
0
      MessageType::WARNING,
5615
0
      cmStrCat("The '", tdr.CollidesWith->GetName(), "' and '",
5616
0
               this->GetName(),
5617
0
               "' targets share an intermediate directory\n    ", targetDir,
5618
0
               "\nwhich may cause problems with the build graph. This project "
5619
0
               "is not compatible with the `SHORT` target intermediate "
5620
0
               "directory strategy. Possible remedies include: moving the "
5621
0
               "target into different directories or renaming a target."));
5622
0
    tdr.Warned = true;
5623
0
  }
5624
0
#endif
5625
5626
0
  return targetDir;
5627
0
}
5628
5629
std::string cmGeneratorTarget::GetCMFSupportDirectory(
5630
  cmStateEnums::IntermediateDirKind kind) const
5631
0
{
5632
0
  cmLocalGenerator* lg = this->GetLocalGenerator();
5633
0
  if (!lg->AlwaysUsesCMFPaths()) {
5634
0
    return cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/",
5635
0
                    lg->GetTargetDirectory(this, kind));
5636
0
  }
5637
0
  return cmStrCat(lg->GetObjectOutputRoot(kind), '/',
5638
0
                  lg->GetTargetDirectory(this, kind));
5639
0
}
5640
5641
bool cmGeneratorTarget::IsLinkable() const
5642
0
{
5643
0
  return (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
5644
0
          this->GetType() == cmStateEnums::SHARED_LIBRARY ||
5645
0
          this->GetType() == cmStateEnums::MODULE_LIBRARY ||
5646
0
          this->GetType() == cmStateEnums::UNKNOWN_LIBRARY ||
5647
0
          this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
5648
0
          this->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
5649
0
          this->IsExecutableWithExports());
5650
0
}
5651
5652
bool cmGeneratorTarget::HasLinkDependencyFile(std::string const& config) const
5653
0
{
5654
0
  if (this->GetType() != cmStateEnums::EXECUTABLE &&
5655
0
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5656
0
      this->GetType() != cmStateEnums::MODULE_LIBRARY) {
5657
0
    return false;
5658
0
  }
5659
5660
0
  if (this->Target->GetProperty("LINK_DEPENDS_NO_SHARED").IsOn()) {
5661
    // Do not use the linker dependency file because it includes shared
5662
    // libraries as well
5663
0
    return false;
5664
0
  }
5665
5666
0
  std::string const depsUseLinker{ "CMAKE_LINK_DEPENDS_USE_LINKER" };
5667
0
  auto linkLanguage = this->GetLinkerLanguage(config);
5668
0
  std::string const langDepsUseLinker{ cmStrCat("CMAKE_", linkLanguage,
5669
0
                                                "_LINK_DEPENDS_USE_LINKER") };
5670
5671
0
  return (!this->Makefile->IsDefinitionSet(depsUseLinker) ||
5672
0
          this->Makefile->IsOn(depsUseLinker)) &&
5673
0
    this->Makefile->IsOn(langDepsUseLinker);
5674
0
}
5675
5676
bool cmGeneratorTarget::IsFrameworkOnApple() const
5677
0
{
5678
0
  return this->Target->IsFrameworkOnApple();
5679
0
}
5680
5681
bool cmGeneratorTarget::IsArchivedAIXSharedLibrary() const
5682
0
{
5683
0
  return this->Target->IsArchivedAIXSharedLibrary();
5684
0
}
5685
5686
bool cmGeneratorTarget::IsImportedFrameworkFolderOnApple(
5687
  std::string const& config) const
5688
0
{
5689
0
  if (this->IsApple() && this->IsImported() &&
5690
0
      (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
5691
0
       this->GetType() == cmStateEnums::SHARED_LIBRARY ||
5692
0
       this->GetType() == cmStateEnums::UNKNOWN_LIBRARY)) {
5693
0
    std::string cfg = config;
5694
0
    if (cfg.empty() && this->GetGlobalGenerator()->IsXcode()) {
5695
      // FIXME(#25515): Remove the need for this workaround.
5696
      // The Xcode generator queries include directories without any
5697
      // specific configuration.  Pick one in case this target does
5698
      // not set either IMPORTED_LOCATION or IMPORTED_CONFIGURATIONS.
5699
0
      cfg =
5700
0
        this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)[0];
5701
0
    }
5702
0
    return cmSystemTools::IsPathToFramework(this->GetLocation(cfg));
5703
0
  }
5704
5705
0
  return false;
5706
0
}
5707
5708
bool cmGeneratorTarget::IsAppBundleOnApple() const
5709
0
{
5710
0
  return this->Target->IsAppBundleOnApple();
5711
0
}
5712
5713
bool cmGeneratorTarget::IsXCTestOnApple() const
5714
0
{
5715
0
  return (this->IsCFBundleOnApple() && this->GetPropertyAsBool("XCTEST"));
5716
0
}
5717
5718
bool cmGeneratorTarget::IsCFBundleOnApple() const
5719
0
{
5720
0
  return (this->GetType() == cmStateEnums::MODULE_LIBRARY && this->IsApple() &&
5721
0
          this->GetPropertyAsBool("BUNDLE"));
5722
0
}
5723
5724
cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
5725
  std::string const& propval) const
5726
0
{
5727
  // The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
5728
  // or only C++/CLI) does only depend on whether the property is an empty
5729
  // string or contains any value at all. In Visual Studio generators
5730
  // this propval is prepended with /clr[:] which results in:
5731
  //
5732
  // 1. propval does not exist: no /clr flag, unmanaged target, has import
5733
  //                            lib
5734
  // 2. empty propval:          add /clr as flag, mixed unmanaged/managed
5735
  //                            target, has import lib
5736
  // 3. netcore propval:        add /clr:netcore as flag, mixed
5737
  //                            unmanaged/managed target, has import lib.
5738
  // 4. any value (safe,pure):  add /clr:[propval] as flag, target with
5739
  //                            managed code only, no import lib
5740
0
  if (propval.empty() || propval == "netcore") {
5741
0
    return ManagedType::Mixed;
5742
0
  }
5743
0
  return ManagedType::Managed;
5744
0
}
5745
5746
cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
5747
  std::string const& config) const
5748
0
{
5749
  // Only libraries and executables can be managed targets.
5750
0
  if (this->GetType() > cmStateEnums::SHARED_LIBRARY) {
5751
0
    return ManagedType::Undefined;
5752
0
  }
5753
5754
0
  if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
5755
0
    return ManagedType::Native;
5756
0
  }
5757
5758
  // Check imported target.
5759
0
  if (this->IsImported()) {
5760
0
    if (cmGeneratorTarget::ImportInfo const* info =
5761
0
          this->GetImportInfo(config)) {
5762
0
      return info->Managed;
5763
0
    }
5764
0
    return ManagedType::Undefined;
5765
0
  }
5766
5767
  // Check for explicitly set clr target property.
5768
0
  if (cmValue clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
5769
0
    return this->CheckManagedType(*clr);
5770
0
  }
5771
5772
  // C# targets are always managed. This language specific check
5773
  // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
5774
  // has to be set manually for C# targets.
5775
0
  return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native;
5776
0
}
5777
5778
bool cmGeneratorTarget::AddHeaderSetVerification()
5779
0
{
5780
0
  for (bool const isInterface : { false, true }) {
5781
0
    if (!this->GetPropertyAsBool(isInterface ? "VERIFY_INTERFACE_HEADER_SETS"
5782
0
                                             : "VERIFY_PRIVATE_HEADER_SETS")) {
5783
0
      continue;
5784
0
    }
5785
5786
0
    if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
5787
0
        this->GetType() != cmStateEnums::SHARED_LIBRARY &&
5788
0
        (this->GetType() != cmStateEnums::MODULE_LIBRARY || isInterface) &&
5789
0
        this->GetType() != cmStateEnums::UNKNOWN_LIBRARY &&
5790
0
        this->GetType() != cmStateEnums::OBJECT_LIBRARY &&
5791
0
        this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
5792
0
        this->GetType() != cmStateEnums::EXECUTABLE) {
5793
0
      continue;
5794
0
    }
5795
5796
0
    char const* headerSetsProperty = isInterface
5797
0
      ? "INTERFACE_HEADER_SETS_TO_VERIFY"
5798
0
      : "PRIVATE_HEADER_SETS_TO_VERIFY";
5799
5800
0
    auto verifyValue = this->GetProperty(headerSetsProperty);
5801
0
    bool const all = verifyValue.IsEmpty();
5802
0
    std::set<std::string> verifySet;
5803
0
    if (!all) {
5804
0
      cmList verifyList{ verifyValue };
5805
0
      verifySet.insert(verifyList.begin(), verifyList.end());
5806
0
    }
5807
5808
0
    cmTarget* verifyTarget = nullptr;
5809
0
    std::string const verifyTargetName =
5810
0
      cmStrCat(this->GetName(),
5811
0
               isInterface ? "_verify_interface_header_sets"
5812
0
                           : "_verify_private_header_sets");
5813
5814
0
    char const* allVerifyTargetName = isInterface
5815
0
      ? "all_verify_interface_header_sets"
5816
0
      : "all_verify_private_header_sets";
5817
0
    cmTarget* allVerifyTarget =
5818
0
      this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
5819
0
        allVerifyTargetName, { cmStateEnums::TargetDomain::NATIVE });
5820
5821
0
    auto fileSetEntries = isInterface
5822
0
      ? this->GetInterfaceFileSets(cm::FileSetMetadata::HEADERS)
5823
0
      : this->GetFileSets(cm::FileSetMetadata::HEADERS);
5824
5825
0
    std::set<cmGeneratorFileSet const*> fileSets;
5826
0
    for (auto const& fileSet : fileSetEntries) {
5827
0
      if (all || verifySet.count(fileSet->GetName())) {
5828
0
        fileSets.insert(fileSet);
5829
0
        verifySet.erase(fileSet->GetName());
5830
0
      }
5831
0
    }
5832
5833
0
    if (isInterface) {
5834
0
      cmPolicies::PolicyStatus const cmp0209 = this->GetPolicyStatusCMP0209();
5835
0
      if (cmp0209 != cmPolicies::NEW &&
5836
0
          this->GetType() == cmStateEnums::EXECUTABLE &&
5837
0
          !this->GetPropertyAsBool("ENABLE_EXPORTS")) {
5838
0
        if (cmp0209 == cmPolicies::WARN && !fileSets.empty()) {
5839
0
          this->Makefile->IssueMessage(
5840
0
            MessageType::AUTHOR_WARNING,
5841
0
            cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0209),
5842
0
                     "\n"
5843
0
                     "Executable target \"",
5844
0
                     this->GetName(),
5845
0
                     "\" has interface header file sets, but it does not "
5846
0
                     "enable exports. Those headers would be verified under "
5847
0
                     "CMP0209 NEW behavior.\n"));
5848
0
        }
5849
0
        continue;
5850
0
      }
5851
0
    }
5852
5853
0
    if (!verifySet.empty()) {
5854
0
      this->Makefile->IssueMessage(
5855
0
        MessageType::FATAL_ERROR,
5856
0
        cmStrCat("Property ", headerSetsProperty, " of target \"",
5857
0
                 this->GetName(),
5858
0
                 "\" contained the following header sets that are nonexistent "
5859
0
                 "or not ",
5860
0
                 isInterface ? "INTERFACE" : "PRIVATE", ":\n  ",
5861
0
                 cmJoin(verifySet, "\n  ")));
5862
0
      return false;
5863
0
    }
5864
5865
0
    cm::optional<cm::optional<std::string>> defaultLanguage;
5866
0
    for (auto const* fileSet : fileSets) {
5867
0
      auto const& dirCges = fileSet->CompileDirectoryEntries();
5868
0
      auto const& fileCges = fileSet->CompileFileEntries();
5869
5870
0
      static auto const contextSensitive =
5871
0
        [](std::unique_ptr<cmCompiledGeneratorExpression> const& cge) {
5872
0
          return cge->GetHadContextSensitiveCondition();
5873
0
        };
5874
0
      bool dirCgesContextSensitive = false;
5875
0
      bool fileCgesContextSensitive = false;
5876
5877
0
      std::vector<std::string> dirs;
5878
0
      std::map<std::string, std::vector<std::string>> filesPerDir;
5879
0
      bool first = true;
5880
0
      for (auto const& config : this->Makefile->GetGeneratorConfigs(
5881
0
             cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) {
5882
0
        cm::GenEx::Context context(this->LocalGenerator, config);
5883
0
        if (first || dirCgesContextSensitive) {
5884
0
          dirs = fileSet->EvaluateDirectoryEntries(dirCges, context, this);
5885
0
          dirCgesContextSensitive =
5886
0
            std::any_of(dirCges.begin(), dirCges.end(), contextSensitive);
5887
0
        }
5888
0
        if (first || fileCgesContextSensitive) {
5889
0
          filesPerDir.clear();
5890
0
          for (auto const& fileCge : fileCges) {
5891
0
            fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, context,
5892
0
                                       this);
5893
0
            if (fileCge->GetHadContextSensitiveCondition()) {
5894
0
              fileCgesContextSensitive = true;
5895
0
            }
5896
0
          }
5897
0
        }
5898
5899
0
        for (auto const& files : filesPerDir) {
5900
0
          for (auto const& file : files.second) {
5901
0
            cm::optional<std::string> filenameOpt =
5902
0
              this->GenerateHeaderSetVerificationFile(
5903
0
                *this->Makefile->GetOrCreateSource(file), files.first,
5904
0
                verifyTargetName, defaultLanguage);
5905
0
            if (!filenameOpt) {
5906
0
              continue;
5907
0
            }
5908
0
            std::string filename = *filenameOpt;
5909
5910
0
            if (!verifyTarget) {
5911
0
              {
5912
0
                cmMakefile::PolicyPushPop polScope(this->Makefile);
5913
0
                this->Makefile->SetPolicy(cmPolicies::CMP0119,
5914
0
                                          cmPolicies::NEW);
5915
0
                verifyTarget = this->Makefile->AddLibrary(
5916
0
                  verifyTargetName, cmStateEnums::OBJECT_LIBRARY, {}, true);
5917
0
              }
5918
5919
0
              if (isInterface) {
5920
                // Link to the original target so that we pick up its
5921
                // interface compile options just like a consumer would.
5922
                // This also ensures any generated headers in the original
5923
                // target will be created.
5924
0
                verifyTarget->AddLinkLibrary(
5925
0
                  *this->Makefile, this->GetName(),
5926
0
                  cmTargetLinkLibraryType::GENERAL_LibraryType);
5927
0
              } else {
5928
                // For private file sets, we need to simulate compiling the
5929
                // same way as the original target. That includes linking to
5930
                // the same things so we pick up the same transitive
5931
                // properties. For the <LANG>_... properties, we don't care if
5932
                // we set them for languages this target won't eventually use.
5933
                // Copy language-standard properties for all supported
5934
                // languages. We don't care if we set properties for languages
5935
                // this target won't eventually use.
5936
0
                static std::array<std::string, 19> const propertiesToCopy{ {
5937
0
                  "COMPILE_DEFINITIONS",    "COMPILE_FEATURES",
5938
0
                  "COMPILE_FLAGS",          "COMPILE_OPTIONS",
5939
0
                  "DEFINE_SYMBOL",          "INCLUDE_DIRECTORIES",
5940
0
                  "LINK_LIBRARIES",         "C_STANDARD",
5941
0
                  "C_STANDARD_REQUIRED",    "C_EXTENSIONS",
5942
0
                  "CXX_STANDARD",           "CXX_STANDARD_REQUIRED",
5943
0
                  "CXX_EXTENSIONS",         "OBJC_STANDARD",
5944
0
                  "OBJC_STANDARD_REQUIRED", "OBJC_EXTENSIONS",
5945
0
                  "OBJCXX_STANDARD",        "OBJCXX_STANDARD_REQUIRED",
5946
0
                  "OBJCXX_EXTENSIONS",
5947
0
                } };
5948
0
                for (std::string const& prop : propertiesToCopy) {
5949
0
                  cmValue propValue = this->Target->GetProperty(prop);
5950
0
                  if (propValue.IsSet()) {
5951
0
                    verifyTarget->SetProperty(prop, propValue);
5952
0
                  }
5953
0
                }
5954
                // The original target might have generated headers. Since
5955
                // we only link to the original target for compilation,
5956
                // there's nothing to force such generation to happen yet.
5957
                // Our verify target must depend on the original target to
5958
                // ensure such generated files will be created.
5959
0
                verifyTarget->AddUtility(this->GetName(), false,
5960
0
                                         this->Makefile);
5961
0
                verifyTarget->AddCodegenDependency(this->GetName());
5962
0
              }
5963
5964
0
              verifyTarget->SetProperty("AUTOMOC", "OFF");
5965
0
              verifyTarget->SetProperty("AUTORCC", "OFF");
5966
0
              verifyTarget->SetProperty("AUTOUIC", "OFF");
5967
0
              verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
5968
0
              verifyTarget->SetProperty("UNITY_BUILD", "OFF");
5969
0
              verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF");
5970
5971
0
              if (isInterface) {
5972
0
                verifyTarget->FinalizeTargetConfiguration(
5973
0
                  this->Makefile->GetCompileDefinitionsEntries());
5974
0
              } else {
5975
                // Private verification only needs to add the directory scope
5976
                // definitions here
5977
0
                for (auto const& def :
5978
0
                     this->Makefile->GetCompileDefinitionsEntries()) {
5979
0
                  verifyTarget->InsertCompileDefinition(def);
5980
0
                }
5981
0
              }
5982
5983
0
              if (!allVerifyTarget) {
5984
0
                allVerifyTarget =
5985
0
                  this->GlobalGenerator->GetMakefiles()
5986
0
                    .front()
5987
0
                    ->AddNewUtilityTarget(allVerifyTargetName, true);
5988
0
              }
5989
5990
0
              allVerifyTarget->AddUtility(verifyTargetName, false);
5991
0
            }
5992
5993
0
            if (fileCgesContextSensitive) {
5994
0
              filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, '>');
5995
0
            }
5996
0
            verifyTarget->AddSource(filename);
5997
0
          }
5998
0
        }
5999
6000
0
        if (!dirCgesContextSensitive && !fileCgesContextSensitive) {
6001
0
          break;
6002
0
        }
6003
0
        first = false;
6004
0
      }
6005
0
    }
6006
6007
0
    if (verifyTarget) {
6008
0
      this->LocalGenerator->AddGeneratorTarget(
6009
0
        cm::make_unique<cmGeneratorTarget>(verifyTarget,
6010
0
                                           this->LocalGenerator));
6011
0
    }
6012
0
  }
6013
6014
0
  return true;
6015
0
}
6016
6017
cm::optional<std::string> cmGeneratorTarget::GenerateHeaderSetVerificationFile(
6018
  cmSourceFile& source, std::string const& dir,
6019
  std::string const& verifyTargetName,
6020
  cm::optional<cm::optional<std::string>>& defaultLanguage) const
6021
0
{
6022
0
  if (source.GetPropertyAsBool("SKIP_LINTING")) {
6023
0
    return cm::nullopt;
6024
0
  }
6025
6026
0
  cm::optional<std::string> language =
6027
0
    this->ResolveHeaderLanguage(source, defaultLanguage);
6028
0
  if (!language) {
6029
0
    return cm::nullopt;
6030
0
  }
6031
6032
0
  std::string headerFilename = dir;
6033
0
  if (!headerFilename.empty()) {
6034
0
    headerFilename += '/';
6035
0
  }
6036
0
  headerFilename += source.GetLocation().GetName();
6037
6038
0
  return this->GenerateStubForLanguage(*language, headerFilename,
6039
0
                                       verifyTargetName, source);
6040
0
}
6041
6042
cm::optional<std::string> cmGeneratorTarget::ResolveHeaderLanguage(
6043
  cmSourceFile& source,
6044
  cm::optional<cm::optional<std::string>>& defaultLanguage) const
6045
0
{
6046
0
  static std::array<cm::string_view, 4> const supportedLangs{ {
6047
0
    "C",
6048
0
    "CXX",
6049
0
    "OBJC",
6050
0
    "OBJCXX",
6051
0
  } };
6052
0
  auto isSupported = [](cm::string_view lang) -> bool {
6053
0
    return std::find(supportedLangs.begin(), supportedLangs.end(), lang) !=
6054
0
      supportedLangs.end();
6055
0
  };
6056
6057
  // If the source has an explicit language, validate and return it.
6058
0
  std::string language = source.GetOrDetermineLanguage();
6059
0
  if (!language.empty()) {
6060
0
    if (!isSupported(language)) {
6061
0
      return cm::nullopt;
6062
0
    }
6063
0
    return cm::optional<std::string>(std::move(language));
6064
0
  }
6065
6066
  /*
6067
    Compute and cache the default language for unlanguaged headers.
6068
    The lattice join is run once per file set, not once per header.
6069
    Lattice:   OBJCXX
6070
              /      \
6071
            CXX      OBJC
6072
              \      /
6073
                 C
6074
  */
6075
0
  if (!defaultLanguage) {
6076
0
    std::set<std::string> langs;
6077
0
    for (AllConfigSource const& tgtSource : this->GetAllConfigSources()) {
6078
0
      std::string const& lang = tgtSource.Source->GetOrDetermineLanguage();
6079
0
      if (isSupported(lang)) {
6080
0
        langs.insert(lang);
6081
0
      }
6082
0
    }
6083
0
    if (langs.empty()) {
6084
0
      std::vector<std::string> languagesVector;
6085
0
      this->GlobalGenerator->GetEnabledLanguages(languagesVector);
6086
0
      for (std::string const& lang : languagesVector) {
6087
0
        if (isSupported(lang)) {
6088
0
          langs.insert(lang);
6089
0
        }
6090
0
      }
6091
0
    }
6092
6093
0
    cm::optional<std::string> resolved;
6094
0
    if (langs.count("OBJCXX") || (langs.count("CXX") && langs.count("OBJC"))) {
6095
0
      resolved = "OBJCXX"; // promote
6096
0
    } else if (langs.count("CXX")) {
6097
0
      resolved = "CXX";
6098
0
    } else if (langs.count("OBJC")) {
6099
0
      resolved = "OBJC";
6100
0
    } else if (langs.count("C")) {
6101
0
      resolved = "C";
6102
0
    }
6103
0
    defaultLanguage = resolved;
6104
0
  }
6105
6106
0
  return *defaultLanguage;
6107
0
}
6108
6109
cm::optional<std::string> cmGeneratorTarget::GenerateStubForLanguage(
6110
  std::string const& language, std::string const& headerFilename,
6111
  std::string const& verifyTargetName, cmSourceFile& source) const
6112
0
{
6113
0
  static std::array<std::pair<cm::string_view, cm::string_view>, 4> const
6114
0
    langToExt = { {
6115
0
      { "C", ".c" },
6116
0
      { "CXX", ".cxx" },
6117
0
      { "OBJC", ".m" },
6118
0
      { "OBJCXX", ".mm" },
6119
0
    } };
6120
6121
  // NOLINTNEXTLINE(readability-qualified-auto)
6122
0
  auto const it =
6123
0
    std::find_if(langToExt.begin(), langToExt.end(),
6124
0
                 [&](std::pair<cm::string_view, cm::string_view> const& p) {
6125
0
                   return p.first == language;
6126
0
                 });
6127
0
  if (it == langToExt.end()) {
6128
0
    return cm::nullopt;
6129
0
  }
6130
6131
0
  std::string filename =
6132
0
    cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
6133
0
             verifyTargetName, '/', headerFilename, it->second);
6134
6135
0
  cmSourceFile* verificationSource =
6136
0
    this->Makefile->GetOrCreateSource(filename);
6137
0
  source.SetSpecialSourceType(
6138
0
    cmSourceFile::SpecialSourceType::HeaderSetVerificationSource);
6139
0
  verificationSource->SetProperty("LANGUAGE", language);
6140
6141
0
  cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename));
6142
6143
0
  cmGeneratedFileStream fout(filename);
6144
0
  fout.SetCopyIfDifferent(true);
6145
  // The IWYU "associated" pragma tells include-what-you-use to
6146
  // consider the headerFile as part of the entire language
6147
  // unit within include-what-you-use and as a result allows
6148
  // one to get IWYU advice for headers.
6149
  // Also suppress clang-tidy include checks in generated code.
6150
0
  fout
6151
0
    << "/* NOLINTNEXTLINE(misc-header-include-cycle,misc-include-cleaner) */\n"
6152
0
    << "#include <" << headerFilename << "> /* IWYU pragma: associated */\n";
6153
0
  fout.close();
6154
6155
0
  return cm::optional<std::string>(std::move(filename));
6156
0
}
6157
6158
std::string cmGeneratorTarget::GetImportedXcFrameworkPath(
6159
  std::string const& config) const
6160
0
{
6161
0
  if (!(this->IsApple() && this->IsImported() &&
6162
0
        (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
6163
0
         this->GetType() == cmStateEnums::STATIC_LIBRARY ||
6164
0
         this->GetType() == cmStateEnums::UNKNOWN_LIBRARY))) {
6165
0
    return {};
6166
0
  }
6167
6168
0
  std::string desiredConfig = config;
6169
0
  if (config.empty()) {
6170
0
    desiredConfig = "NOCONFIG";
6171
0
  }
6172
6173
0
  std::string result;
6174
6175
0
  cmValue loc = nullptr;
6176
0
  cmValue imp = nullptr;
6177
0
  std::string suffix;
6178
6179
0
  if (this->Target->GetMappedConfig(desiredConfig, loc, imp, suffix)) {
6180
0
    if (loc) {
6181
0
      result = *loc;
6182
0
    } else {
6183
0
      std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
6184
0
      if (cmValue configLocation = this->GetProperty(impProp)) {
6185
0
        result = *configLocation;
6186
0
      } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) {
6187
0
        result = *location;
6188
0
      }
6189
0
    }
6190
6191
0
    if (cmSystemTools::IsPathToXcFramework(result)) {
6192
0
      return result;
6193
0
    }
6194
0
  }
6195
6196
0
  return {};
6197
0
}
6198
6199
bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
6200
0
{
6201
0
  auto sources = this->GetSourceFiles(config);
6202
0
  bool const have_direct = std::any_of(
6203
0
    sources.begin(), sources.end(), [](BT<cmSourceFile*> const& sf) -> bool {
6204
0
      return sf.Value->GetLanguage() == "Fortran"_s;
6205
0
    });
6206
0
  bool have_via_target_objects = false;
6207
0
  if (!have_direct) {
6208
0
    auto const sourceObjectLibraries = this->GetSourceObjectLibraries(config);
6209
0
    have_via_target_objects =
6210
0
      std::any_of(sourceObjectLibraries.begin(), sourceObjectLibraries.end(),
6211
0
                  [&config](cmGeneratorTarget const* tgt) -> bool {
6212
0
                    return tgt->HaveFortranSources(config);
6213
0
                  });
6214
0
  }
6215
0
  return have_direct || have_via_target_objects;
6216
0
}
6217
6218
bool cmGeneratorTarget::HaveFortranSources() const
6219
0
{
6220
0
  auto sources = this->GetAllConfigSources();
6221
0
  bool const have_direct = std::any_of(
6222
0
    sources.begin(), sources.end(), [](AllConfigSource const& sf) -> bool {
6223
0
      return sf.Source->GetLanguage() == "Fortran"_s;
6224
0
    });
6225
0
  bool have_via_target_objects = false;
6226
0
  if (!have_direct) {
6227
0
    std::vector<std::string> configs =
6228
0
      this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
6229
0
    for (auto const& config : configs) {
6230
0
      auto const sourceObjectLibraries =
6231
0
        this->GetSourceObjectLibraries(config);
6232
0
      have_via_target_objects =
6233
0
        std::any_of(sourceObjectLibraries.begin(), sourceObjectLibraries.end(),
6234
0
                    [&config](cmGeneratorTarget const* tgt) -> bool {
6235
0
                      return tgt->HaveFortranSources(config);
6236
0
                    });
6237
0
      if (have_via_target_objects) {
6238
0
        break;
6239
0
      }
6240
0
    }
6241
0
  }
6242
0
  return have_direct || have_via_target_objects;
6243
0
}
6244
6245
bool cmGeneratorTarget::HaveCxx20ModuleSources() const
6246
0
{
6247
0
  auto const& fileSets = this->GetAllFileSets();
6248
0
  return std::any_of(fileSets.begin(), fileSets.end(),
6249
0
                     [](cmGeneratorFileSet const* file_set) -> bool {
6250
0
                       auto const& fs_type = file_set->GetType();
6251
0
                       return fs_type == cm::FileSetMetadata::CXX_MODULES;
6252
0
                     });
6253
0
}
6254
6255
cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
6256
  std::string const& config) const
6257
0
{
6258
0
  auto const* state = this->Makefile->GetState();
6259
0
  if (!state->GetLanguageEnabled("CXX")) {
6260
0
    return Cxx20SupportLevel::MissingCxx;
6261
0
  }
6262
6263
0
  cmValue standardDefault =
6264
0
    this->Makefile->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
6265
0
  if (!standardDefault || standardDefault->empty()) {
6266
    // We do not know any meaningful C++ standard levels for this compiler.
6267
0
    return Cxx20SupportLevel::NoCxx20;
6268
0
  }
6269
6270
0
  cmStandardLevelResolver standardResolver(this->Makefile);
6271
0
  cmStandardLevel const cxxStd20 =
6272
0
    *standardResolver.LanguageStandardLevel("CXX", "20");
6273
0
  cm::optional<cmStandardLevel> explicitLevel =
6274
0
    this->GetExplicitStandardLevel("CXX", config);
6275
0
  if (!explicitLevel || *explicitLevel < cxxStd20) {
6276
0
    return Cxx20SupportLevel::NoCxx20;
6277
0
  }
6278
6279
0
  cmValue scandepRule =
6280
0
    this->Makefile->GetDefinition("CMAKE_CXX_SCANDEP_SOURCE");
6281
0
  if (!scandepRule) {
6282
0
    return Cxx20SupportLevel::MissingRule;
6283
0
  }
6284
0
  return Cxx20SupportLevel::Supported;
6285
0
}
6286
6287
void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
6288
0
{
6289
0
  bool haveScannableSources = false;
6290
6291
  // Check for `CXX_MODULE*` file sets and a lack of support.
6292
0
  if (this->HaveCxx20ModuleSources()) {
6293
0
    haveScannableSources = true;
6294
0
  }
6295
6296
0
  if (!haveScannableSources) {
6297
    // Check to see if there are regular sources that have requested scanning.
6298
0
    auto sources = this->GetSourceFiles(config);
6299
0
    for (auto const& source : sources) {
6300
0
      auto const* sf = source.Value;
6301
0
      auto const& lang = sf->GetLanguage();
6302
0
      if (lang != "CXX"_s) {
6303
0
        continue;
6304
0
      }
6305
      // Ignore sources which do not need dyndep.
6306
0
      if (this->NeedDyndepForSource(lang, config, sf)) {
6307
0
        haveScannableSources = true;
6308
0
      }
6309
0
    }
6310
0
  }
6311
6312
  // If there isn't anything scannable, ignore it.
6313
0
  if (!haveScannableSources) {
6314
0
    return;
6315
0
  }
6316
6317
  // If the generator doesn't support modules at all, error that we have
6318
  // sources that require the support.
6319
0
  if (!this->GetGlobalGenerator()->CheckCxxModuleSupport(
6320
0
        cmGlobalGenerator::CxxModuleSupportQuery::Expected)) {
6321
0
    this->Makefile->IssueMessage(
6322
0
      MessageType::FATAL_ERROR,
6323
0
      cmStrCat("The target named \"", this->GetName(),
6324
0
               "\" has C++ sources that may use modules, but modules are not "
6325
0
               "supported by this generator:\n  ",
6326
0
               this->GetGlobalGenerator()->GetName(),
6327
0
               "\n"
6328
0
               "Modules are supported only by Ninja, Ninja Multi-Config, "
6329
0
               "and Visual Studio generators for VS 17.4 and newer.  "
6330
0
               "See the cmake-cxxmodules(7) manual for details.  "
6331
0
               "Use the CMAKE_CXX_SCAN_FOR_MODULES variable to enable or "
6332
0
               "disable scanning."));
6333
0
    return;
6334
0
  }
6335
6336
0
  switch (this->HaveCxxModuleSupport(config)) {
6337
0
    case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx:
6338
0
      this->Makefile->IssueMessage(
6339
0
        MessageType::FATAL_ERROR,
6340
0
        cmStrCat("The target named \"", this->GetName(),
6341
0
                 "\" has C++ sources that use modules, but the \"CXX\" "
6342
0
                 "language has not been enabled."));
6343
0
      break;
6344
0
    case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: {
6345
0
      cmStandardLevelResolver standardResolver(this->Makefile);
6346
0
      auto effStandard =
6347
0
        standardResolver.GetEffectiveStandard(this, "CXX", config);
6348
0
      if (effStandard.empty()) {
6349
0
        effStandard = "; no C++ standard found";
6350
0
      } else {
6351
0
        effStandard = cmStrCat("; found \"cxx_std_", effStandard, '"');
6352
0
      }
6353
0
      this->Makefile->IssueMessage(
6354
0
        MessageType::FATAL_ERROR,
6355
0
        cmStrCat(
6356
0
          "The target named \"", this->GetName(),
6357
0
          "\" has C++ sources that use modules, but does not include "
6358
0
          "\"cxx_std_20\" (or newer) among its `target_compile_features`",
6359
0
          effStandard, '.'));
6360
0
    } break;
6361
0
    case cmGeneratorTarget::Cxx20SupportLevel::MissingRule: {
6362
0
      this->Makefile->IssueMessage(
6363
0
        MessageType::FATAL_ERROR,
6364
0
        cmStrCat("The target named \"", this->GetName(),
6365
0
                 "\" has C++ sources that may use modules, but the compiler "
6366
0
                 "does not provide a way to discover the import graph "
6367
0
                 "dependencies.  See the cmake-cxxmodules(7) manual for "
6368
0
                 "details.  Use the CMAKE_CXX_SCAN_FOR_MODULES variable to "
6369
0
                 "enable or disable scanning."));
6370
0
    } break;
6371
0
    case cmGeneratorTarget::Cxx20SupportLevel::Supported:
6372
      // All is well.
6373
0
      break;
6374
0
  }
6375
0
}
6376
6377
bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang,
6378
                                             std::string const& config) const
6379
0
{
6380
0
  if (lang != "CXX"_s) {
6381
0
    return false;
6382
0
  }
6383
0
  return this->HaveCxxModuleSupport(config) == Cxx20SupportLevel::Supported &&
6384
0
    this->GetGlobalGenerator()->CheckCxxModuleSupport(
6385
0
      cmGlobalGenerator::CxxModuleSupportQuery::Inspect);
6386
0
}
6387
6388
bool cmGeneratorTarget::NeedDyndep(std::string const& lang,
6389
                                   std::string const& config) const
6390
0
{
6391
0
  return lang == "Fortran"_s || this->NeedCxxModuleSupport(lang, config);
6392
0
}
6393
6394
bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang,
6395
                                            std::string const& config,
6396
                                            cmSourceFile const* sf) const
6397
0
{
6398
  // Fortran always needs to be scanned.
6399
0
  if (lang == "Fortran"_s) {
6400
0
    return true;
6401
0
  }
6402
  // Only C++ code needs scanned otherwise.
6403
0
  if (lang != "CXX"_s) {
6404
0
    return false;
6405
0
  }
6406
6407
  // Any file in `CXX_MODULES` file sets need scanned (it being `CXX` is
6408
  // enforced elsewhere).
6409
0
  auto const* fs = this->GetFileSetForSource(config, sf);
6410
0
  if (fs && fs->GetType() == cm::FileSetMetadata::CXX_MODULES) {
6411
0
    return true;
6412
0
  }
6413
6414
0
  auto targetDyndep = this->NeedCxxDyndep(config);
6415
0
  if (targetDyndep == CxxModuleSupport::Unavailable) {
6416
0
    return false;
6417
0
  }
6418
0
  auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES");
6419
0
  if (sfProp.IsSet()) {
6420
0
    return sfProp.IsOn();
6421
0
  }
6422
0
  return targetDyndep == CxxModuleSupport::Enabled;
6423
0
}
6424
6425
cmGeneratorTarget::CxxModuleSupport cmGeneratorTarget::NeedCxxDyndep(
6426
  std::string const& config) const
6427
0
{
6428
0
  bool haveRule = false;
6429
0
  switch (this->HaveCxxModuleSupport(config)) {
6430
0
    case Cxx20SupportLevel::MissingCxx:
6431
0
    case Cxx20SupportLevel::NoCxx20:
6432
0
      return CxxModuleSupport::Unavailable;
6433
0
    case Cxx20SupportLevel::MissingRule:
6434
0
      break;
6435
0
    case Cxx20SupportLevel::Supported:
6436
0
      haveRule = true;
6437
0
      break;
6438
0
  }
6439
0
  bool haveGeneratorSupport =
6440
0
    this->GetGlobalGenerator()->CheckCxxModuleSupport(
6441
0
      cmGlobalGenerator::CxxModuleSupportQuery::Inspect);
6442
0
  auto const tgtProp = this->GetProperty("CXX_SCAN_FOR_MODULES");
6443
0
  if (tgtProp.IsSet()) {
6444
0
    return tgtProp.IsOn() ? CxxModuleSupport::Enabled
6445
0
                          : CxxModuleSupport::Disabled;
6446
0
  }
6447
6448
0
  CxxModuleSupport policyAnswer = CxxModuleSupport::Unavailable;
6449
0
  switch (this->GetPolicyStatusCMP0155()) {
6450
0
    case cmPolicies::WARN:
6451
0
    case cmPolicies::OLD:
6452
      // The OLD behavior is to not scan the source.
6453
0
      policyAnswer = CxxModuleSupport::Disabled;
6454
0
      break;
6455
0
    case cmPolicies::NEW:
6456
      // The NEW behavior is to scan the source if the compiler supports
6457
      // scanning and the generator supports it.
6458
0
      if (haveRule && haveGeneratorSupport) {
6459
0
        policyAnswer = CxxModuleSupport::Enabled;
6460
0
      } else {
6461
0
        policyAnswer = CxxModuleSupport::Disabled;
6462
0
      }
6463
0
      break;
6464
0
  }
6465
0
  return policyAnswer;
6466
0
}
6467
6468
bool cmGeneratorTarget::HasFileSets() const
6469
0
{
6470
0
  return !this->FileSets->Empty();
6471
0
}
6472
6473
std::vector<cmGeneratorFileSet const*> const&
6474
cmGeneratorTarget::GetAllFileSets() const
6475
0
{
6476
0
  return this->FileSets->GetAllFileSets();
6477
0
}
6478
6479
std::vector<cmGeneratorFileSet const*> const& cmGeneratorTarget::GetFileSets(
6480
  cm::string_view type) const
6481
0
{
6482
0
  return this->FileSets->GetFileSets(type);
6483
0
}
6484
std::vector<cmGeneratorFileSet const*> const&
6485
cmGeneratorTarget::GetInterfaceFileSets(cm::string_view type) const
6486
0
{
6487
0
  return this->FileSets->GetInterfaceFileSets(type);
6488
0
}
6489
6490
cmGeneratorFileSet const* cmGeneratorTarget::GetFileSet(
6491
  std::string const& name) const
6492
0
{
6493
0
  return this->FileSets->GetFileSet(name);
6494
0
}
6495
6496
cmGeneratorFileSet const* cmGeneratorTarget::GetFileSetForSource(
6497
  std::string const& config, cmSourceFile const* sf) const
6498
0
{
6499
0
  return this->FileSets->GetFileSetForSource(config, sf);
6500
0
}
6501
6502
std::string cmGeneratorTarget::BuildDatabasePath(
6503
  std::string const& lang, std::string const& config) const
6504
0
{
6505
  // Check to see if the target wants it.
6506
0
  if (!this->GetPropertyAsBool("EXPORT_BUILD_DATABASE")) {
6507
0
    return {};
6508
0
  }
6509
0
  if (!cmExperimental::HasSupportEnabled(
6510
0
        *this->Makefile, cmExperimental::Feature::ExportBuildDatabase)) {
6511
0
    return {};
6512
0
  }
6513
  // Check to see if the generator supports it.
6514
0
  if (!this->GetGlobalGenerator()->SupportsBuildDatabase()) {
6515
0
    return {};
6516
0
  }
6517
6518
0
  if (this->GetGlobalGenerator()->IsMultiConfig()) {
6519
0
    return cmStrCat(this->GetSupportDirectory(), '/', config, '/', lang,
6520
0
                    "_build_database.json");
6521
0
  }
6522
6523
0
  return cmStrCat(this->GetSupportDirectory(), '/', lang,
6524
0
                  "_build_database.json");
6525
0
}
6526
6527
std::string cmGeneratorTarget::GetSwiftModuleName() const
6528
0
{
6529
0
  return this->GetPropertyOrDefault("Swift_MODULE_NAME", this->GetName());
6530
0
}
6531
6532
std::string cmGeneratorTarget::GetSwiftModuleFileName() const
6533
0
{
6534
0
  std::string moduleFilename = this->GetPropertyOrDefault(
6535
0
    "Swift_MODULE", this->GetSwiftModuleName() + ".swiftmodule");
6536
0
  if (this->GetPolicyStatusCMP0195() == cmPolicies::NEW) {
6537
0
    if (cmValue moduleTriple =
6538
0
          this->Makefile->GetDefinition("CMAKE_Swift_MODULE_TRIPLE")) {
6539
0
      moduleFilename = cmStrCat(std::move(moduleFilename), '/', *moduleTriple,
6540
0
                                ".swiftmodule");
6541
0
    }
6542
0
  }
6543
0
  return moduleFilename;
6544
0
}
6545
6546
std::string cmGeneratorTarget::GetSwiftModuleDirectory(
6547
  std::string const& config) const
6548
0
{
6549
  // This is like the *_OUTPUT_DIRECTORY properties except that we don't have a
6550
  // separate per-configuration target property.
6551
  //
6552
  // The property expands generator expressions. Multi-config generators append
6553
  // a per-configuration subdirectory to the specified directory unless a
6554
  // generator expression is used.
6555
0
  bool appendConfigDir = true;
6556
0
  std::string moduleDirectory;
6557
6558
0
  if (cmValue value = this->GetProperty("Swift_MODULE_DIRECTORY")) {
6559
0
    moduleDirectory = cmGeneratorExpression::Evaluate(
6560
0
      *value, this->LocalGenerator, config, this);
6561
0
    appendConfigDir = *value == moduleDirectory;
6562
0
  }
6563
0
  if (moduleDirectory.empty()) {
6564
0
    moduleDirectory = this->LocalGenerator->GetCurrentBinaryDirectory();
6565
0
  }
6566
0
  if (appendConfigDir) {
6567
0
    this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
6568
0
      "/", config, "", moduleDirectory);
6569
0
  }
6570
0
  return moduleDirectory;
6571
0
}
6572
6573
std::string cmGeneratorTarget::GetSwiftModulePath(
6574
  std::string const& config) const
6575
0
{
6576
0
  return cmStrCat(this->GetSwiftModuleDirectory(config), '/',
6577
0
                  this->GetSwiftModuleFileName());
6578
0
}
6579
6580
std::string cmGeneratorTarget::GetPropertyOrDefault(
6581
  std::string const& property, std::string defaultValue) const
6582
0
{
6583
0
  if (cmValue name = this->GetProperty(property)) {
6584
0
    return *name;
6585
0
  }
6586
0
  return defaultValue;
6587
0
}