cmGeneratorTarget.cxx 199 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
  , DebugLinkDirectoriesDone(false)
107 108 109
  , DebugSourcesDone(false)
  , LinkImplementationLanguageIsContextDependent(true)
  , UtilityItemsDone(false)
110 111
{
  this->Makefile = this->Target->GetMakefile();
112
  this->LocalGenerator = lg;
113
  this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
114

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

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

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

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

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

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

137 138 139 140
  CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
                                     t->GetLinkDirectoriesBacktraces(),
                                     this->LinkDirectoriesEntries);

141 142 143
  CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
                                     t->GetSourceBacktraces(),
                                     this->SourceEntries, true);
144

145
  this->DLLPlatform =
146
    !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
147 148

  this->PolicyMap = t->PolicyMap;
149 150
}

151 152
cmGeneratorTarget::~cmGeneratorTarget()
{
153
  cmDeleteAll(this->IncludeDirectoriesEntries);
154
  cmDeleteAll(this->CompileOptionsEntries);
155
  cmDeleteAll(this->CompileFeaturesEntries);
156
  cmDeleteAll(this->CompileDefinitionsEntries);
157
  cmDeleteAll(this->LinkOptionsEntries);
158
  cmDeleteAll(this->LinkDirectoriesEntries);
159
  cmDeleteAll(this->SourceEntries);
160 161 162
  cmDeleteAll(this->LinkInformation);
}

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

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

180 181 182 183 184
cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
{
  return this->LocalGenerator;
}

185
cmStateEnums::TargetType cmGeneratorTarget::GetType() const
186 187 188 189
{
  return this->Target->GetType();
}

190
const std::string& cmGeneratorTarget::GetName() const
191 192 193 194
{
  return this->Target->GetName();
}

195 196
std::string cmGeneratorTarget::GetExportName() const
{
197
  const char* exportName = this->GetProperty("EXPORT_NAME");
198

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

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

229 230 231 232 233 234 235 236 237
const char* cmGeneratorTarget::GetSafeProperty(const std::string& prop) const
{
  const char* ret = this->GetProperty(prop);
  if (!ret) {
    return "";
  }
  return ret;
}

238 239
const char* cmGeneratorTarget::GetOutputTargetType(
  cmStateEnums::ArtifactType artifact) const
240
{
241
  switch (this->GetType()) {
242
    case cmStateEnums::SHARED_LIBRARY:
243
      if (this->IsDLLPlatform()) {
244 245 246 247 248 249 250
        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";
251
        }
252
      } else {
253 254 255
        // For non-DLL platforms shared libraries are treated as
        // library targets.
        return "LIBRARY";
256
      }
257
      break;
258
    case cmStateEnums::STATIC_LIBRARY:
259 260
      // Static libraries are always treated as archive targets.
      return "ARCHIVE";
261
    case cmStateEnums::MODULE_LIBRARY:
262 263
      switch (artifact) {
        case cmStateEnums::RuntimeBinaryArtifact:
264
          // Module libraries are always treated as library targets.
265 266
          return "LIBRARY";
        case cmStateEnums::ImportLibraryArtifact:
267
          // Module import libraries are treated as archive targets.
268
          return "ARCHIVE";
269
      }
270
      break;
271 272 273
    case cmStateEnums::OBJECT_LIBRARY:
      // Object libraries are always treated as object targets.
      return "OBJECT";
274
    case cmStateEnums::EXECUTABLE:
275 276 277 278 279 280 281
      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";
282
      }
283
      break;
284 285
    default:
      break;
286
  }
287 288 289
  return "";
}

290 291
std::string cmGeneratorTarget::GetOutputName(
  const std::string& config, cmStateEnums::ArtifactType artifact) const
292
{
293
  // Lookup/compute/cache the output name for this configuration.
294
  OutputNameKey key(config, artifact);
295 296
  cmGeneratorTarget::OutputNameMapType::iterator i =
    this->OutputNameMap.find(key);
297
  if (i == this->OutputNameMap.end()) {
298 299 300
    // Add empty name in map to detect potential recursion.
    OutputNameMapType::value_type entry(key, "");
    i = this->OutputNameMap.insert(entry).first;
301

302 303
    // Compute output name.
    std::vector<std::string> props;
304
    std::string type = this->GetOutputTargetType(artifact);
305
    std::string configUpper = cmSystemTools::UpperCase(config);
306
    if (!type.empty() && !configUpper.empty()) {
307 308
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
      props.push_back(type + "_OUTPUT_NAME_" + configUpper);
309 310
    }
    if (!type.empty()) {
311 312
      // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
      props.push_back(type + "_OUTPUT_NAME");
313 314
    }
    if (!configUpper.empty()) {
315 316 317 318
      // OUTPUT_NAME_<CONFIG>
      props.push_back("OUTPUT_NAME_" + configUpper);
      // <CONFIG>_OUTPUT_NAME
      props.push_back(configUpper + "_OUTPUT_NAME");
319
    }
320 321
    // OUTPUT_NAME
    props.push_back("OUTPUT_NAME");
322

323
    std::string outName;
324 325
    for (std::string const& p : props) {
      if (const char* outNameProp = this->GetProperty(p)) {
326 327 328
        outName = outNameProp;
        break;
      }
329
    }
330

331
    if (outName.empty()) {
332
      outName = this->GetName();
333
    }
334 335 336

    // Now evaluate genex and update the previously-prepared map entry.
    cmGeneratorExpression ge;
337
    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
338
    i->second = cge->Evaluate(this->LocalGenerator, config);
339
  } else if (i->second.empty()) {
340 341
    // An empty map entry indicates we have been called recursively
    // from the above block.
342
    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
343 344
      cmake::FATAL_ERROR,
      "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
345
      this->GetBacktrace());
346
  }
347
  return i->second;
348 349
}

350 351 352 353 354 355 356
void cmGeneratorTarget::ClearSourcesCache()
{
  this->KindedSourcesMap.clear();
  this->LinkImplementationLanguageIsContextDependent = true;
  this->Objects.clear();
}

357
void cmGeneratorTarget::AddSourceCommon(const std::string& src)
358
{
359 360
  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
  cmGeneratorExpression ge(lfbt);
361
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
362
  cge->SetEvaluateForBuildsystem(true);
363
  this->SourceEntries.push_back(new TargetPropertyEntry(std::move(cge)));
364
  this->ClearSourcesCache();
365 366
}

367 368 369 370 371 372
void cmGeneratorTarget::AddSource(const std::string& src)
{
  this->Target->AddSource(src);
  this->AddSourceCommon(src);
}

373 374 375
void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
  this->Target->AddTracedSources(srcs);
376
  if (!srcs.empty()) {
377
    this->AddSourceCommon(cmJoin(srcs, ";"));
378
  }
379 380
}

381 382 383 384 385 386
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);
387
  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
388 389 390 391 392
  cge->SetEvaluateForBuildsystem(true);
  // Insert before begin/end
  std::vector<TargetPropertyEntry*>::iterator pos = before
    ? this->IncludeDirectoriesEntries.begin()
    : this->IncludeDirectoriesEntries.end();
393 394
  this->IncludeDirectoriesEntries.insert(
    pos, new TargetPropertyEntry(std::move(cge)));
395 396
}

397 398
std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
  cmSourceFile const* sf) const
399
{
400
  SourceEntriesType::const_iterator i = this->SourceDepends.find(sf);
401
  if (i != this->SourceDepends.end()) {
402
    return &i->second.Depends;
403
  }
Daniel Pfeifer's avatar
Daniel Pfeifer committed
404
  return nullptr;
405 406
}

407 408 409 410
static void handleSystemIncludesDep(
  cmLocalGenerator* lg, cmGeneratorTarget const* depTgt,
  const std::string& config, cmGeneratorTarget const* headTarget,
  cmGeneratorExpressionDAGChecker* dagChecker,
411 412
  std::vector<std::string>& result, bool excludeImported,
  std::string const& language)
413 414
{
  if (const char* dirs =
415
        depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
416
    cmGeneratorExpression ge;
417 418
    cmSystemTools::ExpandListArgument(
      ge.Parse(dirs)->Evaluate(lg, config, false, headTarget, depTgt,
419
                               dagChecker, language),
420 421 422
      result);
  }
  if (!depTgt->IsImported() || excludeImported) {
423
    return;
424
  }
425 426

  if (const char* dirs =
427
        depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
428
    cmGeneratorExpression ge;
429 430
    cmSystemTools::ExpandListArgument(
      ge.Parse(dirs)->Evaluate(lg, config, false, headTarget, depTgt,
431
                               dagChecker, language),
432 433
      result);
  }
434 435
}

436
/* clang-format off */
437
#define IMPLEMENT_VISIT(KIND)                                                 \
438
  {                                                                           \
439
    KindedSources const& kinded = this->GetKindedSources(config);             \
440 441 442
    for (SourceAndKind const& s : kinded.Sources) {                           \
      if (s.Kind == KIND) {                                                   \
        data.push_back(s.Source);                                             \
443
      }                                                                       \
444 445 446
    }                                                                         \
  }
/* clang-format on */
447

448 449
void cmGeneratorTarget::GetObjectSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
450
{
451
  IMPLEMENT_VISIT(SourceKindObjectSource);
452

453
  if (!this->Objects.empty()) {
454
    return;
455
  }
456

457 458
  for (cmSourceFile const* it : data) {
    this->Objects[it];
459
  }
460 461

  this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
462 463
}

464
void cmGeneratorTarget::ComputeObjectMapping()
465
{
466
  if (!this->Objects.empty()) {
467
    return;
468
  }
469 470 471

  std::vector<std::string> configs;
  this->Makefile->GetConfigurations(configs);
472
  if (configs.empty()) {
473
    configs.emplace_back();
474
  }
475
  for (std::string const& c : configs) {
476
    std::vector<cmSourceFile const*> sourceFiles;
477
    this->GetObjectSources(sourceFiles, c);
478
  }
479 480
}

481 482 483
const char* cmGeneratorTarget::GetFeature(const std::string& feature,
                                          const std::string& config) const
{
484
  if (!config.empty()) {
485 486 487
    std::string featureConfig = feature;
    featureConfig += "_";
    featureConfig += cmSystemTools::UpperCase(config);
488
    if (const char* value = this->GetProperty(featureConfig)) {
489 490
      return value;
    }
491 492
  }
  if (const char* value = this->GetProperty(feature)) {
493
    return value;
494
  }
495
  return this->LocalGenerator->GetFeature(feature, config);
496 497
}

498 499
bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
                                     std::string const& config) const
500
{
501
  const char* feature = "INTERPROCEDURAL_OPTIMIZATION";
502 503 504 505 506 507 508
  const bool result = cmSystemTools::IsOn(this->GetFeature(feature, config));

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

509 510 511 512 513
  if (lang != "C" && lang != "CXX" && lang != "Fortran") {
    // We do not define IPO behavior for other languages.
    return false;
  }

514 515 516
  cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();

  if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
517
    if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
518 519 520 521 522 523
      return true;
    }
    if (this->PolicyReportedCMP0069) {
      // problem is already reported, no need to issue a message
      return false;
    }
524 525 526
    const bool in_try_compile =
      this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile();
    if (cmp0069 == cmPolicies::WARN && !in_try_compile) {
527 528 529 530 531 532 533 534 535 536 537 538 539
      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
540
  const char* message = nullptr;
541
  if (!this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_SUPPORTED_BY_CMAKE")) {
542
    message = "CMake doesn't support IPO for current compiler";
543 544
  } else if (!this->Makefile->IsOn("_CMAKE_" + lang +
                                   "_IPO_MAY_BE_SUPPORTED_BY_COMPILER")) {
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    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;
565 566
}

567
const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
568
{
569 570
  this->ComputeObjectMapping();
  return this->Objects[file];
571 572
}

573 574 575 576 577 578 579 580 581
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
582
  return nullptr;
583 584
}

585
void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile const* sf)
586 587 588 589 590 591
{
  this->ExplicitObjectName.insert(sf);
}

bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
{
592
  const_cast<cmGeneratorTarget*>(this)->ComputeObjectMapping();
593 594
  std::set<cmSourceFile const*>::const_iterator it =
    this->ExplicitObjectName.find(file);
595 596 597
  return it != this->ExplicitObjectName.end();
}

598 599 600
void cmGeneratorTarget::GetModuleDefinitionSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
{
601
  IMPLEMENT_VISIT(SourceKindModuleDefinition);
602 603
}

604 605
void cmGeneratorTarget::GetHeaderSources(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
606
{
607
  IMPLEMENT_VISIT(SourceKindHeader);
608 609
}

610 611
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
                                        const std::string& config) const
612
{
613
  IMPLEMENT_VISIT(SourceKindExtra);
614 615
}

616 617
void cmGeneratorTarget::GetCustomCommands(
  std::vector<cmSourceFile const*>& data, const std::string& config) const
618
{
619
  IMPLEMENT_VISIT(SourceKindCustomCommand);
620 621
}

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

628
void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& headers,
629
                                               const std::string& config) const
630
{
631 632
  KindedSources const& kinded = this->GetKindedSources(config);
  headers = kinded.ExpectedResxHeaders;
633 634
}

635
void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& data,
636
                                       const std::string& config) const
637
{
638
  IMPLEMENT_VISIT(SourceKindResx);
639 640
}

641 642
void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data,
                                       const std::string& config) const
643
{
644
  IMPLEMENT_VISIT(SourceKindAppManifest);
645 646
}

647 648
void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
                                     const std::string& config) const
649
{
650
  IMPLEMENT_VISIT(SourceKindManifest);
651 652
}

653 654
void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data,
                                        const std::string& config) const
655
{
656
  IMPLEMENT_VISIT(SourceKindCertificate);
657 658
}

659 660
void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers,
                                               const std::string& config) const
661
{
662 663
  KindedSources const& kinded = this->GetKindedSources(config);
  headers = kinded.ExpectedXamlHeaders;
664 665
}

666 667
void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs,
                                               const std::string& config) const
668
{
669 670
  KindedSources const& kinded = this->GetKindedSources(config);
  srcs = kinded.ExpectedXamlSources;
671 672 673 674
}

std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
{
675
  if (!this->UtilityItemsDone) {
676
    this->UtilityItemsDone = true;
677
    std::set<std::string> const& utilities = this->GetUtilities();
678
    for (std::string const& i : utilities) {
679 680 681 682 683 684
      if (cmGeneratorTarget* gt =
            this->LocalGenerator->FindGeneratorTargetToUse(i)) {
        this->UtilityItems.insert(cmLinkItem(gt));
      } else {
        this->UtilityItems.insert(cmLinkItem(i));
      }
685
    }
686
  }
687
  return this->UtilityItems;
688 689
}

690
void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data,
691
                                       const std::string& config) const
692
{
693
  IMPLEMENT_VISIT(SourceKindXaml);
694 695
}

696 697 698
const char* cmGeneratorTarget::GetLocation(const std::string& config) const
{
  static std::string location;
699
  if (this->IsImported()) {
700 701
    location = this->Target->ImportedGetFullPath(
      config, cmStateEnums::RuntimeBinaryArtifact);
702
  } else {
703
    location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
704
  }
705 706 707
  return location.c_str();
}

708 709
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
  const
710 711 712 713
{
  return this->Target->GetPreBuildCommands();
}

714 715
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreLinkCommands()
  const
716 717 718 719
{
  return this->Target->GetPreLinkCommands();
}

720 721
std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
  const
722 723 724 725
{
  return this->Target->GetPostBuildCommands();
}

726 727 728 729 730
bool cmGeneratorTarget::IsImported() const
{
  return this->Target->IsImported();
}

731 732 733 734 735
bool cmGeneratorTarget::IsImportedGloballyVisible() const
{
  return this->Target->IsImportedGloballyVisible();
}

736 737 738
const char* cmGeneratorTarget::GetLocationForBuild() const
{
  static std::string location;
739
  if (this->IsImported()) {
740 741
    location = this->Target->ImportedGetFullPath(
      "", cmStateEnums::RuntimeBinaryArtifact);
742
    return location.c_str();
743
  }
744 745

  // Now handle the deprecated build-time configuration location.
746
  location = this->GetDirectory();
747
  const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
748
  if (cfgid && strcmp(cfgid, ".") != 0) {
749 750
    location += "/";
    location += cfgid;
751
  }
752

753
  if (this->IsAppBundleOnApple()) {
754
    std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
755
    if (!macdir.empty()) {
756 757 758
      location += "/";
      location += macdir;
    }
759
  }
760
  location += "/";
761
  location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
762 763 764
  return location.c_str();
}

765
bool cmGeneratorTarget::IsSystemIncludeDirectory(
766 767
  const std::string& dir, const std::string& config,
  const std::string& language) const
768
{
769
  assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
770
  std::string config_upper;
771
  if (!config.empty()) {
772
    config_upper = cmSystemTools::UpperCase(config);
773
  }
774

775
  typedef std::map<std::string, std::vector<std::string>> IncludeCacheType;
776
  IncludeCacheType::const_iterator iter =
777
    this->SystemIncludesCache.find(config_upper);
778

779
  if (iter == this->SystemIncludesCache.end()) {
780
    cmGeneratorExpressionDAGChecker dagChecker(
781
      this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
782

783
    bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
784

785
    std::vector<std::string> result;
786
    for (std::string const& it : this->Target->GetSystemIncludeDirectories()) {
787
      cmGeneratorExpression ge;
788
      cmSystemTools::ExpandListArgument(
789
        ge.Parse(it)->Evaluate(this->LocalGenerator, config, false, this,
790
                               &dagChecker, language),
791 792
        result);
    }
793

794
    std::vector<cmGeneratorTarget const*> const& deps =
795
      this->GetLinkImplementationClosure(config);
796 797
    for (cmGeneratorTarget const* dep : deps) {
      handleSystemIncludesDep(this->LocalGenerator, dep, config, this,
798
                              &dagChecker, result, excludeImported, language);
799
    }
800

801 802 803 804
    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());
805

806 807
    IncludeCacheType::value_type entry(config_upper, result);
    iter = this->SystemIncludesCache.insert(entry).first;
808
  }
809

810
  return std::binary_search(iter->second.begin(), iter->second.end(), dir);
811 812
}

813
bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const
814 815 816 817
{
  return this->Target->GetPropertyAsBool(prop);
}

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

842 843 844 845 846 847 848 849 850
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) {
851 852 853 854
        std::string uniqueName =
          thisTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
            lib.Target);
        std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
855 856 857 858 859 860 861 862 863 864
        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));
      }
    }
  }
}

865 866 867
static bool processSources(
  cmGeneratorTarget const* tgt,
  const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
868
  std::vector<std::string>& srcs, std::unordered_set<std::string>& uniqueSrcs,
869 870
  cmGeneratorExpressionDAGChecker* dagChecker, std::string const& config,
  bool debugSources)
871
{
872
  cmMakefile* mf = tgt->Target->GetMakefile();
873 874 875

  bool contextDependent = false;

876 877
  for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
    cmLinkImplItem const& item = entry->LinkImplItem;
878
    std::string const& targetName = item.AsStr();
879
    std::vector<std::string> entrySources;
880
    cmSystemTools::ExpandListArgument(
881
      entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
882 883 884
                          dagChecker),
      entrySources);

885
    if (entry->ge->GetHadContextSensitiveCondition()) {
886
      contextDependent = true;
887
    }
888

889
    for (std::string& src : entrySources) {
890 891 892
      cmSourceFile* sf = mf->GetOrCreateSource(src);
      std::string e;
      std::string fullPath = sf->GetFullPath(&e);
893 894
      if (fullPath.empty()) {
        if (!e.empty()) {
895
          cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
896
          cm->IssueMessage(cmake::FATAL_ERROR, e, tgt->GetBacktrace());
897
        }
898 899
        return contextDependent;
      }
900

901
      if (!targetName.empty() && !cmSystemTools::FileIsFullPath(src)) {
902
        std::ostringstream err;
903 904
        if (!targetName.empty()) {
          err << "Target \"" << targetName
905
              << "\" contains relative path in its INTERFACE_SOURCES:\n  \""
906 907
              << src << "\"";
        } else {
908
          err << "Found relative path while evaluating sources of \""
909 910
              << tgt->GetName() << "\":\n  \"" << src << "\"\n";
        }
911 912 913
        tgt->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, err.str());
        return contextDependent;
      }
914 915
      src = fullPath;
    }
916
    std::string usedSources;
917
    for (std::string const& src : entrySources) {
918
      if (uniqueSrcs.insert(src).second) {
919
        srcs.push_back(src);
920
        if (debugSources) {
921 922 923 924
          usedSources += " * " + src + "\n";
        }
      }
    }
925 926
    if (!usedSources.empty()) {
      tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
927 928 929
        cmake::LOG,
        std::string("Used sources for target ") + tgt->GetName() + ":\n" +
          usedSources,
930
        entry->ge->GetBacktrace());
931 932
    }
  }
933 934 935
  return contextDependent;
}

936 937
void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
                                       const std::string& config) const
938
{
939
  assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
940

941
  if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
942 943 944 945 946 947 948
    // At configure-time, this method can be called as part of getting the
    // LOCATION property or to export() a file to be include()d.  However
    // there is no cmGeneratorTarget at configure-time, so search the SOURCES
    // for TARGET_OBJECTS instead for backwards compatibility with OLD
    // behavior of CMP0024 and CMP0026 only.

    cmStringRange sourceEntries = this->Target->GetSourceEntries();
949
    for (std::string const& entry : sourceEntries) {
950 951
      std::vector<std::string> items;
      cmSystemTools::ExpandListArgument(entry, items);
952 953 954
      for (std::string const& item : items) {
        if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
            item[item.size() - 1] == '>') {
955 956
          continue;
        }
957
        files.push_back(item);
958 959
      }
    }
960 961
    return;
  }
962 963

  std::vector<std::string> debugProperties;
964 965 966
  const char* debugProp =
    this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
  if (debugProp) {
967
    cmSystemTools::ExpandListArgument(debugProp, debugProperties);
968
  }
969

970 971 972
  bool debugSources = !this->DebugSourcesDone &&
    std::find(debugProperties.begin(), debugProperties.end(), "SOURCES") !=
      debugProperties.end();
973

974
  if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
975
    this->DebugSourcesDone = true;
976
  }
977

978 979
  cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
                                             nullptr);
980

981
  std::unordered_set<std::string> uniqueSrcs;
982 983 984
  bool contextDependentDirectSources =
    processSources(this, this->SourceEntries, files, uniqueSrcs, &dagChecker,
                   config, debugSources);
985

986
  // Collect INTERFACE_SOURCES of all direct link-dependencies.
987 988
  std::vector<cmGeneratorTarget::TargetPropertyEntry*>
    linkInterfaceSourcesEntries;
989 990
  AddInterfaceEntries(this, config, "INTERFACE_SOURCES",
                      linkInterfaceSourcesEntries);
991
  std::vector<std::string>::size_type numFilesBefore = files.size();
992 993 994 995
  bool contextDependentInterfaceSources =
    processSources(this, linkInterfaceSourcesEntries, files, uniqueSrcs,
                   &dagChecker, config, debugSources);

996 997 998 999 1000 1001 1002 1003
  // Collect TARGET_OBJECTS of direct object link-dependencies.
  std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkObjectsEntries;
  AddObjectEntries(this, config, linkObjectsEntries);
  std::vector<std::string>::size_type numFilesBefore2 = files.size();
  bool contextDependentObjects =
    processSources(this, linkObjectsEntries, files, uniqueSrcs, &dagChecker,
                   config, debugSources);

1004
  if (!contextDependentDirectSources &&
1005 1006
      !(contextDependentInterfaceSources && numFilesBefore < files.size()) &&
      !(contextDependentObjects && numFilesBefore2 < files.size())) {
1007
    this->LinkImplementationLanguageIsContextDependent = false;
1008
  }
1009 1010

  cmDeleteAll(linkInterfaceSourcesEntries);
1011
  cmDeleteAll(linkObjectsEntries);
1012 1013
}

1014
void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
1015
                                       const std::string& config) const
1016
{
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
  if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
    // Since we are still configuring not all sources may exist yet,
    // so we need to avoid full source classification because that
    // requires the absolute paths to all sources to be determined.
    // Since this is only for compatibility with old policies that
    // projects should not depend on anymore, just compute the files
    // without memoizing them.
    std::vector<std::string> srcs;
    this->GetSourceFiles(srcs, config);
    std::set<cmSourceFile*> emitted;
1027 1028
    for (std::string const& s : srcs) {
      cmSourceFile* sf = this->Makefile->GetOrCreateSource(s);
1029 1030 1031 1032 1033 1034 1035
      if (emitted.insert(sf).second) {
        files.push_back(sf);
      }
    }
    return;
  }

1036 1037
  KindedSources const& kinded = this->GetKindedSources(config);
  files.reserve(kinded.Sources.size());
1038 1039
  for (SourceAndKind const& si : kinded.Sources) {
    files.push_back(si.Source);
1040 1041
  }
}
1042

1043 1044 1045 1046 1047
void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
  std::vector<cmSourceFile*>& files, const std::string& config) const
{
  KindedSources const& kinded = this->GetKindedSources(config);
  files.reserve(kinded.Sources.size());
1048 1049 1050
  for (SourceAndKind const& si : kinded.Sources) {
    if (si.Source->GetObjectLibrary().empty()) {
      files.push_back(si.Source);
1051 1052 1053 1054
    }
  }
}

1055 1056 1057 1058 1059
cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
  std::string const& config) const
{
  // If we already processed one configuration and found no dependenc
  // on configuration then always use the one result.
1060
  if (!this->LinkImplementationLanguageIsContextDependent) {
1061
    return this->KindedSourcesMap.begin()->second;
1062
  }
1063

1064 1065 1066 1067
  // Lookup any existing link implementation for this configuration.
  std::string const key = cmSystemTools::UpperCase(config);
  KindedSourcesMapType::iterator it = this->KindedSourcesMap.find(key);
  if (it != this->KindedSourcesMap.end()) {
Brad King's avatar