cmGeneratorTarget.cxx 225 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3
4
#include "cmGeneratorTarget.h"

5
#include <algorithm>
6
7
#include <cassert>
#include <cerrno>
8
#include <cstddef>
9
10
11
#include <cstdio>
#include <cstdlib>
#include <cstring>
12
#include <iterator>
13
#include <memory>
14
#include <sstream>
15
#include <unordered_set>
wahikihiki's avatar
wahikihiki committed
16
#include <utility>
17

18
19
#include <cm/string_view>

20
21
22
23
#include <queue>

#include "cmsys/RegularExpression.hxx"

24
#include "cmAlgorithms.h"
25
#include "cmComputeLinkInformation.h"
26
#include "cmCustomCommand.h"
27
#include "cmCustomCommandGenerator.h"
28
#include "cmCustomCommandLines.h"
29
#include "cmGeneratedFileStream.h"
30
#include "cmGeneratorExpression.h"
31
#include "cmGeneratorExpressionContext.h"
32
#include "cmGeneratorExpressionDAGChecker.h"
33
#include "cmGeneratorExpressionNode.h"
34
35
36
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
37
#include "cmMessageType.h"
38
#include "cmPropertyMap.h"
39
#include "cmRange.h"
40
#include "cmSourceFile.h"
41
#include "cmSourceFileLocation.h"
42
#include "cmSourceFileLocationKind.h"
43
#include "cmState.h"
44
#include "cmStringAlgorithms.h"
45
#include "cmSystemTools.h"
46
#include "cmTarget.h"
47
#include "cmTargetLinkLibraryType.h"
48
#include "cmTargetPropertyComputer.h"
49
#include "cmake.h"
50

51
class cmMessenger;
52

53
54
55
56
57
58
59
60
61
template <>
const char* cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
  cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
  cmListFileBacktrace const& /* context */)
{
  return tgt->GetSourcesProperty();
}

template <>
62
63
64
const char*
cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
  cmGeneratorTarget const* tgt)
65
66
67
68
69
70
71
72
73
74
75
{
  return tgt->GetLocation("");
}

template <>
const char* cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
  cmGeneratorTarget const* tgt, const std::string& config)
{
  return tgt->GetLocation(config);
}

76
77
class cmGeneratorTarget::TargetPropertyEntry
{
78
protected:
79
  static cmLinkImplItem NoLinkImplItem;
80

81
public:
82
83
  TargetPropertyEntry(cmLinkImplItem const& item)
    : LinkImplItem(item)
84
85
  {
  }
86
87
88
  virtual ~TargetPropertyEntry() = default;

  virtual const std::string& Evaluate(
89
    cmLocalGenerator* lg, const std::string& config,
90
91
    cmGeneratorTarget const* headTarget,
    cmGeneratorExpressionDAGChecker* dagChecker,
92
    std::string const& language) const = 0;
93
94
95
96
97

  virtual cmListFileBacktrace GetBacktrace() const = 0;
  virtual std::string const& GetInput() const = 0;
  virtual bool GetHadContextSensitiveCondition() const { return false; }

98
99
100
101
  cmLinkImplItem const& LinkImplItem;
};
cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;

102
103
104
105
106
107
108
109
110
111
class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
{
public:
  TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
                           cmLinkImplItem const& item = NoLinkImplItem)
    : cmGeneratorTarget::TargetPropertyEntry(item)
    , ge(std::move(cge))
  {
  }

112
113
114
115
  const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config,
                              cmGeneratorTarget const* headTarget,
                              cmGeneratorExpressionDAGChecker* dagChecker,
                              std::string const& language) const override
116
  {
117
    return this->ge->Evaluate(lg, config, headTarget, dagChecker, nullptr,
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
                              language);
  }

  cmListFileBacktrace GetBacktrace() const override
  {
    return this->ge->GetBacktrace();
  }

  std::string const& GetInput() const override { return this->ge->GetInput(); }

  bool GetHadContextSensitiveCondition() const override
  {
    return this->ge->GetHadContextSensitiveCondition();
  }

private:
  const std::unique_ptr<cmCompiledGeneratorExpression> ge;
};

class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
{
public:
  TargetPropertyEntryString(std::string propertyValue,
                            cmListFileBacktrace backtrace,
                            cmLinkImplItem const& item = NoLinkImplItem)
    : cmGeneratorTarget::TargetPropertyEntry(item)
    , PropertyValue(std::move(propertyValue))
    , Backtrace(std::move(backtrace))
  {
  }

149
  const std::string& Evaluate(cmLocalGenerator*, const std::string&,
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
                              cmGeneratorTarget const*,
                              cmGeneratorExpressionDAGChecker*,
                              std::string const&) const override
  {
    return this->PropertyValue;
  }

  cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
  std::string const& GetInput() const override { return this->PropertyValue; }

private:
  std::string PropertyValue;
  cmListFileBacktrace Backtrace;
};

cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry(
  const std::string& propertyValue,
  cmListFileBacktrace backtrace = cmListFileBacktrace(),
  bool evaluateForBuildsystem = false)
{
  if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
    cmGeneratorExpression ge(std::move(backtrace));
    std::unique_ptr<cmCompiledGeneratorExpression> cge =
      ge.Parse(propertyValue);
    cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
    return new TargetPropertyEntryGenex(std::move(cge));
  }

178
  return new TargetPropertyEntryString(propertyValue, std::move(backtrace));
179
180
}

181
void CreatePropertyGeneratorExpressions(
182
  cmStringRange entries, cmBacktraceRange backtraces,
183
184
  std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
  bool evaluateForBuildsystem = false)
185
{
wahikihiki's avatar
wahikihiki committed
186
187
  auto btIt = backtraces.begin();
  for (auto it = entries.begin(); it != entries.end(); ++it, ++btIt) {
188
    items.push_back(
189
      CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
190
  }
191
192
}

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
namespace {
// Represent a target property entry after evaluating generator expressions
// and splitting up lists.
struct EvaluatedTargetPropertyEntry
{
  EvaluatedTargetPropertyEntry(cmLinkImplItem const& item,
                               cmListFileBacktrace bt)
    : LinkImplItem(item)
    , Backtrace(std::move(bt))
  {
  }

  // Move-only.
  EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry&&) = default;
  EvaluatedTargetPropertyEntry(EvaluatedTargetPropertyEntry const&) = delete;
  EvaluatedTargetPropertyEntry& operator=(EvaluatedTargetPropertyEntry&&) =
    delete;
  EvaluatedTargetPropertyEntry& operator=(
    EvaluatedTargetPropertyEntry const&) = delete;

  cmLinkImplItem const& LinkImplItem;
  cmListFileBacktrace Backtrace;
  std::vector<std::string> Values;
  bool ContextDependent = false;
};

EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
  cmGeneratorTarget const* thisTarget, std::string const& config,
  std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
  cmGeneratorTarget::TargetPropertyEntry* entry)
{
  EvaluatedTargetPropertyEntry ee(entry->LinkImplItem, entry->GetBacktrace());
225
  cmExpandList(entry->Evaluate(thisTarget->GetLocalGenerator(), config,
226
227
                               thisTarget, dagChecker, lang),
               ee.Values);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  if (entry->GetHadContextSensitiveCondition()) {
    ee.ContextDependent = true;
  }
  return ee;
}

std::vector<EvaluatedTargetPropertyEntry> EvaluateTargetPropertyEntries(
  cmGeneratorTarget const* thisTarget, std::string const& config,
  std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
  std::vector<cmGeneratorTarget::TargetPropertyEntry*> const& in)
{
  std::vector<EvaluatedTargetPropertyEntry> out;
  out.reserve(in.size());
  for (cmGeneratorTarget::TargetPropertyEntry* entry : in) {
    out.emplace_back(EvaluateTargetPropertyEntry(thisTarget, config, lang,
                                                 dagChecker, entry));
  }
  return out;
}
}

249
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
250
  : Target(t)
251
  , FortranModuleDirectoryCreated(false)
252
253
  , SourceFileFlagsConstructed(false)
  , PolicyWarnedCMP0022(false)
254
  , PolicyReportedCMP0069(false)
255
256
257
258
  , DebugIncludesDone(false)
  , DebugCompileOptionsDone(false)
  , DebugCompileFeaturesDone(false)
  , DebugCompileDefinitionsDone(false)
259
  , DebugLinkOptionsDone(false)
260
  , DebugLinkDirectoriesDone(false)
261
  , DebugPrecompileHeadersDone(false)
262
263
264
  , DebugSourcesDone(false)
  , LinkImplementationLanguageIsContextDependent(true)
  , UtilityItemsDone(false)
265
266
{
  this->Makefile = this->Target->GetMakefile();
267
  this->LocalGenerator = lg;
268
  this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
269

270
271
  this->GlobalGenerator->ComputeTargetObjectDirectory(this);

272
273
274
  CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
                                     t->GetIncludeDirectoriesBacktraces(),
                                     this->IncludeDirectoriesEntries);
275

276
277
278
  CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
                                     t->GetCompileOptionsBacktraces(),
                                     this->CompileOptionsEntries);
279

280
281
282
  CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
                                     t->GetCompileFeaturesBacktraces(),
                                     this->CompileFeaturesEntries);
283

284
285
286
  CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
                                     t->GetCompileDefinitionsBacktraces(),
                                     this->CompileDefinitionsEntries);
287

288
289
290
291
  CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
                                     t->GetLinkOptionsBacktraces(),
                                     this->LinkOptionsEntries);

292
293
294
295
  CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
                                     t->GetLinkDirectoriesBacktraces(),
                                     this->LinkDirectoriesEntries);

296
297
298
299
  CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
                                     t->GetPrecompileHeadersBacktraces(),
                                     this->PrecompileHeadersEntries);

300
301
302
  CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
                                     t->GetSourceBacktraces(),
                                     this->SourceEntries, true);
303

304
  this->PolicyMap = t->GetPolicyMap();
305
306
}

307
308
cmGeneratorTarget::~cmGeneratorTarget()
{
309
  cmDeleteAll(this->IncludeDirectoriesEntries);
310
  cmDeleteAll(this->CompileOptionsEntries);
311
  cmDeleteAll(this->CompileFeaturesEntries);
312
  cmDeleteAll(this->CompileDefinitionsEntries);
313
  cmDeleteAll(this->LinkOptionsEntries);
314
  cmDeleteAll(this->LinkDirectoriesEntries);
315
  cmDeleteAll(this->PrecompileHeadersEntries);
316
  cmDeleteAll(this->SourceEntries);
317
318
319
  cmDeleteAll(this->LinkInformation);
}

320
321
322
const char* cmGeneratorTarget::GetSourcesProperty() const
{
  std::vector<std::string> values;
323
  for (TargetPropertyEntry* se : this->SourceEntries) {
324
    values.push_back(se->GetInput());
325
326
327
  }
  static std::string value;
  value.clear();
328
  value = cmJoin(values, ";");
329
330
331
  return value.c_str();
}

332
333
334
335
336
cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
{
  return this->GetLocalGenerator()->GetGlobalGenerator();
}

337
338
339
340
341
cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
{
  return this->LocalGenerator;
}

342
cmStateEnums::TargetType cmGeneratorTarget::GetType() const
343
344
345
346
{
  return this->Target->GetType();
}

347
const std::string& cmGeneratorTarget::GetName() const
348
349
350
351
{
  return this->Target->GetName();
}

352
353
std::string cmGeneratorTarget::GetExportName() const
{
354
  const char* exportName = this->GetProperty("EXPORT_NAME");
355

356
357
  if (exportName && *exportName) {
    if (!cmGeneratorExpression::IsValidTargetName(exportName)) {
358
359
360
      std::ostringstream e;
      e << "EXPORT_NAME property \"" << exportName << "\" for \""
        << this->GetName() << "\": is not valid.";
361
      cmSystemTools::Error(e.str());
362
363
      return "";
    }
364
365
    return exportName;
  }
366
367
368
  return this->GetName();
}

369
const char* cmGeneratorTarget::GetProperty(const std::string& prop) const
370
{
371
372
373
  if (!cmTargetPropertyComputer::PassesWhitelist(
        this->GetType(), prop, this->Makefile->GetMessenger(),
        this->GetBacktrace())) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
374
    return nullptr;
375
376
377
378
379
380
  }
  if (const char* result = cmTargetPropertyComputer::GetProperty(
        this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) {
    return result;
  }
  if (cmSystemTools::GetFatalErrorOccured()) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
381
    return nullptr;
382
  }
383
384
385
  return this->Target->GetProperty(prop);
}

386
387
388
389
390
391
392
393
394
const char* cmGeneratorTarget::GetSafeProperty(const std::string& prop) const
{
  const char* ret = this->GetProperty(prop);
  if (!ret) {
    return "";
  }
  return ret;
}

395
396
const char* cmGeneratorTarget::GetOutputTargetType(
  cmStateEnums::ArtifactType artifact) const
397
{
398
  switch (this->GetType()) {
399
    case cmStateEnums::SHARED_LIBRARY:
400
      if (this->IsDLLPlatform()) {
401
402
403
404
405
406
407
        switch (artifact) {
          case cmStateEnums::RuntimeBinaryArtifact:
            // A DLL shared library is treated as a runtime target.
            return "RUNTIME";
          case cmStateEnums::ImportLibraryArtifact:
            // A DLL import library is treated as an archive target.
            return "ARCHIVE";
408
        }
409
      } else {
410
411
412
        // For non-DLL platforms shared libraries are treated as
        // library targets.
        return "LIBRARY";
413
      }
414
      break;
415
    case cmStateEnums::STATIC_LIBRARY:
416
417
      // Static libraries are always treated as archive targets.
      return "ARCHIVE";
418
    case cmStateEnums::MODULE_LIBRARY:
419
420
      switch (artifact) {
        case cmStateEnums::RuntimeBinaryArtifact:
421
          // Module libraries are always treated as library targets.
422
423
          return "LIBRARY";
        case cmStateEnums::ImportLibraryArtifact:
424
          // Module import libraries are treated as archive targets.
425
          return "ARCHIVE";
426
      }
427
      break;
428
429
430
    case cmStateEnums::OBJECT_LIBRARY:
      // Object libraries are always treated as object targets.
      return "OBJECT";
431
    case cmStateEnums::EXECUTABLE:
432
433
434
435
436
437
438
      switch (artifact) {
        case cmStateEnums::RuntimeBinaryArtifact:
          // Executables are always treated as runtime targets.
          return "RUNTIME";
        case cmStateEnums::ImportLibraryArtifact:
          // Executable import libraries are treated as archive targets.
          return "ARCHIVE";
439
      }
440
      break;
441
442
    default:
      break;
443
  }
444
445
446
  return "";
}

447
448
std::string cmGeneratorTarget::GetOutputName(
  const std::string& config, cmStateEnums::ArtifactType artifact) const
449
{
450
  // Lookup/compute/cache the output name for this configuration.
451
  OutputNameKey key(config, artifact);
wahikihiki's avatar
wahikihiki committed
452
  auto i = this->OutputNameMap.find(key);
453
  if (i == this->OutputNameMap.end()) {
454
455
456
    // Add empty name in map to detect potential recursion.
    OutputNameMapType::value_type entry(key, "");
    i = this->OutputNameMap.insert(entry).first;
457

458
459
    // Compute output name.
    std::vector<std::string> props;
460
    std::string type = this->GetOutputTargetType(artifact);
461
    std::string configUpper = cmSystemTools::UpperCase(config);
462
    if (!type.empty() && !configUpper.empty()) {
463
464
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
      props.push_back(type + "_OUTPUT_NAME_" + configUpper);
465
466
    }
    if (!type.empty()) {
467
468
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
      props.push_back(type + "_OUTPUT_NAME");
469
470
    }
    if (!configUpper.empty()) {
471
472
473
474
      // OUTPUT_NAME_<CONFIG>
      props.push_back("OUTPUT_NAME_" + configUpper);
      // <CONFIG>_OUTPUT_NAME
      props.push_back(configUpper + "_OUTPUT_NAME");
475
    }
476
    // OUTPUT_NAME
wahikihiki's avatar
wahikihiki committed
477
    props.emplace_back("OUTPUT_NAME");
478

479
    std::string outName;
480
481
    for (std::string const& p : props) {
      if (const char* outNameProp = this->GetProperty(p)) {
482
483
484
        outName = outNameProp;
        break;
      }
485
    }
486

487
    if (outName.empty()) {
488
      outName = this->GetName();
489
    }
490
491

    // Now evaluate genex and update the previously-prepared map entry.
492
493
    i->second =
      cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config);
494
  } else if (i->second.empty()) {
495
496
    // An empty map entry indicates we have been called recursively
    // from the above block.
497
    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
498
      MessageType::FATAL_ERROR,
499
      "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
500
      this->GetBacktrace());
501
  }
502
  return i->second;
503
504
}

505
506
507
508
std::string cmGeneratorTarget::GetFilePrefix(
  const std::string& config, cmStateEnums::ArtifactType artifact) const
{
  if (this->IsImported()) {
509
    const char* prefix = this->GetFilePrefixInternal(config, artifact);
510
511
512
513

    return prefix ? prefix : std::string();
  }

514
515
516
  std::string prefix;
  std::string suffix;
  std::string base;
517
518
519
520
521
522
523
  this->GetFullNameInternal(config, artifact, prefix, base, suffix);
  return prefix;
}
std::string cmGeneratorTarget::GetFileSuffix(
  const std::string& config, cmStateEnums::ArtifactType artifact) const
{
  if (this->IsImported()) {
524
    const char* suffix = this->GetFileSuffixInternal(config, artifact);
525
526
527
528

    return suffix ? suffix : std::string();
  }

529
530
531
  std::string prefix;
  std::string suffix;
  std::string base;
532
533
534
535
  this->GetFullNameInternal(config, artifact, prefix, base, suffix);
  return suffix;
}

536
537
538
539
std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
{
  const char* postfix = nullptr;
  if (!config.empty()) {
540
541
    std::string configProp =
      cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
542
543
544
545
546
547
548
549
550
551
    postfix = this->GetProperty(configProp);
    // Mac application bundles and frameworks have no postfix.
    if (!this->IsImported() && postfix &&
        (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
      postfix = nullptr;
    }
  }
  return postfix ? postfix : std::string();
}

552
const char* cmGeneratorTarget::GetFilePrefixInternal(
553
554
  std::string const& config, cmStateEnums::ArtifactType artifact,
  const std::string& language) const
555
556
557
558
559
560
561
562
563
564
565
566
567
568
{
  // no prefix for non-main target types.
  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
      this->GetType() != cmStateEnums::EXECUTABLE) {
    return nullptr;
  }

  const bool isImportedLibraryArtifact =
    (artifact == cmStateEnums::ImportLibraryArtifact);

  // Return an empty prefix for the import library if this platform
  // does not support import libraries.
569
  if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
    return nullptr;
  }

  // The implib option is only allowed for shared libraries, module
  // libraries, and executables.
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
      this->GetType() != cmStateEnums::EXECUTABLE) {
    artifact = cmStateEnums::RuntimeBinaryArtifact;
  }

  // Compute prefix value.
  const char* targetPrefix =
    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
                               : this->GetProperty("PREFIX"));

  if (!targetPrefix) {
    const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
    if (!language.empty() && prefixVar && *prefixVar) {
      std::string langPrefix = prefixVar + std::string("_") + language;
      targetPrefix = this->Makefile->GetDefinition(langPrefix);
    }

    // if there is no prefix on the target nor specific language
    // use the cmake definition.
    if (!targetPrefix && prefixVar) {
      targetPrefix = this->Makefile->GetDefinition(prefixVar);
    }
  }

  return targetPrefix;
}
const char* cmGeneratorTarget::GetFileSuffixInternal(
603
604
  std::string const& config, cmStateEnums::ArtifactType artifact,
  const std::string& language) const
605
606
607
608
609
610
611
612
613
614
615
616
617
618
{
  // no suffix for non-main target types.
  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
      this->GetType() != cmStateEnums::EXECUTABLE) {
    return nullptr;
  }

  const bool isImportedLibraryArtifact =
    (artifact == cmStateEnums::ImportLibraryArtifact);

  // Return an empty suffix for the import library if this platform
  // does not support import libraries.
619
  if (isImportedLibraryArtifact && !this->NeedImportLibraryName(config)) {
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
    return nullptr;
  }

  // The implib option is only allowed for shared libraries, module
  // libraries, and executables.
  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
      this->GetType() != cmStateEnums::EXECUTABLE) {
    artifact = cmStateEnums::RuntimeBinaryArtifact;
  }

  // Compute suffix value.
  const char* targetSuffix =
    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
                               : this->GetProperty("SUFFIX"));

  if (!targetSuffix) {
    const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
    if (!language.empty() && suffixVar && *suffixVar) {
      std::string langSuffix = suffixVar + std::string("_") + language;
      targetSuffix = this->Makefile->GetDefinition(langSuffix);
    }

    // if there is no suffix on the target nor specific language
    // use the cmake definition.
    if (!targetSuffix && suffixVar) {
      targetSuffix = this->Makefile->GetDefinition(suffixVar);
    }
  }

  return targetSuffix;
}

653
654
655
656
657
658
659
void cmGeneratorTarget::ClearSourcesCache()
{
  this->KindedSourcesMap.clear();
  this->LinkImplementationLanguageIsContextDependent = true;
  this->Objects.clear();
}

660
void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
661
{
662
663
664
  this->SourceEntries.insert(
    before ? this->SourceEntries.begin() : this->SourceEntries.end(),
    CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
665
  this->ClearSourcesCache();
666
667
}

668
void cmGeneratorTarget::AddSource(const std::string& src, bool before)
669
{
670
671
  this->Target->AddSource(src, before);
  this->AddSourceCommon(src, before);
672
673
}

674
675
676
void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
  this->Target->AddTracedSources(srcs);
677
  if (!srcs.empty()) {
678
    this->AddSourceCommon(cmJoin(srcs, ";"));
679
  }
680
681
}

682
683
684
685
void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
                                            bool before)
{
  this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
686
  this->IncludeDirectoriesEntries.insert(
687
688
    before ? this->IncludeDirectoriesEntries.begin()
           : this->IncludeDirectoriesEntries.end(),
689
    CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
690
691
}

692
693
std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
  cmSourceFile const* sf) const
694
{
wahikihiki's avatar
wahikihiki committed
695
  auto i = this->SourceDepends.find(sf);
696
  if (i != this->SourceDepends.end()) {
697
    return &i->second.Depends;
698
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
699
  return nullptr;
700
701
}

702
703
704
705
706
707
708
709
namespace {
void handleSystemIncludesDep(cmLocalGenerator* lg,
                             cmGeneratorTarget const* depTgt,
                             const std::string& config,
                             cmGeneratorTarget const* headTarget,
                             cmGeneratorExpressionDAGChecker* dagChecker,
                             std::vector<std::string>& result,
                             bool excludeImported, std::string const& language)
710
711
{
  if (const char* dirs =
712
        depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
713
714
    cmExpandList(cmGeneratorExpression::Evaluate(dirs, lg, config, headTarget,
                                                 dagChecker, depTgt, language),
715
                 result);
716
717
  }
  if (!depTgt->IsImported() || excludeImported) {
718
    return;
719
  }
720
721

  if (const char* dirs =
722
        depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
723
724
    cmExpandList(cmGeneratorExpression::Evaluate(dirs, lg, config, headTarget,
                                                 dagChecker, depTgt, language),
725
                 result);
726
  }
727
}
728
}
729

730
/* clang-format off */
731
#define IMPLEMENT_VISIT(KIND)                                                 \
732
  do {                                                                        \
733
    KindedSources const& kinded = this->GetKindedSources(config);             \
734
735
    for (SourceAndKind const& s : kinded.Sources) {                           \
      if (s.Kind == KIND) {                                                   \
736
        data.push_back(s.Source.Value);                                       \
737
      }                                                                       \
738
    }                                                                         \
739
  } while (false)
740
/* clang-format on */
741

742
743
void cmGeneratorTarget::GetObjectSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
744
{
745
  IMPLEMENT_VISIT(SourceKindObjectSource);
746

747
  if (!this->Objects.empty()) {
748
    return;
749
  }
750

751
752
  for (cmSourceFile const* it : data) {
    this->Objects[it];
753
  }
754
755

  this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
756
757
}

758
void cmGeneratorTarget::ComputeObjectMapping()
759
{
760
  if (!this->Objects.empty()) {
761
    return;
762
  }
763

764
765
  std::vector<std::string> const& configs =
    this->Makefile->GetGeneratorConfigs();
766
  for (std::string const& c : configs) {
767
    std::vector<cmSourceFile const*> sourceFiles;
768
    this->GetObjectSources(sourceFiles, c);
769
  }
770
771
}

772
773
774
const char* cmGeneratorTarget::GetFeature(const std::string& feature,
                                          const std::string& config) const
{
775
  if (!config.empty()) {
776
777
    std::string featureConfig =
      cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
778
    if (const char* value = this->GetProperty(featureConfig)) {
779
780
      return value;
    }
781
782
  }
  if (const char* value = this->GetProperty(feature)) {
783
    return value;
784
  }
785
  return this->LocalGenerator->GetFeature(feature, config);
786
787
}

788
789
790
791
792
793
794
795
796
797
798
799
800
const char* cmGeneratorTarget::GetLinkPIEProperty(
  const std::string& config) const
{
  static std::string PICValue;

  PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty(
    "POSITION_INDEPENDENT_CODE", config);

  if (PICValue == "(unset)") {
    // POSITION_INDEPENDENT_CODE is not set
    return nullptr;
  }

801
802
803
804
  auto status = this->GetPolicyStatusCMP0083();
  return (status != cmPolicies::WARN && status != cmPolicies::OLD)
    ? PICValue.c_str()
    : nullptr;
805
806
}

807
808
bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
                                     std::string const& config) const
809
{
810
  const char* feature = "INTERPROCEDURAL_OPTIMIZATION";
811
  const bool result = cmIsOn(this->GetFeature(feature, config));
812
813
814
815
816
817

  if (!result) {
    // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
    return false;
  }

818
819
820
821
822
  if (lang != "C" && lang != "CXX" && lang != "Fortran") {
    // We do not define IPO behavior for other languages.
    return false;
  }

823
824
825
  cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();

  if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
826
    if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
827
828
829
830
831
832
      return true;
    }
    if (this->PolicyReportedCMP0069) {
      // problem is already reported, no need to issue a message
      return false;
    }
833
834
835
    const bool in_try_compile =
      this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
    if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
836
837
838
839
840
      std::ostringstream w;
      w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
      w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
        << "'" << this->GetName() << "'.";
      this->LocalGenerator->GetCMakeInstance()->IssueMessage(
841
        MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
842
843
844
845
846
847
848

      this->PolicyReportedCMP0069 = true;
    }
    return false;
  }

  // Note: check consistency with messages from CheckIPOSupported
Daniel Pfeifer's avatar
Daniel Pfeifer committed
849
  const char* message = nullptr;
850
  if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
851
    message = "CMake doesn't support IPO for current compiler";
852
853
  } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
                                   "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
    message = "Compiler doesn't support IPO";
  } else if (!this->GlobalGenerator->IsIPOSupported()) {
    message = "CMake doesn't support IPO for current generator";
  }

  if (!message) {
    // No error/warning messages
    return true;
  }

  if (this->PolicyReportedCMP0069) {
    // problem is already reported, no need to issue a message
    return false;
  }

  this->PolicyReportedCMP0069 = true;

  this->LocalGenerator->GetCMakeInstance()->IssueMessage(
872
    MessageType::FATAL_ERROR, message, this->GetBacktrace());
873
  return false;
874
875
}

876
const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
877
{
878
879
  this->ComputeObjectMapping();
  return this->Objects[file];
880
881
}

882
883
884
885
886
887
888
889
890
const char* cmGeneratorTarget::GetCustomObjectExtension() const
{
  static std::string extension;
  const bool has_ptx_extension =
    this->GetPropertyAsBool("CUDA_PTX_COMPILATION");
  if (has_ptx_extension) {
    extension = ".ptx";
    return extension.c_str();
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
891
  return nullptr;
892
893
}

894
void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
895
896
897
898
899
900
{
  this->ExplicitObjectName.insert(sf);
}

bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
{
901
  const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
wahikihiki's avatar
wahikihiki committed
902
  auto it = this->ExplicitObjectName.find(file);
903
904
905
  return it != this->ExplicitObjectName.end();
}

906
907
908
void cmGeneratorTarget::GetModuleDefinitionSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
{
909
  IMPLEMENT_VISIT(SourceKindModuleDefinition);
910
911
}

912
913
void cmGeneratorTarget::GetHeaderSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
914
{
915
  IMPLEMENT_VISIT(SourceKindHeader);
916
917
}

918
919
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
                                        const std::string& config) const
920
{
921
  IMPLEMENT_VISIT(SourceKindExtra);
922
923
}

924
925
void cmGeneratorTarget::GetCustomCommands(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
926
{
927
  IMPLEMENT_VISIT(SourceKindCustomCommand);
928
929
}

930
931
void cmGeneratorTarget::GetExternalObjects(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
932
{
933
  IMPLEMENT_VISIT(SourceKindExternalObject);
934
935
}

936
void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& headers,
937
                                               const std::string& config) const
938
{
939
940
  KindedSources const& kinded = this->GetKindedSources(config);
  headers = kinded.ExpectedResxHeaders;
941
942
}

943
void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& data,
944
                                       const std::string& config) const
945
{
946
  IMPLEMENT_VISIT(SourceKindResx);
947
948
}

949
950
void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data,
                                       const std::string& config) const
951
{
952
  IMPLEMENT_VISIT(SourceKindAppManifest);
953
954
}

955
956
void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
                                     const std::string& config) const
957
{
958
  IMPLEMENT_VISIT(SourceKindManifest);
959
960
}

961
962
void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data,
                                        const std::string& config) const
963
{
964
  IMPLEMENT_VISIT(SourceKindCertificate);
965
966
}

967
968
void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers,
                                               const std::string& config) const
969
{
970
971
  KindedSources const& kinded = this->GetKindedSources(config);
  headers = kinded.ExpectedXamlHeaders;
972
973
}

974
975
void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs,
                                               const std::string& config) const
976
{
977
978
  KindedSources const& kinded = this->GetKindedSources(config);
  srcs = kinded.ExpectedXamlSources;
979
980
981
982
}

std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
{
983
  if (!this->UtilityItemsDone) {
984
    this->UtilityItemsDone = true;
985
986
    std::set<BT<std::string>> const& utilities = this->GetUtilities();
    for (BT<std::string> const& i : utilities) {
987
      if (cmGeneratorTarget* gt =
988
989
            this->LocalGenerator->FindGeneratorTargetToUse(i.Value)) {
        this->UtilityItems.insert(cmLinkItem(gt, i.Backtrace));
990
      } else {
991
        this->UtilityItems.insert(cmLinkItem(i.Value, i.Backtrace));
992
      }
993
    }
994
  }
995
  return this->UtilityItems;
996
997
}

998
void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data,
999
                                       const std::string& config) const
1000
{
1001
  IMPLEMENT_VISIT(SourceKindXaml);
1002
1003
}

1004
1005
1006
const char* cmGeneratorTarget::GetLocation(const std::string& config) const