cmTarget.cxx 51.1 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
#include "cmTarget.h"
Brad King's avatar
Brad King committed
4

5
#include "cmAlgorithms.h"
6
#include "cmGeneratorExpression.h"
7
#include "cmGeneratorTarget.h"
8 9 10
#include "cmGlobalGenerator.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
11
#include "cmMessenger.h"
12
#include "cmOutputConverter.h"
13
#include "cmProperty.h"
14
#include "cmSourceFile.h"
15 16
#include "cmSourceFileLocation.h"
#include "cmSystemTools.h"
17
#include "cmTargetPropertyComputer.h"
18
#include "cmake.h"
19 20

#include <algorithm>
21
#include <assert.h>
22
#include <cmsys/RegularExpression.hxx>
23 24
#include <map>
#include <set>
25 26
#include <sstream>
#include <string.h>
27 28 29 30 31

#if defined(CMake_HAVE_CXX_UNORDERED_SET)
#include <unordered_set>
#define UNORDERED_SET std::unordered_set
#elif defined(CMAKE_BUILD_WITH_CMAKE)
32 33 34 35 36
#include <cmsys/hash_set.hxx>
#define UNORDERED_SET cmsys::hash_set
#else
#define UNORDERED_SET std::set
#endif
Nicolas Despres's avatar
Nicolas Despres committed
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
template <>
const char* cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
  cmTarget const* tgt)
{
  static std::string loc;
  if (tgt->IsImported()) {
    loc = tgt->ImportedGetFullPath("", false);
    return loc.c_str();
  }

  cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
  if (!gg->GetConfigureDoneCMP0026()) {
    gg->CreateGenerationObjects();
  }
  cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
  loc = gt->GetLocationForBuild();
  return loc.c_str();
}

template <>
const char* cmTargetPropertyComputer::ComputeLocation<cmTarget>(
  cmTarget const* tgt, const std::string& config)
{
  static std::string loc;
  if (tgt->IsImported()) {
    loc = tgt->ImportedGetFullPath(config, false);
    return loc.c_str();
  }

  cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
  if (!gg->GetConfigureDoneCMP0026()) {
    gg->CreateGenerationObjects();
  }
  cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
  loc = gt->GetFullPath(config, false);
  return loc.c_str();
}

template <>
const char* cmTargetPropertyComputer::GetSources<cmTarget>(
  cmTarget const* tgt, cmMessenger* messenger,
  cmListFileBacktrace const& context)
{
  cmStringRange entries = tgt->GetSourceEntries();
  if (entries.empty()) {
    return CM_NULLPTR;
  }

  std::ostringstream ss;
  const char* sep = "";
  for (std::vector<std::string>::const_iterator i = entries.begin();
       i != entries.end(); ++i) {
    std::string const& entry = *i;

    std::vector<std::string> files;
    cmSystemTools::ExpandListArgument(entry, files);
    for (std::vector<std::string>::const_iterator li = files.begin();
         li != files.end(); ++li) {
      if (cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") &&
          (*li)[li->size() - 1] == '>') {
        std::string objLibName = li->substr(17, li->size() - 18);

        if (cmGeneratorExpression::Find(objLibName) != std::string::npos) {
          ss << sep;
          sep = ";";
          ss << *li;
          continue;
        }

        bool addContent = false;
        bool noMessage = true;
        std::ostringstream e;
        cmake::MessageType messageType = cmake::AUTHOR_WARNING;
        switch (context.GetBottom().GetPolicy(cmPolicies::CMP0051)) {
          case cmPolicies::WARN:
            e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
            noMessage = false;
          case cmPolicies::OLD:
            break;
          case cmPolicies::REQUIRED_ALWAYS:
          case cmPolicies::REQUIRED_IF_USED:
          case cmPolicies::NEW:
            addContent = true;
        }
        if (!noMessage) {
          e << "Target \"" << tgt->GetName()
            << "\" contains "
               "$<TARGET_OBJECTS> generator expression in its sources "
               "list.  "
               "This content was not previously part of the SOURCES "
               "property "
               "when that property was read at configure time.  Code "
               "reading "
               "that property needs to be adapted to ignore the generator "
               "expression using the string(GENEX_STRIP) command.";
          messenger->IssueMessage(messageType, e.str(), context);
        }
        if (addContent) {
          ss << sep;
          sep = ";";
          ss << *li;
        }
      } else if (cmGeneratorExpression::Find(*li) == std::string::npos) {
        ss << sep;
        sep = ";";
        ss << *li;
      } else {
        cmSourceFile* sf = tgt->GetMakefile()->GetOrCreateSource(*li);
        // Construct what is known about this source file location.
        cmSourceFileLocation const& location = sf->GetLocation();
        std::string sname = location.GetDirectory();
        if (!sname.empty()) {
          sname += "/";
        }
        sname += location.GetName();

        ss << sep;
        sep = ";";
        // Append this list entry.
        ss << sname;
      }
    }
  }
  static std::string srcs;
  srcs = ss.str();
  return srcs.c_str();
}

166 167 168
class cmTargetInternals
{
public:
169 170
  std::vector<std::string> IncludeDirectoriesEntries;
  std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
171 172
  std::vector<std::string> CompileOptionsEntries;
  std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
173 174
  std::vector<std::string> CompileFeaturesEntries;
  std::vector<cmListFileBacktrace> CompileFeaturesBacktraces;
175 176
  std::vector<std::string> CompileDefinitionsEntries;
  std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
177 178
  std::vector<std::string> SourceEntries;
  std::vector<cmListFileBacktrace> SourceBacktraces;
179 180
  std::vector<std::string> LinkImplementationPropertyEntries;
  std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
181 182
};

183 184
cmTarget::cmTarget(std::string const& name, cmState::TargetType type,
                   Visibility vis, cmMakefile* mf)
185
{
186
  assert(mf);
187 188
  this->Name = name;
  this->TargetTypeValue = type;
189
  this->Makefile = mf;
Ken Martin's avatar
Ken Martin committed
190
  this->HaveInstallRule = false;
191
  this->DLLPlatform = false;
192
  this->IsAndroid = false;
193 194 195
  this->IsImportedTarget =
    (vis == VisibilityImported || vis == VisibilityImportedGlobally);
  this->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
196
  this->BuildInterfaceIncludesAppended = false;
197

198
  // only add dependency information for library targets
199 200
  if (this->TargetTypeValue >= cmState::STATIC_LIBRARY &&
      this->TargetTypeValue <= cmState::MODULE_LIBRARY) {
Ken Martin's avatar
Ken Martin committed
201
    this->RecordDependencies = true;
202
  } else {
Ken Martin's avatar
Ken Martin committed
203
    this->RecordDependencies = false;
204
  }
205

206
  // Check whether this is a DLL platform.
207 208 209
  this->DLLPlatform =
    (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") ||
     this->Makefile->IsOn("MINGW"));
210

211 212 213 214 215
  // Check whether we are targeting an Android platform.
  this->IsAndroid =
    strcmp(this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"),
           "Android") == 0;

216
  // Setup default property values.
217 218
  if (this->GetType() != cmState::INTERFACE_LIBRARY &&
      this->GetType() != cmState::UTILITY) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    this->SetPropertyDefault("ANDROID_API", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_API_MIN", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_ARCH", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_STL_TYPE", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_SKIP_ANT_STEP", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_PROCESS_MAX", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_PROGUARD", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_PROGUARD_CONFIG_PATH", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_SECURE_PROPS_PATH", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_NATIVE_LIB_DIRECTORIES", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_NATIVE_LIB_DEPENDENCIES", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_JAVA_SOURCE_DIR", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_JAR_DIRECTORIES", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_JAR_DEPENDENCIES", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", CM_NULLPTR);
    this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", CM_NULLPTR);
235
    this->SetPropertyDefault("BUILD_RPATH", CM_NULLPTR);
Daniel Pfeifer's avatar
Daniel Pfeifer committed
236
    this->SetPropertyDefault("INSTALL_NAME_DIR", CM_NULLPTR);
237 238 239 240
    this->SetPropertyDefault("INSTALL_RPATH", "");
    this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
    this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
    this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
Daniel Pfeifer's avatar
Daniel Pfeifer committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", CM_NULLPTR);
    this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", CM_NULLPTR);
    this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", CM_NULLPTR);
    this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", CM_NULLPTR);
    this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", CM_NULLPTR);
    this->SetPropertyDefault("Fortran_FORMAT", CM_NULLPTR);
    this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", CM_NULLPTR);
    this->SetPropertyDefault("GNUtoMS", CM_NULLPTR);
    this->SetPropertyDefault("OSX_ARCHITECTURES", CM_NULLPTR);
    this->SetPropertyDefault("IOS_INSTALL_COMBINED", CM_NULLPTR);
    this->SetPropertyDefault("AUTOMOC", CM_NULLPTR);
    this->SetPropertyDefault("AUTOUIC", CM_NULLPTR);
    this->SetPropertyDefault("AUTORCC", CM_NULLPTR);
    this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", CM_NULLPTR);
    this->SetPropertyDefault("AUTOUIC_OPTIONS", CM_NULLPTR);
    this->SetPropertyDefault("AUTORCC_OPTIONS", CM_NULLPTR);
    this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", CM_NULLPTR);
    this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", CM_NULLPTR);
    this->SetPropertyDefault("WIN32_EXECUTABLE", CM_NULLPTR);
    this->SetPropertyDefault("MACOSX_BUNDLE", CM_NULLPTR);
    this->SetPropertyDefault("MACOSX_RPATH", CM_NULLPTR);
    this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", CM_NULLPTR);
    this->SetPropertyDefault("C_CLANG_TIDY", CM_NULLPTR);
    this->SetPropertyDefault("C_COMPILER_LAUNCHER", CM_NULLPTR);
    this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", CM_NULLPTR);
    this->SetPropertyDefault("LINK_WHAT_YOU_USE", CM_NULLPTR);
    this->SetPropertyDefault("C_STANDARD", CM_NULLPTR);
    this->SetPropertyDefault("C_STANDARD_REQUIRED", CM_NULLPTR);
    this->SetPropertyDefault("C_EXTENSIONS", CM_NULLPTR);
    this->SetPropertyDefault("CXX_CLANG_TIDY", CM_NULLPTR);
    this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", CM_NULLPTR);
    this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", CM_NULLPTR);
    this->SetPropertyDefault("CXX_STANDARD", CM_NULLPTR);
    this->SetPropertyDefault("CXX_STANDARD_REQUIRED", CM_NULLPTR);
    this->SetPropertyDefault("CXX_EXTENSIONS", CM_NULLPTR);
    this->SetPropertyDefault("LINK_SEARCH_START_STATIC", CM_NULLPTR);
    this->SetPropertyDefault("LINK_SEARCH_END_STATIC", CM_NULLPTR);
278
  }
279 280 281

  // Collect the set of configuration types.
  std::vector<std::string> configNames;
282
  mf->GetConfigurations(configNames);
283 284

  // Setup per-configuration property default values.
285
  if (this->GetType() != cmState::UTILITY) {
286
    const char* configProps[] = {
287
      /* clang-format needs this comment to break after the opening brace */
288 289 290 291 292 293
      "ARCHIVE_OUTPUT_DIRECTORY_",
      "LIBRARY_OUTPUT_DIRECTORY_",
      "RUNTIME_OUTPUT_DIRECTORY_",
      "PDB_OUTPUT_DIRECTORY_",
      "COMPILE_PDB_OUTPUT_DIRECTORY_",
      "MAP_IMPORTED_CONFIG_",
Daniel Pfeifer's avatar
Daniel Pfeifer committed
294
      CM_NULLPTR
295 296 297
    };
    for (std::vector<std::string>::iterator ci = configNames.begin();
         ci != configNames.end(); ++ci) {
298
      std::string configUpper = cmSystemTools::UpperCase(*ci);
299 300 301
      for (const char** p = configProps; *p; ++p) {
        if (this->TargetTypeValue == cmState::INTERFACE_LIBRARY &&
            strcmp(*p, "MAP_IMPORTED_CONFIG_") != 0) {
302
          continue;
303
        }
304 305
        std::string property = *p;
        property += configUpper;
Daniel Pfeifer's avatar
Daniel Pfeifer committed
306
        this->SetPropertyDefault(property, CM_NULLPTR);
307
      }
308

309 310 311 312 313
      // Initialize per-configuration name postfix property from the
      // variable only for non-executable targets.  This preserves
      // compatibility with previous CMake versions in which executables
      // did not support this variable.  Projects may still specify the
      // property directly.
314 315
      if (this->TargetTypeValue != cmState::EXECUTABLE &&
          this->TargetTypeValue != cmState::INTERFACE_LIBRARY) {
316 317
        std::string property = cmSystemTools::UpperCase(*ci);
        property += "_POSTFIX";
Daniel Pfeifer's avatar
Daniel Pfeifer committed
318
        this->SetPropertyDefault(property, CM_NULLPTR);
319 320
      }
    }
321
  }
322 323

  // Save the backtrace of target construction.
324
  this->Backtrace = this->Makefile->GetBacktrace();
325

326
  if (!this->IsImported()) {
327 328
    // Initialize the INCLUDE_DIRECTORIES property based on the current value
    // of the same directory property:
329
    const cmStringRange parentIncludes =
330
      this->Makefile->GetIncludeDirectoriesEntries();
331
    const cmBacktraceRange parentIncludesBts =
332
      this->Makefile->GetIncludeDirectoriesBacktraces();
333

334
    this->Internal->IncludeDirectoriesEntries.insert(
335 336
      this->Internal->IncludeDirectoriesEntries.end(), parentIncludes.begin(),
      parentIncludes.end());
337
    this->Internal->IncludeDirectoriesBacktraces.insert(
338 339
      this->Internal->IncludeDirectoriesBacktraces.end(),
      parentIncludesBts.begin(), parentIncludesBts.end());
340

341
    const std::set<std::string> parentSystemIncludes =
342
      this->Makefile->GetSystemIncludeDirectories();
343

344 345
    this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
                                          parentSystemIncludes.end());
346

347
    const cmStringRange parentOptions =
348
      this->Makefile->GetCompileOptionsEntries();
349
    const cmBacktraceRange parentOptionsBts =
350
      this->Makefile->GetCompileOptionsBacktraces();
351

352
    this->Internal->CompileOptionsEntries.insert(
353 354
      this->Internal->CompileOptionsEntries.end(), parentOptions.begin(),
      parentOptions.end());
355
    this->Internal->CompileOptionsBacktraces.insert(
356 357 358
      this->Internal->CompileOptionsBacktraces.end(), parentOptionsBts.begin(),
      parentOptionsBts.end());
  }
359

360 361
  if (this->GetType() != cmState::INTERFACE_LIBRARY &&
      this->GetType() != cmState::UTILITY) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
362 363 364
    this->SetPropertyDefault("C_VISIBILITY_PRESET", CM_NULLPTR);
    this->SetPropertyDefault("CXX_VISIBILITY_PRESET", CM_NULLPTR);
    this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", CM_NULLPTR);
365
  }
366

367
  if (this->TargetTypeValue == cmState::EXECUTABLE) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
368 369 370
    this->SetPropertyDefault("ANDROID_GUI", CM_NULLPTR);
    this->SetPropertyDefault("CROSSCOMPILING_EMULATOR", CM_NULLPTR);
    this->SetPropertyDefault("ENABLE_EXPORTS", CM_NULLPTR);
371 372 373
  }
  if (this->TargetTypeValue == cmState::SHARED_LIBRARY ||
      this->TargetTypeValue == cmState::MODULE_LIBRARY) {
374
    this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
375
  }
376 377
  if (this->TargetTypeValue == cmState::SHARED_LIBRARY ||
      this->TargetTypeValue == cmState::EXECUTABLE) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
378
    this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", CM_NULLPTR);
379
  }
380

381 382
  if (this->GetType() != cmState::INTERFACE_LIBRARY &&
      this->GetType() != cmState::UTILITY) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
383
    this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", CM_NULLPTR);
384
  }
385

386
  // Record current policies for later use.
387
  this->Makefile->RecordPolicies(this->PolicyMap);
388

389
  if (this->TargetTypeValue == cmState::INTERFACE_LIBRARY) {
390
    // This policy is checked in a few conditions. The properties relevant
391
    // to the policy are always ignored for cmState::INTERFACE_LIBRARY targets,
392
    // so ensure that the conditions don't lead to nonsense.
393
    this->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
394
  }
395

396 397
  if (this->GetType() != cmState::INTERFACE_LIBRARY &&
      this->GetType() != cmState::UTILITY) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
398 399
    this->SetPropertyDefault("JOB_POOL_COMPILE", CM_NULLPTR);
    this->SetPropertyDefault("JOB_POOL_LINK", CM_NULLPTR);
400
  }
401 402
}

403 404 405 406 407
cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
{
  return this->GetMakefile()->GetGlobalGenerator();
}

408
void cmTarget::AddUtility(const std::string& u, cmMakefile* makefile)
409
{
410
  if (this->Utilities.insert(u).second && makefile) {
Stephen Kelly's avatar
Stephen Kelly committed
411
    this->UtilityBacktraces.insert(
412 413
      std::make_pair(u, makefile->GetBacktrace()));
  }
414 415
}

416
cmListFileBacktrace const* cmTarget::GetUtilityBacktrace(
417
  const std::string& u) const
418
{
419
  std::map<std::string, cmListFileBacktrace>::const_iterator i =
420
    this->UtilityBacktraces.find(u);
421
  if (i == this->UtilityBacktraces.end()) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
422
    return CM_NULLPTR;
423
  }
424 425 426 427

  return &i->second;
}

428 429
cmListFileBacktrace const& cmTarget::GetBacktrace() const
{
430
  return this->Backtrace;
431
}
432

433
bool cmTarget::IsExecutableWithExports() const
434
{
435
  return (this->GetType() == cmState::EXECUTABLE &&
436 437 438
          this->GetPropertyAsBool("ENABLE_EXPORTS"));
}

439
bool cmTarget::HasImportLibrary() const
Brad King's avatar
Brad King committed
440
{
441 442
  return (this->DLLPlatform && (this->GetType() == cmState::SHARED_LIBRARY ||
                                this->IsExecutableWithExports()));
Brad King's avatar
Brad King committed
443 444
}

445
bool cmTarget::IsFrameworkOnApple() const
446
{
447
  return (this->GetType() == cmState::SHARED_LIBRARY &&
448 449
          this->Makefile->IsOn("APPLE") &&
          this->GetPropertyAsBool("FRAMEWORK"));
450 451
}

452
bool cmTarget::IsAppBundleOnApple() const
453
{
454
  return (this->GetType() == cmState::EXECUTABLE &&
455 456 457 458
          this->Makefile->IsOn("APPLE") &&
          this->GetPropertyAsBool("MACOSX_BUNDLE"));
}

459 460
void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
461
  if (!srcs.empty()) {
Ben Boeckel's avatar
Ben Boeckel committed
462
    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
463
    this->Internal->SourceEntries.push_back(cmJoin(srcs, ";"));
464
    this->Internal->SourceBacktraces.push_back(lfbt);
465
  }
466 467
}

468 469
void cmTarget::AddSources(std::vector<std::string> const& srcs)
{
470 471
  std::string srcFiles;
  const char* sep = "";
472 473
  for (std::vector<std::string>::const_iterator i = srcs.begin();
       i != srcs.end(); ++i) {
474 475 476
    std::string filename = *i;
    const char* src = filename.c_str();

477 478
    if (!(src[0] == '$' && src[1] == '<')) {
      if (!filename.empty()) {
479
        filename = this->ProcessSourceItemCMP0049(filename);
480
        if (filename.empty()) {
481
          return;
482
        }
483
      }
484 485
      this->Makefile->GetOrCreateSource(filename);
    }
486 487 488
    srcFiles += sep;
    srcFiles += filename;
    sep = ";";
489 490
  }
  if (!srcFiles.empty()) {
Ben Boeckel's avatar
Ben Boeckel committed
491
    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
492 493
    this->Internal->SourceEntries.push_back(srcFiles);
    this->Internal->SourceBacktraces.push_back(lfbt);
494
  }
495
}
496

497
std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
498 499 500 501 502 503
{
  std::string src = s;

  // For backwards compatibility replace varibles in source names.
  // This should eventually be removed.
  this->Makefile->ExpandVariablesInString(src);
504
  if (src != s) {
505
    std::ostringstream e;
506 507
    bool noMessage = false;
    cmake::MessageType messageType = cmake::AUTHOR_WARNING;
508
    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0049)) {
509
      case cmPolicies::WARN:
Stephen Kelly's avatar
Stephen Kelly committed
510
        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0049) << "\n";
511 512 513 514 515 516 517 518
        break;
      case cmPolicies::OLD:
        noMessage = true;
        break;
      case cmPolicies::REQUIRED_ALWAYS:
      case cmPolicies::REQUIRED_IF_USED:
      case cmPolicies::NEW:
        messageType = cmake::FATAL_ERROR;
519 520 521 522 523 524
    }
    if (!noMessage) {
      e << "Legacy variable expansion in source file \"" << s
        << "\" expanded to \"" << src << "\" in target \"" << this->GetName()
        << "\".  This behavior will be removed in a "
           "future version of CMake.";
Stephen Kelly's avatar
Stephen Kelly committed
525
      this->Makefile->IssueMessage(messageType, e.str());
526
      if (messageType == cmake::FATAL_ERROR) {
527
        return "";
528 529
      }
    }
530
  }
531 532 533 534 535 536
  return src;
}

cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
{
  std::string src = this->ProcessSourceItemCMP0049(s);
537
  if (!s.empty() && src.empty()) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
538
    return CM_NULLPTR;
539
  }
540
  return this->AddSource(src);
541 542
}

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
struct CreateLocation
{
  cmMakefile const* Makefile;

  CreateLocation(cmMakefile const* mf)
    : Makefile(mf)
  {
  }

  cmSourceFileLocation operator()(const std::string& filename)
  {
    return cmSourceFileLocation(this->Makefile, filename);
  }
};

struct LocationMatcher
559
{
560 561 562 563 564 565 566
  const cmSourceFileLocation& Needle;

  LocationMatcher(const cmSourceFileLocation& needle)
    : Needle(needle)
  {
  }

567
  bool operator()(cmSourceFileLocation& loc)
568 569 570 571 572 573 574 575 576
  {
    return loc.Matches(this->Needle);
  }
};

struct TargetPropertyEntryFinder
{
private:
  const cmSourceFileLocation& Needle;
577

578 579 580 581 582 583
public:
  TargetPropertyEntryFinder(const cmSourceFileLocation& needle)
    : Needle(needle)
  {
  }

584
  bool operator()(std::string const& entry)
585 586
  {
    std::vector<std::string> files;
587
    cmSystemTools::ExpandListArgument(entry, files);
588 589 590 591 592
    std::vector<cmSourceFileLocation> locations(files.size());
    std::transform(files.begin(), files.end(), locations.begin(),
                   CreateLocation(this->Needle.GetMakefile()));

    return std::find_if(locations.begin(), locations.end(),
593
                        LocationMatcher(this->Needle)) != locations.end();
594 595 596
  }
};

597 598
cmSourceFile* cmTarget::AddSource(const std::string& src)
{
599 600 601
  cmSourceFileLocation sfl(this->Makefile, src);
  if (std::find_if(this->Internal->SourceEntries.begin(),
                   this->Internal->SourceEntries.end(),
602 603
                   TargetPropertyEntryFinder(sfl)) ==
      this->Internal->SourceEntries.end()) {
Ben Boeckel's avatar
Ben Boeckel committed
604
    cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
605 606
    this->Internal->SourceEntries.push_back(src);
    this->Internal->SourceBacktraces.push_back(lfbt);
607 608
  }
  if (cmGeneratorExpression::Find(src) != std::string::npos) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
609
    return CM_NULLPTR;
610
  }
611
  return this->Makefile->GetOrCreateSource(src);
612 613
}

614
void cmTarget::AddLinkDirectory(const std::string& d)
615 616
{
  // Make sure we don't add unnecessary search directories.
617
  if (this->LinkDirectoriesEmmitted.insert(d).second) {
618
    this->LinkDirectories.push_back(d);
619
  }
620 621
}

622
const std::vector<std::string>& cmTarget::GetLinkDirectories() const
623
{
Ken Martin's avatar
Ken Martin committed
624
  return this->LinkDirectories;
625
}
626

627 628
void cmTarget::ClearDependencyInformation(cmMakefile& mf,
                                          const std::string& target)
629 630 631 632 633
{
  // Clear the dependencies. The cache variable must exist iff we are
  // recording dependency information for this target.
  std::string depname = target;
  depname += "_LIB_DEPENDS";
634 635 636 637 638
  if (this->RecordDependencies) {
    mf.AddCacheDefinition(depname, "", "Dependencies for target",
                          cmState::STATIC);
  } else {
    if (mf.GetDefinition(depname)) {
639 640 641 642 643 644
      std::string message = "Target ";
      message += target;
      message += " has dependency information when it shouldn't.\n";
      message += "Your cache is probably stale. Please remove the entry\n  ";
      message += depname;
      message += "\nfrom the cache.";
645
      cmSystemTools::Error(message.c_str());
646
    }
647
  }
648 649
}

650 651
std::string cmTarget::GetDebugGeneratorExpressions(
  const std::string& value, cmTargetLinkLibraryType llt) const
652
{
653
  if (llt == GENERAL_LibraryType) {
654
    return value;
655
  }
656 657

  // Get the list of configurations considered to be DEBUG.
658
  std::vector<std::string> debugConfigs =
659
    this->Makefile->GetCMakeInstance()->GetDebugConfigs();
660 661 662

  std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";

663 664 665 666
  if (debugConfigs.size() > 1) {
    for (std::vector<std::string>::const_iterator li =
           debugConfigs.begin() + 1;
         li != debugConfigs.end(); ++li) {
667 668
      configString += ",$<CONFIG:" + *li + ">";
    }
669 670
    configString = "$<OR:" + configString + ">";
  }
671

672
  if (llt == OPTIMIZED_LibraryType) {
673
    configString = "$<NOT:" + configString + ">";
674
  }
675 676 677
  return "$<" + configString + ":" + value + ">";
}

678
static std::string targetNameGenex(const std::string& lib)
679
{
680
  return "$<TARGET_NAME:" + lib + ">";
681 682
}

683 684
bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
                                   cmListFileContext const& lfc)
685 686
{
  bool ret = true;
687 688
  if (!this->TLLCommands.empty()) {
    if (this->TLLCommands.back().first != signature) {
689 690
      ret = false;
    }
691 692
  }
  if (this->TLLCommands.empty() || this->TLLCommands.back().second != lfc) {
693
    this->TLLCommands.push_back(std::make_pair(signature, lfc));
694
  }
695 696 697
  return ret;
}

698
void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
699
{
700 701
  const char* sigString =
    (sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
702
  s << "The uses of the " << sigString << " signature are here:\n";
703
  typedef std::vector<std::pair<TLLSignature, cmListFileContext> > Container;
704
  cmOutputConverter converter(this->GetMakefile()->GetStateSnapshot());
705 706 707
  for (Container::const_iterator it = this->TLLCommands.begin();
       it != this->TLLCommands.end(); ++it) {
    if (it->first == sig) {
708
      cmListFileContext lfc = it->second;
709 710
      lfc.FilePath = converter.ConvertToRelativePath(
        this->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
711
      s << " * " << lfc << std::endl;
712
    }
713
  }
714 715
}

716
void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
717
                              cmTargetLinkLibraryType llt)
718
{
719
  cmTarget* tgt = this->Makefile->FindTargetToUse(lib);
720
  {
721
    const bool isNonImportedTarget = tgt && !tgt->IsImported();
722

723
    const std::string libName =
724 725 726
      (isNonImportedTarget && llt != GENERAL_LibraryType)
      ? targetNameGenex(lib)
      : lib;
727 728 729
    this->AppendProperty(
      "LINK_LIBRARIES",
      this->GetDebugGeneratorExpressions(libName, llt).c_str());
730 731
  }

732 733
  if (cmGeneratorExpression::Find(lib) != std::string::npos ||
      (tgt && tgt->GetType() == cmState::INTERFACE_LIBRARY) ||
734
      (this->Name == lib)) {
735
    return;
736
  }
737

738
  cmTarget::LibraryID tmp;
Ken Martin's avatar
Ken Martin committed
739 740
  tmp.first = lib;
  tmp.second = llt;
741
  this->OriginalLinkLibraries.push_back(tmp);
742

743 744 745 746
  // Add the explicit dependency information for this target. This is
  // simply a set of libraries separated by ";". There should always
  // be a trailing ";". These library names are not canonical, in that
  // they may be "-framework x", "-ly", "/path/libz.a", etc.
747 748 749 750
  // We shouldn't remove duplicates here because external libraries
  // may be purposefully duplicated to handle recursive dependencies,
  // and we removing one instance will break the link line. Duplicates
  // will be appropriately eliminated at emit time.
751
  if (this->RecordDependencies) {
752
    std::string targetEntry = this->Name;
753 754
    targetEntry += "_LIB_DEPENDS";
    std::string dependencies;
755 756
    const char* old_val = mf.GetDefinition(targetEntry);
    if (old_val) {
757
      dependencies += old_val;
758 759
    }
    switch (llt) {
760
      case GENERAL_LibraryType:
761 762
        dependencies += "general";
        break;
763
      case DEBUG_LibraryType:
764 765
        dependencies += "debug";
        break;
766
      case OPTIMIZED_LibraryType:
767 768
        dependencies += "optimized";
        break;
769
    }
770
    dependencies += ";";
771 772
    dependencies += lib;
    dependencies += ";";
773 774 775
    mf.AddCacheDefinition(targetEntry, dependencies.c_str(),
                          "Dependencies for the target", cmState::STATIC);
  }
776 777
}

778
void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
779
{
780
  this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
781 782
}

783 784 785 786 787 788 789 790 791 792
cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
{
  return cmMakeRange(this->Internal->IncludeDirectoriesEntries);
}

cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
{
  return cmMakeRange(this->Internal->IncludeDirectoriesBacktraces);
}

793 794 795 796 797 798 799 800 801 802
cmStringRange cmTarget::GetCompileOptionsEntries() const
{
  return cmMakeRange(this->Internal->CompileOptionsEntries);
}

cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
{
  return cmMakeRange(this->Internal->CompileOptionsBacktraces);
}

803 804 805 806 807 808 809 810 811 812
cmStringRange cmTarget::GetCompileFeaturesEntries() const
{
  return cmMakeRange(this->Internal->CompileFeaturesEntries);
}

cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
{
  return cmMakeRange(this->Internal->CompileFeaturesBacktraces);
}

813 814 815 816 817 818 819 820 821 822
cmStringRange cmTarget::GetCompileDefinitionsEntries() const
{
  return cmMakeRange(this->Internal->CompileDefinitionsEntries);
}

cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
{
  return cmMakeRange(this->Internal->CompileDefinitionsBacktraces);
}

823 824 825 826 827 828 829 830 831 832
cmStringRange cmTarget::GetSourceEntries() const
{
  return cmMakeRange(this->Internal->SourceEntries);
}

cmBacktraceRange cmTarget::GetSourceBacktraces() const
{
  return cmMakeRange(this->Internal->SourceBacktraces);
}

833 834 835 836 837 838 839 840 841 842
cmStringRange cmTarget::GetLinkImplementationEntries() const
{
  return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
}

cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
{
  return cmMakeRange(this->Internal->LinkImplementationPropertyBacktraces);
}

843
void cmTarget::SetProperty(const std::string& prop, const char* value)
Bill Hoffman's avatar
Bill Hoffman committed
844
{
845 846 847
  if (!cmTargetPropertyComputer::PassesWhitelist(
        this->GetType(), prop, this->Makefile->GetMessenger(),
        this->Makefile->GetBacktrace())) {
848
    return;
849 850
  }
  if (prop == "NAME") {
851
    std::ostringstream e;
Stephen Kelly's avatar
Stephen Kelly committed
852
    e << "NAME property is read-only\n";
Stephen Kelly's avatar
Stephen Kelly committed
853
    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
Stephen Kelly's avatar
Stephen Kelly committed
854
    return;
855 856
  }
  if (prop == "INCLUDE_DIRECTORIES") {
857 858
    this->Internal->IncludeDirectoriesEntries.clear();
    this->Internal->IncludeDirectoriesBacktraces.clear();
859
    if (value) {
860 861 862
      this->Internal->IncludeDirectoriesEntries.push_back(value);
      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
      this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);