cmGeneratorTarget.cxx 191 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 "cmsys/RegularExpression.hxx"
6 7 8 9
#include <algorithm>
#include <assert.h>
#include <errno.h>
#include <iterator>
10
#include <memory> // IWYU pragma: keep
11 12 13 14 15
#include <queue>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
16
#include <unordered_set>
17

18
#include "cmAlgorithms.h"
19
#include "cmComputeLinkInformation.h"
20
#include "cmCustomCommand.h"
21
#include "cmCustomCommandGenerator.h"
22
#include "cmCustomCommandLines.h"
23 24 25 26 27
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
28
#include "cmPropertyMap.h"
29
#include "cmSourceFile.h"
30
#include "cmSourceFileLocation.h"
31
#include "cmState.h"
32
#include "cmSystemTools.h"
33
#include "cmTarget.h"
34
#include "cmTargetLinkLibraryType.h"
35
#include "cmTargetPropertyComputer.h"
36
#include "cmake.h"
37

38
class cmMessenger;
39

40 41 42 43 44 45 46 47 48
template <>
const char* cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
  cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
  cmListFileBacktrace const& /* context */)
{
  return tgt->GetSourcesProperty();
}

template <>
49 50 51
const char*
cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
  cmGeneratorTarget const* tgt)
52 53 54 55 56 57 58 59 60 61 62
{
  return tgt->GetLocation("");
}

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

63 64
class cmGeneratorTarget::TargetPropertyEntry
{
65
  static cmLinkImplItem NoLinkImplItem;
66

67
public:
68
  TargetPropertyEntry(std::unique_ptr<cmCompiledGeneratorExpression> cge,
69
                      cmLinkImplItem const& item = NoLinkImplItem)
70
    : ge(std::move(cge))
71 72 73
    , LinkImplItem(item)
  {
  }
74
  const std::unique_ptr<cmCompiledGeneratorExpression> ge;
75 76 77 78 79
  cmLinkImplItem const& LinkImplItem;
};
cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;

void CreatePropertyGeneratorExpressions(
80
  cmStringRange entries, cmBacktraceRange backtraces,
81 82
  std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
  bool evaluateForBuildsystem = false)
83 84 85
{
  std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin();
  for (std::vector<std::string>::const_iterator it = entries.begin();
86
       it != entries.end(); ++it, ++btIt) {
87
    cmGeneratorExpression ge(*btIt);
88
    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
89
    cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
90 91
    items.push_back(
      new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
92
  }
93 94
}

95
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
96
  : Target(t)
97
  , FortranModuleDirectoryCreated(false)
98 99
  , SourceFileFlagsConstructed(false)
  , PolicyWarnedCMP0022(false)
100
  , PolicyReportedCMP0069(false)
101 102 103 104
  , DebugIncludesDone(false)
  , DebugCompileOptionsDone(false)
  , DebugCompileFeaturesDone(false)
  , DebugCompileDefinitionsDone(false)
105
  , DebugLinkOptionsDone(false)
106 107 108
  , DebugSourcesDone(false)
  , LinkImplementationLanguageIsContextDependent(true)
  , UtilityItemsDone(false)
109 110
{
  this->Makefile = this->Target->GetMakefile();
111
  this->LocalGenerator = lg;
112
  this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
113

114 115
  this->GlobalGenerator->ComputeTargetObjectDirectory(this);

116 117 118
  CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
                                     t->GetIncludeDirectoriesBacktraces(),
                                     this->IncludeDirectoriesEntries);
119

120 121 122
  CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
                                     t->GetCompileOptionsBacktraces(),
                                     this->CompileOptionsEntries);
123

124 125 126
  CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
                                     t->GetCompileFeaturesBacktraces(),
                                     this->CompileFeaturesEntries);
127

128 129 130
  CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
                                     t->GetCompileDefinitionsBacktraces(),
                                     this->CompileDefinitionsEntries);
131

132 133 134 135
  CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
                                     t->GetLinkOptionsBacktraces(),
                                     this->LinkOptionsEntries);

136 137 138
  CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
                                     t->GetSourceBacktraces(),
                                     this->SourceEntries, true);
139

140
  this->DLLPlatform =
141 142
    strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
           "") != 0;
143 144

  this->PolicyMap = t->PolicyMap;
145 146
}

147 148
cmGeneratorTarget::~cmGeneratorTarget()
{
149
  cmDeleteAll(this->IncludeDirectoriesEntries);
150
  cmDeleteAll(this->CompileOptionsEntries);
151
  cmDeleteAll(this->CompileFeaturesEntries);
152
  cmDeleteAll(this->CompileDefinitionsEntries);
153
  cmDeleteAll(this->LinkOptionsEntries);
154
  cmDeleteAll(this->SourceEntries);
155 156 157
  cmDeleteAll(this->LinkInformation);
}

158 159 160
const char* cmGeneratorTarget::GetSourcesProperty() const
{
  std::vector<std::string> values;
161 162
  for (TargetPropertyEntry* se : this->SourceEntries) {
    values.push_back(se->ge->GetInput());
163 164 165
  }
  static std::string value;
  value.clear();
166
  value = cmJoin(values, ";");
167 168 169
  return value.c_str();
}

170 171 172 173 174
cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
{
  return this->GetLocalGenerator()->GetGlobalGenerator();
}

175 176 177 178 179
cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
{
  return this->LocalGenerator;
}

180
cmStateEnums::TargetType cmGeneratorTarget::GetType() const
181 182 183 184
{
  return this->Target->GetType();
}

185
const std::string& cmGeneratorTarget::GetName() const
186 187 188 189
{
  return this->Target->GetName();
}

190 191
std::string cmGeneratorTarget::GetExportName() const
{
192
  const char* exportName = this->GetProperty("EXPORT_NAME");
193

194 195
  if (exportName && *exportName) {
    if (!cmGeneratorExpression::IsValidTargetName(exportName)) {
196 197 198 199 200 201
      std::ostringstream e;
      e << "EXPORT_NAME property \"" << exportName << "\" for \""
        << this->GetName() << "\": is not valid.";
      cmSystemTools::Error(e.str().c_str());
      return "";
    }
202 203
    return exportName;
  }
204 205 206
  return this->GetName();
}

207
const char* cmGeneratorTarget::GetProperty(const std::string& prop) const
208
{
209 210 211
  if (!cmTargetPropertyComputer::PassesWhitelist(
        this->GetType(), prop, this->Makefile->GetMessenger(),
        this->GetBacktrace())) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
212
    return nullptr;
213 214 215 216 217 218
  }
  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
219
    return nullptr;
220
  }
221 222 223
  return this->Target->GetProperty(prop);
}

224 225
const char* cmGeneratorTarget::GetOutputTargetType(
  cmStateEnums::ArtifactType artifact) const
226
{
227
  switch (this->GetType()) {
228
    case cmStateEnums::SHARED_LIBRARY:
229
      if (this->IsDLLPlatform()) {
230 231 232 233 234 235 236
        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";
237
        }
238
      } else {
239 240 241
        // For non-DLL platforms shared libraries are treated as
        // library targets.
        return "LIBRARY";
242
      }
243
      break;
244
    case cmStateEnums::STATIC_LIBRARY:
245 246
      // Static libraries are always treated as archive targets.
      return "ARCHIVE";
247
    case cmStateEnums::MODULE_LIBRARY:
248 249
      switch (artifact) {
        case cmStateEnums::RuntimeBinaryArtifact:
250
          // Module libraries are always treated as library targets.
251 252
          return "LIBRARY";
        case cmStateEnums::ImportLibraryArtifact:
253
          // Module import libraries are treated as archive targets.
254
          return "ARCHIVE";
255
      }
256
      break;
257 258 259
    case cmStateEnums::OBJECT_LIBRARY:
      // Object libraries are always treated as object targets.
      return "OBJECT";
260
    case cmStateEnums::EXECUTABLE:
261 262 263 264 265 266 267
      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";
268
      }
269
      break;
270 271
    default:
      break;
272
  }
273 274 275
  return "";
}

276 277
std::string cmGeneratorTarget::GetOutputName(
  const std::string& config, cmStateEnums::ArtifactType artifact) const
278
{
279
  // Lookup/compute/cache the output name for this configuration.
280
  OutputNameKey key(config, artifact);
281 282
  cmGeneratorTarget::OutputNameMapType::iterator i =
    this->OutputNameMap.find(key);
283
  if (i == this->OutputNameMap.end()) {
284 285 286
    // Add empty name in map to detect potential recursion.
    OutputNameMapType::value_type entry(key, "");
    i = this->OutputNameMap.insert(entry).first;
287

288 289
    // Compute output name.
    std::vector<std::string> props;
290
    std::string type = this->GetOutputTargetType(artifact);
291
    std::string configUpper = cmSystemTools::UpperCase(config);
292
    if (!type.empty() && !configUpper.empty()) {
293 294
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
      props.push_back(type + "_OUTPUT_NAME_" + configUpper);
295 296
    }
    if (!type.empty()) {
297 298
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
      props.push_back(type + "_OUTPUT_NAME");
299 300
    }
    if (!configUpper.empty()) {
301 302 303 304
      // OUTPUT_NAME_<CONFIG>
      props.push_back("OUTPUT_NAME_" + configUpper);
      // <CONFIG>_OUTPUT_NAME
      props.push_back(configUpper + "_OUTPUT_NAME");
305
    }
306 307
    // OUTPUT_NAME
    props.push_back("OUTPUT_NAME");
308

309
    std::string outName;
310 311
    for (std::string const& p : props) {
      if (const char* outNameProp = this->GetProperty(p)) {
312 313 314
        outName = outNameProp;
        break;
      }
315
    }
316

317
    if (outName.empty()) {
318
      outName = this->GetName();
319
    }
320 321 322

    // Now evaluate genex and update the previously-prepared map entry.
    cmGeneratorExpression ge;
323
    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
324
    i->second = cge->Evaluate(this->LocalGenerator, config);
325
  } else if (i->second.empty()) {
326 327
    // An empty map entry indicates we have been called recursively
    // from the above block.
328
    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
329 330
      cmake::FATAL_ERROR,
      "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
331
      this->GetBacktrace());
332
  }
333
  return i->second;
334 335
}

336 337 338 339 340 341 342
void cmGeneratorTarget::ClearSourcesCache()
{
  this->KindedSourcesMap.clear();
  this->LinkImplementationLanguageIsContextDependent = true;
  this->Objects.clear();
}

343
void cmGeneratorTarget::AddSourceCommon(const std::string& src)
344
{
345 346
  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
  cmGeneratorExpression ge(lfbt);
347
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
348
  cge->SetEvaluateForBuildsystem(true);
349
  this->SourceEntries.push_back(new TargetPropertyEntry(std::move(cge)));
350
  this->ClearSourcesCache();
351 352
}

353 354 355 356 357 358
void cmGeneratorTarget::AddSource(const std::string& src)
{
  this->Target->AddSource(src);
  this->AddSourceCommon(src);
}

359 360 361
void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
  this->Target->AddTracedSources(srcs);
362
  if (!srcs.empty()) {
363
    this->AddSourceCommon(cmJoin(srcs, ";"));
364
  }
365 366
}

367 368 369 370 371 372
void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
                                            bool before)
{
  this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
  cmGeneratorExpression ge(lfbt);
373
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
374 375 376 377 378
  cge->SetEvaluateForBuildsystem(true);
  // Insert before begin/end
  std::vector<TargetPropertyEntry*>::iterator pos = before
    ? this->IncludeDirectoriesEntries.begin()
    : this->IncludeDirectoriesEntries.end();
379 380
  this->IncludeDirectoriesEntries.insert(
    pos, new TargetPropertyEntry(std::move(cge)));
381 382
}

383 384
std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
  cmSourceFile const* sf) const
385
{
386
  SourceEntriesType::const_iterator i = this->SourceDepends.find(sf);
387
  if (i != this->SourceDepends.end()) {
388
    return &i->second.Depends;
389
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
390
  return nullptr;
391 392
}

393 394 395 396
static void handleSystemIncludesDep(
  cmLocalGenerator* lg, cmGeneratorTarget const* depTgt,
  const std::string& config, cmGeneratorTarget const* headTarget,
  cmGeneratorExpressionDAGChecker* dagChecker,
397 398
  std::vector<std::string>& result, bool excludeImported,
  std::string const& language)
399 400
{
  if (const char* dirs =
401
        depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
402
    cmGeneratorExpression ge;
403 404
    cmSystemTools::ExpandListArgument(
      ge.Parse(dirs)->Evaluate(lg, config, false, headTarget, depTgt,
405
                               dagChecker, language),
406 407 408
      result);
  }
  if (!depTgt->IsImported() || excludeImported) {
409
    return;
410
  }
411 412

  if (const char* dirs =
413
        depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
414
    cmGeneratorExpression ge;
415 416
    cmSystemTools::ExpandListArgument(
      ge.Parse(dirs)->Evaluate(lg, config, false, headTarget, depTgt,
417
                               dagChecker, language),
418 419
      result);
  }
420 421
}

422
/* clang-format off */
423
#define IMPLEMENT_VISIT(KIND)                                                 \
424
  {                                                                           \
425
    KindedSources const& kinded = this->GetKindedSources(config);             \
426 427 428
    for (SourceAndKind const& s : kinded.Sources) {                           \
      if (s.Kind == KIND) {                                                   \
        data.push_back(s.Source);                                             \
429
      }                                                                       \
430 431 432
    }                                                                         \
  }
/* clang-format on */
433

434 435
void cmGeneratorTarget::GetObjectSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
436
{
437
  IMPLEMENT_VISIT(SourceKindObjectSource);
438

439
  if (!this->Objects.empty()) {
440
    return;
441
  }
442

443 444
  for (cmSourceFile const* it : data) {
    this->Objects[it];
445
  }
446 447

  this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
448 449
}

450
void cmGeneratorTarget::ComputeObjectMapping()
451
{
452
  if (!this->Objects.empty()) {
453
    return;
454
  }
455 456 457

  std::vector<std::string> configs;
  this->Makefile->GetConfigurations(configs);
458
  if (configs.empty()) {
459
    configs.emplace_back();
460
  }
461
  for (std::string const& c : configs) {
462
    std::vector<cmSourceFile const*> sourceFiles;
463
    this->GetObjectSources(sourceFiles, c);
464
  }
465 466
}

467 468 469
const char* cmGeneratorTarget::GetFeature(const std::string& feature,
                                          const std::string& config) const
{
470
  if (!config.empty()) {
471 472 473
    std::string featureConfig = feature;
    featureConfig += "_";
    featureConfig += cmSystemTools::UpperCase(config);
474
    if (const char* value = this->GetProperty(featureConfig)) {
475 476
      return value;
    }
477 478
  }
  if (const char* value = this->GetProperty(feature)) {
479
    return value;
480
  }
481
  return this->LocalGenerator->GetFeature(feature, config);
482 483
}

484 485
bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
                                     std::string const& config) const
486
{
487
  const char* feature = "INTERPROCEDURAL_OPTIMIZATION";
488 489 490 491 492 493 494
  const bool result = cmSystemTools::IsOn(this->GetFeature(feature, config));

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

495 496 497 498 499
  if (lang != "C" && lang != "CXX" && lang != "Fortran") {
    // We do not define IPO behavior for other languages.
    return false;
  }

500 501 502
  cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();

  if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
503
    if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
504 505 506 507 508 509
      return true;
    }
    if (this->PolicyReportedCMP0069) {
      // problem is already reported, no need to issue a message
      return false;
    }
510 511 512
    const bool in_try_compile =
      this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
    if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
513 514 515 516 517 518 519 520 521 522 523 524 525
      std::ostringstream w;
      w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0069) << "\n";
      w << "INTERPROCEDURAL_OPTIMIZATION property will be ignored for target "
        << "'" << this->GetName() << "'.";
      this->LocalGenerator->GetCMakeInstance()->IssueMessage(
        cmake::AUTHOR_WARNING, w.str(), this->GetBacktrace());

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

  // Note: check consistency with messages from CheckIPOSupported
Daniel Pfeifer's avatar
Daniel Pfeifer committed
526
  const char* message = nullptr;
527
  if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
528
    message = "CMake doesn't support IPO for current compiler";
529 530
  } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
                                   "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    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(
    cmake::FATAL_ERROR, message, this->GetBacktrace());
  return false;
551 552
}

553
const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
554
{
555 556
  this->ComputeObjectMapping();
  return this->Objects[file];
557 558
}

559 560 561 562 563 564 565 566 567
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
568
  return nullptr;
569 570
}

571
void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
572 573 574 575 576 577
{
  this->ExplicitObjectName.insert(sf);
}

bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
{
578
  const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
579 580
  std::set<cmSourceFile const*>::const_iterator it =
    this->ExplicitObjectName.find(file);
581 582 583
  return it != this->ExplicitObjectName.end();
}

584 585 586
void cmGeneratorTarget::GetModuleDefinitionSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
{
587
  IMPLEMENT_VISIT(SourceKindModuleDefinition);
588 589
}

590 591
void cmGeneratorTarget::GetHeaderSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
592
{
593
  IMPLEMENT_VISIT(SourceKindHeader);
594 595
}

596 597
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
                                        const std::string& config) const
598
{
599
  IMPLEMENT_VISIT(SourceKindExtra);
600 601
}

602 603
void cmGeneratorTarget::GetCustomCommands(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
604
{
605
  IMPLEMENT_VISIT(SourceKindCustomCommand);
606 607
}

608 609
void cmGeneratorTarget::GetExternalObjects(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
610
{
611
  IMPLEMENT_VISIT(SourceKindExternalObject);
612 613
}

614
void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& headers,
615
                                               const std::string& config) const
616
{
617 618
  KindedSources const& kinded = this->GetKindedSources(config);
  headers = kinded.ExpectedResxHeaders;
619 620
}

621
void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& data,
622
                                       const std::string& config) const
623
{
624
  IMPLEMENT_VISIT(SourceKindResx);
625 626
}

627 628
void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data,
                                       const std::string& config) const
629
{
630
  IMPLEMENT_VISIT(SourceKindAppManifest);
631 632
}

633 634
void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
                                     const std::string& config) const
635
{
636
  IMPLEMENT_VISIT(SourceKindManifest);
637 638
}

639 640
void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data,
                                        const std::string& config) const
641
{
642
  IMPLEMENT_VISIT(SourceKindCertificate);
643 644
}

645 646
void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers,
                                               const std::string& config) const
647
{
648 649
  KindedSources const& kinded = this->GetKindedSources(config);
  headers = kinded.ExpectedXamlHeaders;
650 651
}

652 653
void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs,
                                               const std::string& config) const
654
{
655 656
  KindedSources const& kinded = this->GetKindedSources(config);
  srcs = kinded.ExpectedXamlSources;
657 658 659 660
}

std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
{
661
  if (!this->UtilityItemsDone) {
662
    this->UtilityItemsDone = true;
663
    std::set<std::string> const& utilities = this->GetUtilities();
664
    for (std::string const& i : utilities) {
665
      cmGeneratorTarget* gt =
666 667
        this->LocalGenerator->FindGeneratorTargetToUse(i);
      this->UtilityItems.insert(cmLinkItem(i, gt));
668
    }
669
  }
670
  return this->UtilityItems;
671 672
}

673
void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data,
674
                                       const std::string& config) const
675
{
676
  IMPLEMENT_VISIT(SourceKindXaml);
677 678
}

679 680 681
const char* cmGeneratorTarget::GetLocation(const std::string& config) const
{
  static std::string location;
682
  if (this->IsImported()) {
683 684
    location = this->Target->ImportedGetFullPath(
      config, cmStateEnums::RuntimeBinaryArtifact);
685
  } else {
686
    location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
687
  }
688 689 690
  return location.c_str();
}

691 692
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
  const
693 694 695 696
{
  return this->Target->GetPreBuildCommands();
}

697 698
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
  const
699 700 701 702
{
  return this->Target->GetPreLinkCommands();
}

703 704
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
  const
705 706 707 708
{
  return this->Target->GetPostBuildCommands();
}

709 710 711 712 713
bool cmGeneratorTarget::IsImported() const
{
  return this->Target->IsImported();
}

714 715 716 717 718
bool cmGeneratorTarget::IsImportedGloballyVisible() const
{
  return this->Target->IsImportedGloballyVisible();
}

719 720 721
const char* cmGeneratorTarget::GetLocationForBuild() const
{
  static std::string location;
722
  if (this->IsImported()) {
723 724
    location = this->Target->ImportedGetFullPath(
      "", cmStateEnums::RuntimeBinaryArtifact);
725
    return location.c_str();
726
  }
727 728

  // Now handle the deprecated build-time configuration location.
729
  location = this->GetDirectory();
730
  const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
731
  if (cfgid && strcmp(cfgid, ".") != 0) {
732 733
    location += "/";
    location += cfgid;
734
  }
735

736
  if (this->IsAppBundleOnApple()) {
737
    std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
738
    if (!macdir.empty()) {
739 740 741
      location += "/";
      location += macdir;
    }
742
  }
743
  location += "/";
744
  location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
745 746 747
  return location.c_str();
}

748
bool cmGeneratorTarget::IsSystemIncludeDirectory(
749 750
  const std::string& dir, const std::string& config,
  const std::string& language) const
751
{
752
  assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
753
  std::string config_upper;
754
  if (!config.empty()) {
755
    config_upper = cmSystemTools::UpperCase(config);
756
  }
757

758
  typedef std::map<std::string, std::vector<std::string>> IncludeCacheType;
759
  IncludeCacheType::const_iterator iter =
760
    this->SystemIncludesCache.find(config_upper);
761

762
  if (iter == this->SystemIncludesCache.end()) {
763
    cmGeneratorExpressionDAGChecker dagChecker(
Daniel Pfeifer's avatar
Daniel Pfeifer committed
764
      this->GetName(), "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
765

766
    bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
767

768
    std::vector<std::string> result;
769
    for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
770
      cmGeneratorExpression ge;
771
      cmSystemTools::ExpandListArgument(
772
        ge.Parse(it)->Evaluate(this->LocalGenerator, config, false, this,
773
                               &dagChecker, language),
774 775
        result);
    }
776

777
    std::vector<cmGeneratorTarget const*> const& deps =
778
      this->GetLinkImplementationClosure(config);
779 780
    for (cmGeneratorTarget const* dep : deps) {
      handleSystemIncludesDep(this->LocalGenerator, dep, config, this,
781
                              &dagChecker, result, excludeImported, language);
782
    }
783

784 785 786 787
    std::for_each(result.begin(), result.end(),
                  cmSystemTools::ConvertToUnixSlashes);
    std::sort(result.begin(), result.end());
    result.erase(std::unique(result.begin(), result.end()), result.end());
788

789 790
    IncludeCacheType::value_type entry(config_upper, result);
    iter = this->SystemIncludesCache.insert(entry).first;
791
  }
792

793
  return std::binary_search(iter->second.begin(), iter->second.end(), dir);
794 795
}

796
bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
797 798 799 800
{
  return this->Target->GetPropertyAsBool(prop);
}

801 802 803 804 805
static void AddInterfaceEntries(
  cmGeneratorTarget const* thisTarget, std::string const& config,
  std::string const& prop,
  std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries)
{
806 807
  if (cmLinkImplementationLibraries const* impl =
        thisTarget->GetLinkImplementationLibraries(config)) {
808 809 810 811
    for (cmLinkImplItem const& lib : impl->Libraries) {
      if (lib.Target) {
        std::string genex = "$<TARGET_PROPERTY:" + lib + "," + prop + ">";
        cmGeneratorExpression ge(lib.Backtrace);
812
        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
813 814
        cge->SetEvaluateForBuildsystem(true);
        entries.push_back(
815
          new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
816 817
      }
    }
818
  }
819 820
}

821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
static void AddObjectEntries(
  cmGeneratorTarget const* thisTarget, std::string const& config,
  std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries)
{
  if (cmLinkImplementationLibraries const* impl =
        thisTarget->GetLinkImplementationLibraries(config)) {
    for (cmLinkImplItem const& lib : impl->Libraries) {
      if (lib.Target &&
          lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
        std::string genex = "$<TARGET_OBJECTS:" + lib + ">";
        cmGeneratorExpression ge(lib.Backtrace);
        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
        cge->SetEvaluateForBuildsystem(true);
        entries.push_back(
          new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
      }
    }
  }
}

841 842 843
static bool processSources(
  cmGeneratorTarget const* tgt,
  const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
844
  std::vector<std::string>& srcs, std::unordered_set<std::string>& uniqueSrcs,
845 846
  cmGeneratorExpressionDAGChecker* dagChecker, std::string const& config,
  bool debugSources)
847
{
848
  cmMakefile* mf = tgt->Target->GetMakefile();
849 850 851

  bool contextDependent = false;

852 853
  for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
    cmLinkImplItem const& item = entry->LinkImplItem;
854 855
    std::string const& targetName = item;
    std::vector<std::string> entrySources;
856
    cmSystemTools::ExpandListArgument(
857
      entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
858 859 860
                          dagChecker),
      entrySources);

861
    if (entry->ge->GetHadContextSensitiveCondition()) {
862
      contextDependent = true;
863
    }
864

865
    for (std::string& src : entrySources) {
866 867 868
      cmSourceFile* sf = mf->GetOrCreateSource(src);
      std::string e;
      std::string fullPath = sf->GetFullPath(&e);
869 870
      if (fullPath.empty()) {
        if (!e.empty()) {
871
          cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
872
          cm->IssueMessage(cmake::FATAL_ERROR, e, tgt->GetBacktrace());
873
        }
874 875
        return contextDependent;
      }
876

877
      if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) {
878
        std::ostringstream err;
879 880
        if (!targetName.empty()) {
          err << "Target \"" << targetName
881
              << "\" contains relative path in its INTERFACE_SOURCES:\n  \""
882 883
              << src << "\"";
        } else {
884
          err << "Found relative path while evaluating sources of \""
885 886
              << tgt->GetName() << "\":\n  \"" << src << "\"\n";
        }
887 888 889
        tgt->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, err.str());
        return contextDependent;
      }
890 891
      src = fullPath;
    }
892
    std::string usedSources;
893
    for (std::string const& src : entrySources) {
894
      if (uniqueSrcs.insert(src).second) {
895
        srcs.push_back(src);
896
        if (debugSources) {
897 898 899 900
          usedSources