Coverage Report

Created: 2026-10-28 06:38

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