Browse Source

Add generator APIs to get build settings with backtraces

In cmGeneratorTarget and cmLocalGenerator we offer several APIs to get
build settings like include directories, compile definitions, source
files, etc.  Add corresponding APIs that include backtrace information.
Brad King 7 years ago
parent
commit
753ab3c978
4 changed files with 329 additions and 112 deletions
  1. 197 70
      Source/cmGeneratorTarget.cxx
  2. 25 6
      Source/cmGeneratorTarget.h
  3. 91 34
      Source/cmLocalGenerator.cxx
  4. 16 2
      Source/cmLocalGenerator.h

+ 197 - 70
Source/cmGeneratorTarget.cxx

@@ -439,7 +439,7 @@ static void handleSystemIncludesDep(
     KindedSources const& kinded = this->GetKindedSources(config);             \
     for (SourceAndKind const& s : kinded.Sources) {                           \
       if (s.Kind == KIND) {                                                   \
-        data.push_back(s.Source);                                             \
+        data.push_back(s.Source.Value);                                       \
       }                                                                       \
     }                                                                         \
   }
@@ -865,7 +865,8 @@ static void AddObjectEntries(
 static bool processSources(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& srcs, std::unordered_set<std::string>& uniqueSrcs,
+  std::vector<BT<std::string>>& srcs,
+  std::unordered_set<std::string>& uniqueSrcs,
   cmGeneratorExpressionDAGChecker* dagChecker, std::string const& config,
   bool debugSources)
 {
@@ -916,7 +917,7 @@ static bool processSources(
     std::string usedSources;
     for (std::string const& src : entrySources) {
       if (uniqueSrcs.insert(src).second) {
-        srcs.push_back(src);
+        srcs.emplace_back(src, entry->ge->GetBacktrace());
         if (debugSources) {
           usedSources += " * " + src + "\n";
         }
@@ -933,9 +934,10 @@ static bool processSources(
   return contextDependent;
 }
 
-void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
-                                       const std::string& config) const
+std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
+  std::string const& config) const
 {
+  std::vector<BT<std::string>> files;
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
 
   if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) {
@@ -957,7 +959,7 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
         files.push_back(item);
       }
     }
-    return;
+    return files;
   }
 
   std::vector<std::string> debugProperties;
@@ -1009,11 +1011,23 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
 
   cmDeleteAll(linkInterfaceSourcesEntries);
   cmDeleteAll(linkObjectsEntries);
+  return files;
 }
 
 void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
                                        const std::string& config) const
 {
+  std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config);
+  files.reserve(tmp.size());
+  for (BT<cmSourceFile*>& v : tmp) {
+    files.push_back(v.Value);
+  }
+}
+
+std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles(
+  std::string const& config) const
+{
+  std::vector<BT<cmSourceFile*>> files;
   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
@@ -1021,16 +1035,15 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
     // 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::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
     std::set<cmSourceFile*> emitted;
-    for (std::string const& s : srcs) {
-      cmSourceFile* sf = this->Makefile->GetOrCreateSource(s);
+    for (BT<std::string> const& s : srcs) {
+      cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
       if (emitted.insert(sf).second) {
-        files.push_back(sf);
+        files.emplace_back(sf, s.Backtrace);
       }
     }
-    return;
+    return files;
   }
 
   KindedSources const& kinded = this->GetKindedSources(config);
@@ -1038,18 +1051,33 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
   for (SourceAndKind const& si : kinded.Sources) {
     files.push_back(si.Source);
   }
+  return files;
 }
 
 void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
   std::vector<cmSourceFile*>& files, const std::string& config) const
 {
+  std::vector<BT<cmSourceFile*>> tmp =
+    this->GetSourceFilesWithoutObjectLibraries(config);
+  files.reserve(tmp.size());
+  for (BT<cmSourceFile*>& v : tmp) {
+    files.push_back(v.Value);
+  }
+}
+
+std::vector<BT<cmSourceFile*>>
+cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
+  std::string const& config) const
+{
+  std::vector<BT<cmSourceFile*>> files;
   KindedSources const& kinded = this->GetKindedSources(config);
   files.reserve(kinded.Sources.size());
   for (SourceAndKind const& si : kinded.Sources) {
-    if (si.Source->GetObjectLibrary().empty()) {
+    if (si.Source.Value->GetObjectLibrary().empty()) {
       files.push_back(si.Source);
     }
   }
+  return files;
 }
 
 cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
@@ -1089,16 +1117,15 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
                                              std::string const& config) const
 {
   // Get the source file paths by string.
-  std::vector<std::string> srcs;
-  this->GetSourceFiles(srcs, config);
+  std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config);
 
   cmsys::RegularExpression header_regex(CM_HEADER_REGEX);
   std::vector<cmSourceFile*> badObjLib;
 
   std::set<cmSourceFile*> emitted;
-  for (std::string const& s : srcs) {
+  for (BT<std::string> const& s : srcs) {
     // Create each source at most once.
-    cmSourceFile* sf = this->Makefile->GetOrCreateSource(s);
+    cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value);
     if (!emitted.insert(sf).second) {
       continue;
     }
@@ -1161,7 +1188,7 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
     }
 
     // Save this classified source file in the result vector.
-    files.Sources.push_back({ sf, kind });
+    files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind });
   }
 
   if (!badObjLib.empty()) {
@@ -1197,14 +1224,14 @@ void cmGeneratorTarget::ComputeAllConfigSources() const
     KindedSources const& sources = this->GetKindedSources(configs[ci]);
     for (SourceAndKind const& src : sources.Sources) {
       std::map<cmSourceFile const*, size_t>::iterator mi =
-        index.find(src.Source);
+        index.find(src.Source.Value);
       if (mi == index.end()) {
         AllConfigSource acs;
-        acs.Source = src.Source;
+        acs.Source = src.Source.Value;
         acs.Kind = src.Kind;
         this->AllConfigSources.push_back(std::move(acs));
         std::map<cmSourceFile const*, size_t>::value_type entry(
-          src.Source, this->AllConfigSources.size() - 1);
+          src.Source.Value, this->AllConfigSources.size() - 1);
         mi = index.insert(entry).first;
       }
       this->AllConfigSources[mi->second].Configs.push_back(ci);
@@ -2474,7 +2501,7 @@ std::string cmGeneratorTarget::GetCreateRuleVariable(
 static void processIncludeDirectories(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& includes,
+  std::vector<BT<std::string>>& includes,
   std::unordered_set<std::string>& uniqueIncludes,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugIncludes, const std::string& language)
@@ -2566,7 +2593,7 @@ static void processIncludeDirectories(
       std::string inc = entryInclude;
 
       if (uniqueIncludes.insert(inc).second) {
-        includes.push_back(inc);
+        includes.emplace_back(inc, entry->ge->GetBacktrace());
         if (debugIncludes) {
           usedIncludes += " * " + inc + "\n";
         }
@@ -2582,10 +2609,10 @@ static void processIncludeDirectories(
   }
 }
 
-std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
+std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
   const std::string& config, const std::string& lang) const
 {
-  std::vector<std::string> includes;
+  std::vector<BT<std::string>> includes;
   std::unordered_set<std::string> uniqueIncludes;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
@@ -2655,7 +2682,7 @@ enum class OptionsParse
 static void processOptionsInternal(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions, const char* logName, std::string const& language,
@@ -2672,9 +2699,13 @@ static void processOptionsInternal(
       if (uniqueOptions.insert(opt).second) {
         if (parse == OptionsParse::Shell &&
             cmHasLiteralPrefix(opt, "SHELL:")) {
-          cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, options);
+          std::vector<std::string> tmp;
+          cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
+          for (std::string& o : tmp) {
+            options.emplace_back(std::move(o), entry->ge->GetBacktrace());
+          }
         } else {
-          options.push_back(opt);
+          options.emplace_back(opt, entry->ge->GetBacktrace());
         }
         if (debugOptions) {
           usedOptions += " * " + opt + "\n";
@@ -2694,7 +2725,7 @@ static void processOptionsInternal(
 static void processCompileOptions(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions, std::string const& language)
@@ -2708,6 +2739,17 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
                                           const std::string& config,
                                           const std::string& language) const
 {
+  std::vector<BT<std::string>> tmp = this->GetCompileOptions(config, language);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
+  std::string const& config, std::string const& language) const
+{
+  std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueOptions;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
@@ -2743,12 +2785,13 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
                         language);
 
   cmDeleteAll(linkInterfaceCompileOptionsEntries);
+  return result;
 }
 
 static void processCompileFeatures(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions)
@@ -2761,6 +2804,17 @@ static void processCompileFeatures(
 void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
                                            const std::string& config) const
 {
+  std::vector<BT<std::string>> tmp = this->GetCompileFeatures(config);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
+  std::string const& config) const
+{
+  std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueFeatures;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
@@ -2793,12 +2847,13 @@ void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
                          uniqueFeatures, &dagChecker, config, debugFeatures);
 
   cmDeleteAll(linkInterfaceCompileFeaturesEntries);
+  return result;
 }
 
 static void processCompileDefinitions(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions, std::string const& language)
@@ -2809,9 +2864,21 @@ static void processCompileDefinitions(
 }
 
 void cmGeneratorTarget::GetCompileDefinitions(
-  std::vector<std::string>& list, const std::string& config,
+  std::vector<std::string>& result, const std::string& config,
   const std::string& language) const
 {
+  std::vector<BT<std::string>> tmp =
+    this->GetCompileDefinitions(config, language);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
+  std::string const& config, std::string const& language) const
+{
+  std::vector<BT<std::string>> list;
   std::unordered_set<std::string> uniqueOptions;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
@@ -2872,13 +2939,14 @@ void cmGeneratorTarget::GetCompileDefinitions(
                             language);
 
   cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
+  return list;
 }
 
 namespace {
 void processLinkOptions(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions, std::string const& language)
@@ -2893,6 +2961,17 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
                                        const std::string& config,
                                        const std::string& language) const
 {
+  std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
+  std::string const& config, std::string const& language) const
+{
+  std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueOptions;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
@@ -2946,21 +3025,24 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
   const std::string SHELL{ "SHELL:" };
   const std::string LINKER_SHELL = LINKER + SHELL;
 
-  std::vector<std::string>::iterator entry;
+  std::vector<BT<std::string>>::iterator entry;
   while ((entry = std::find_if(result.begin(), result.end(),
-                               [&LINKER](const std::string& item) -> bool {
-                                 return item.compare(0, LINKER.length(),
-                                                     LINKER) == 0;
+                               [&LINKER](BT<std::string> const& item) -> bool {
+                                 return item.Value.compare(0, LINKER.length(),
+                                                           LINKER) == 0;
                                })) != result.end()) {
+    std::string value = std::move(entry->Value);
+    cmListFileBacktrace bt = std::move(entry->Backtrace);
+    entry = result.erase(entry);
+
     std::vector<std::string> linkerOptions;
-    if (entry->compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
+    if (value.compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
       cmSystemTools::ParseUnixCommandLine(
-        entry->c_str() + LINKER_SHELL.length(), linkerOptions);
+        value.c_str() + LINKER_SHELL.length(), linkerOptions);
     } else {
       linkerOptions =
-        cmSystemTools::tokenize(entry->substr(LINKER.length()), ",");
+        cmSystemTools::tokenize(value.substr(LINKER.length()), ",");
     }
-    entry = result.erase(entry);
 
     if (linkerOptions.empty() ||
         (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
@@ -2976,56 +3058,64 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
         cmake::FATAL_ERROR,
         "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
         this->GetBacktrace());
-      return;
+      return result;
     }
 
+    std::vector<BT<std::string>> options;
     if (wrapperFlag.empty()) {
       // nothing specified, insert elements as is
-      result.insert(entry, linkerOptions.begin(), linkerOptions.end());
+      options.reserve(linkerOptions.size());
+      for (std::string& o : linkerOptions) {
+        options.emplace_back(std::move(o), bt);
+      }
     } else {
-      std::vector<std::string> options;
-
       if (!wrapperSep.empty()) {
         if (concatFlagAndArgs) {
           // insert flag elements except last one
-          options.insert(options.end(), wrapperFlag.begin(),
-                         wrapperFlag.end() - 1);
+          for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
+            options.emplace_back(*i, bt);
+          }
           // concatenate last flag element and all LINKER list values
           // in one option
-          options.push_back(wrapperFlag.back() +
-                            cmJoin(linkerOptions, wrapperSep));
+          options.emplace_back(
+            wrapperFlag.back() + cmJoin(linkerOptions, wrapperSep), bt);
         } else {
-          options.insert(options.end(), wrapperFlag.begin(),
-                         wrapperFlag.end());
+          for (std::string const& i : wrapperFlag) {
+            options.emplace_back(i, bt);
+          }
           // concatenate all LINKER list values in one option
-          options.push_back(cmJoin(linkerOptions, wrapperSep));
+          options.emplace_back(cmJoin(linkerOptions, wrapperSep), bt);
         }
       } else {
         // prefix each element of LINKER list with wrapper
         if (concatFlagAndArgs) {
-          std::transform(
-            linkerOptions.begin(), linkerOptions.end(), linkerOptions.begin(),
-            [&wrapperFlag](const std::string& value) -> std::string {
-              return wrapperFlag.back() + value;
-            });
+          std::transform(linkerOptions.begin(), linkerOptions.end(),
+                         linkerOptions.begin(),
+                         [&wrapperFlag](std::string const& o) -> std::string {
+                           return wrapperFlag.back() + o;
+                         });
         }
-        for (const auto& value : linkerOptions) {
-          options.insert(options.end(), wrapperFlag.begin(),
-                         concatFlagAndArgs ? wrapperFlag.end() - 1
-                                           : wrapperFlag.end());
-          options.push_back(value);
+        for (std::string& o : linkerOptions) {
+          for (auto i = wrapperFlag.begin(),
+                    e = concatFlagAndArgs ? wrapperFlag.end() - 1
+                                          : wrapperFlag.end();
+               i != e; ++i) {
+            options.emplace_back(*i, bt);
+          }
+          options.emplace_back(std::move(o), bt);
         }
       }
-      result.insert(entry, options.begin(), options.end());
     }
+    result.insert(entry, options.begin(), options.end());
   }
+  return result;
 }
 
 namespace {
 void processStaticLibraryLinkOptions(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   std::string const& language)
@@ -3040,6 +3130,18 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions(
   std::vector<std::string>& result, const std::string& config,
   const std::string& language) const
 {
+  std::vector<BT<std::string>> tmp =
+    this->GetStaticLibraryLinkOptions(config, language);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
+  std::string const& config, std::string const& language) const
+{
+  std::vector<BT<std::string>> result;
   std::vector<cmGeneratorTarget::TargetPropertyEntry*> entries;
   std::unordered_set<std::string> uniqueOptions;
 
@@ -3060,13 +3162,14 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions(
                                   &dagChecker, config, language);
 
   cmDeleteAll(entries);
+  return result;
 }
 
 namespace {
 void processLinkDirectories(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& directories,
+  std::vector<BT<std::string>>& directories,
   std::unordered_set<std::string>& uniqueDirectories,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugDirectories, std::string const& language)
@@ -3145,6 +3248,18 @@ void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
                                            const std::string& config,
                                            const std::string& language) const
 {
+  std::vector<BT<std::string>> tmp =
+    this->GetLinkDirectories(config, language);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
+  std::string const& config, std::string const& language) const
+{
+  std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueDirectories;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
@@ -3180,13 +3295,14 @@ void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
                          debugDirectories, language);
 
   cmDeleteAll(linkInterfaceLinkDirectoriesEntries);
+  return result;
 }
 
 namespace {
 void processLinkDepends(
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
-  std::vector<std::string>& options,
+  std::vector<BT<std::string>>& options,
   std::unordered_set<std::string>& uniqueOptions,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   std::string const& language)
@@ -3201,6 +3317,17 @@ void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
                                        const std::string& config,
                                        const std::string& language) const
 {
+  std::vector<BT<std::string>> tmp = this->GetLinkDepends(config, language);
+  result.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    result.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
+  std::string const& config, std::string const& language) const
+{
+  std::vector<BT<std::string>> result;
   std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkDependsEntries;
   std::unordered_set<std::string> uniqueOptions;
   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr,
@@ -3222,6 +3349,7 @@ void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result,
                      &dagChecker, config, language);
 
   cmDeleteAll(linkDependsEntries);
+  return result;
 }
 
 void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
@@ -3287,10 +3415,9 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
 
 bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
 {
-  std::vector<std::string> features;
-  this->GetCompileFeatures(features, config);
-  for (std::string const& f : features) {
-    if (!this->Makefile->AddRequiredTargetFeature(this->Target, f)) {
+  std::vector<BT<std::string>> features = this->GetCompileFeatures(config);
+  for (BT<std::string> const& f : features) {
+    if (!this->Makefile->AddRequiredTargetFeature(this->Target, f.Value)) {
       return false;
     }
   }

+ 25 - 6
Source/cmGeneratorTarget.h

@@ -75,8 +75,8 @@ public:
   bool GetPropertyAsBool(const std::string& prop) const;
   void GetSourceFiles(std::vector<cmSourceFile*>& files,
                       const std::string& config) const;
-  void GetSourceFilesWithoutObjectLibraries(std::vector<cmSourceFile*>& files,
-                                            const std::string& config) const;
+  std::vector<BT<cmSourceFile*>> GetSourceFiles(
+    std::string const& config) const;
 
   /** Source file kinds (classifications).
       Generators use this to decide how to treat a source file.  */
@@ -99,7 +99,7 @@ public:
   /** A source file paired with a kind (classification).  */
   struct SourceAndKind
   {
-    cmSourceFile* Source;
+    BT<cmSourceFile*> Source;
     SourceKind Kind;
   };
 
@@ -412,34 +412,49 @@ public:
                                     std::string const& config) const;
 
   /** Get the include directories for this target.  */
-  std::vector<std::string> GetIncludeDirectories(
+  std::vector<BT<std::string>> GetIncludeDirectories(
     const std::string& config, const std::string& lang) const;
 
   void GetCompileOptions(std::vector<std::string>& result,
                          const std::string& config,
                          const std::string& language) const;
+  std::vector<BT<std::string>> GetCompileOptions(
+    std::string const& config, std::string const& language) const;
 
   void GetCompileFeatures(std::vector<std::string>& features,
                           const std::string& config) const;
+  std::vector<BT<std::string>> GetCompileFeatures(
+    std::string const& config) const;
 
   void GetCompileDefinitions(std::vector<std::string>& result,
                              const std::string& config,
                              const std::string& language) const;
+  std::vector<BT<std::string>> GetCompileDefinitions(
+    std::string const& config, std::string const& language) const;
 
   void GetLinkOptions(std::vector<std::string>& result,
                       const std::string& config,
                       const std::string& language) const;
+  std::vector<BT<std::string>> GetLinkOptions(
+    std::string const& config, std::string const& language) const;
+
   void GetStaticLibraryLinkOptions(std::vector<std::string>& result,
                                    const std::string& config,
                                    const std::string& language) const;
+  std::vector<BT<std::string>> GetStaticLibraryLinkOptions(
+    std::string const& config, std::string const& language) const;
 
   void GetLinkDirectories(std::vector<std::string>& result,
                           const std::string& config,
                           const std::string& language) const;
+  std::vector<BT<std::string>> GetLinkDirectories(
+    std::string const& config, std::string const& language) const;
 
   void GetLinkDepends(std::vector<std::string>& result,
                       const std::string& config,
                       const std::string& language) const;
+  std::vector<BT<std::string>> GetLinkDepends(
+    std::string const& config, std::string const& language) const;
 
   bool IsSystemIncludeDirectory(const std::string& dir,
                                 const std::string& config,
@@ -841,8 +856,12 @@ private:
                        cmListFileBacktrace const& bt,
                        std::vector<cmLinkItem>& items) const;
 
-  void GetSourceFiles(std::vector<std::string>& files,
-                      const std::string& config) const;
+  std::vector<BT<std::string>> GetSourceFilePaths(
+    std::string const& config) const;
+  std::vector<BT<cmSourceFile*>> GetSourceFilesWithoutObjectLibraries(
+    std::string const& config) const;
+  void GetSourceFilesWithoutObjectLibraries(std::vector<cmSourceFile*>& files,
+                                            const std::string& config) const;
 
   struct HeadToLinkImplementationMap
     : public std::map<cmGeneratorTarget const*, cmOptionalLinkImplementation>

+ 91 - 34
Source/cmLocalGenerator.cxx

@@ -219,6 +219,24 @@ static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs,
     });
 }
 
+static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs,
+                                    const std::string& config,
+                                    const std::string& lang,
+                                    const cmGeneratorTarget* target)
+{
+  if (!target) {
+    return;
+  }
+
+  std::stable_sort(includeDirs.begin(), includeDirs.end(),
+                   [target, &config, &lang](BT<std::string> const& a,
+                                            BT<std::string> const& b) {
+                     return !target->IsSystemIncludeDirectory(a.Value, config,
+                                                              lang) &&
+                       target->IsSystemIncludeDirectory(b.Value, config, lang);
+                   });
+}
+
 void cmLocalGenerator::TraceDependencies()
 {
   std::vector<std::string> configs;
@@ -869,6 +887,21 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
                                              bool stripImplicitDirs,
                                              bool appendAllImplicitDirs) const
 {
+  std::vector<BT<std::string>> tmp = this->GetIncludeDirectories(
+    target, lang, config, stripImplicitDirs, appendAllImplicitDirs);
+  dirs.reserve(tmp.size());
+  for (BT<std::string>& v : tmp) {
+    dirs.emplace_back(std::move(v.Value));
+  }
+}
+
+std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectories(
+  cmGeneratorTarget const* target, std::string const& lang,
+  std::string const& config, bool stripImplicitDirs,
+  bool appendAllImplicitDirs) const
+{
+  std::vector<BT<std::string>> result;
+
   // Do not repeat an include path.
   std::set<std::string> emitted;
 
@@ -885,7 +918,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
       std::string binDir =
         this->StateSnapshot.GetDirectory().GetCurrentBinary();
       if (emitted.insert(binDir).second) {
-        dirs.push_back(std::move(binDir));
+        result.emplace_back(std::move(binDir));
       }
     }
     // Current source directory
@@ -893,13 +926,13 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
       std::string srcDir =
         this->StateSnapshot.GetDirectory().GetCurrentSource();
       if (emitted.insert(srcDir).second) {
-        dirs.push_back(std::move(srcDir));
+        result.emplace_back(std::move(srcDir));
       }
     }
   }
 
   if (!target) {
-    return;
+    return result;
   }
 
   // Implicit include directories
@@ -932,7 +965,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
   }
 
   // Get the target-specific include directories.
-  std::vector<std::string> userDirs =
+  std::vector<BT<std::string>> userDirs =
     target->GetIncludeDirectories(config, lang);
 
   // Support putting all the in-project include directories first if
@@ -940,44 +973,44 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
   if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) {
     std::string const &topSourceDir = this->GetState()->GetSourceDirectory(),
                       &topBinaryDir = this->GetState()->GetBinaryDirectory();
-    for (std::string const& i : userDirs) {
+    for (BT<std::string> const& i : userDirs) {
       // Emit this directory only if it is a subdirectory of the
       // top-level source or binary tree.
-      if (cmSystemTools::ComparePath(i, topSourceDir) ||
-          cmSystemTools::ComparePath(i, topBinaryDir) ||
-          cmSystemTools::IsSubDirectory(i, topSourceDir) ||
-          cmSystemTools::IsSubDirectory(i, topBinaryDir)) {
-        if (emitted.insert(i).second) {
-          dirs.push_back(i);
+      if (cmSystemTools::ComparePath(i.Value, topSourceDir) ||
+          cmSystemTools::ComparePath(i.Value, topBinaryDir) ||
+          cmSystemTools::IsSubDirectory(i.Value, topSourceDir) ||
+          cmSystemTools::IsSubDirectory(i.Value, topBinaryDir)) {
+        if (emitted.insert(i.Value).second) {
+          result.push_back(i);
         }
       }
     }
   }
 
   // Construct the final ordered include directory list.
-  for (std::string const& i : userDirs) {
-    if (emitted.insert(i).second) {
-      dirs.push_back(i);
+  for (BT<std::string> const& i : userDirs) {
+    if (emitted.insert(i.Value).second) {
+      result.push_back(i);
     }
   }
 
-  MoveSystemIncludesToEnd(dirs, config, lang, target);
+  MoveSystemIncludesToEnd(result, config, lang, target);
 
   // Add standard include directories for this language.
   {
-    std::vector<std::string>::size_type const before = userDirs.size();
+    std::vector<std::string> userStandardDirs;
     {
       std::string key = "CMAKE_";
       key += lang;
       key += "_STANDARD_INCLUDE_DIRECTORIES";
       std::string const value = this->Makefile->GetSafeDefinition(key);
-      cmSystemTools::ExpandListArgument(value, userDirs);
+      cmSystemTools::ExpandListArgument(value, userStandardDirs);
     }
-    for (std::vector<std::string>::iterator i = userDirs.begin() + before,
-                                            ie = userDirs.end();
-         i != ie; ++i) {
-      cmSystemTools::ConvertToUnixSlashes(*i);
-      dirs.push_back(*i);
+    userDirs.reserve(userDirs.size() + userStandardDirs.size());
+    for (std::string& d : userStandardDirs) {
+      cmSystemTools::ConvertToUnixSlashes(d);
+      result.emplace_back(d);
+      userDirs.emplace_back(std::move(d));
     }
   }
 
@@ -985,18 +1018,20 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
     // Append only implicit directories that were requested by the user
     for (std::string const& i : implicitDirs) {
       if (std::find(userDirs.begin(), userDirs.end(), i) != userDirs.end()) {
-        dirs.push_back(i);
+        result.emplace_back(i);
       }
     }
     // Append remaining implicit directories on demand
     if (appendAllImplicitDirs) {
       for (std::string const& i : implicitDirs) {
-        if (std::find(dirs.begin(), dirs.end(), i) == dirs.end()) {
-          dirs.push_back(i);
+        if (std::find(result.begin(), result.end(), i) == result.end()) {
+          result.emplace_back(i);
         }
       }
     }
   }
+
+  return result;
 }
 
 void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
@@ -1253,15 +1288,29 @@ void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target,
                                         std::string const& lang,
                                         std::set<std::string>& defines) const
 {
+  std::set<BT<std::string>> tmp = this->GetTargetDefines(target, config, lang);
+  for (BT<std::string> const& v : tmp) {
+    defines.emplace(v.Value);
+  }
+}
+
+std::set<BT<std::string>> cmLocalGenerator::GetTargetDefines(
+  cmGeneratorTarget const* target, std::string const& config,
+  std::string const& lang) const
+{
+  std::set<BT<std::string>> defines;
+
   // Add the export symbol definition for shared library objects.
   if (const std::string* exportMacro = target->GetExportMacro()) {
     this->AppendDefines(defines, *exportMacro);
   }
 
   // Add preprocessor definitions for this target and configuration.
-  std::vector<std::string> targetDefines;
-  target->GetCompileDefinitions(targetDefines, config, lang);
+  std::vector<BT<std::string>> targetDefines =
+    target->GetCompileDefinitions(config, lang);
   this->AppendDefines(defines, targetDefines);
+
+  return defines;
 }
 
 std::string cmLocalGenerator::GetTargetFortranFlags(
@@ -2060,6 +2109,16 @@ void cmLocalGenerator::AppendIncludeDirectories(
 
 void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
                                      const char* defines_list) const
+{
+  std::set<BT<std::string>> tmp;
+  this->AppendDefines(tmp, ExpandListWithBacktrace(defines_list));
+  for (BT<std::string> const& i : tmp) {
+    defines.emplace(i.Value);
+  }
+}
+
+void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines,
+                                     const char* defines_list) const
 {
   // Short-circuit if there are no definitions.
   if (!defines_list) {
@@ -2067,18 +2126,16 @@ void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
   }
 
   // Expand the list of definitions.
-  std::vector<std::string> defines_vec;
-  cmSystemTools::ExpandListArgument(defines_list, defines_vec);
-  this->AppendDefines(defines, defines_vec);
+  this->AppendDefines(defines, ExpandListWithBacktrace(defines_list));
 }
 
 void cmLocalGenerator::AppendDefines(
-  std::set<std::string>& defines,
-  const std::vector<std::string>& defines_vec) const
+  std::set<BT<std::string>>& defines,
+  const std::vector<BT<std::string>>& defines_vec) const
 {
-  for (std::string const& d : defines_vec) {
+  for (BT<std::string> const& d : defines_vec) {
     // Skip unsupported definitions.
-    if (!this->CheckDefinition(d)) {
+    if (!this->CheckDefinition(d.Value)) {
       continue;
     }
     defines.insert(d);

+ 16 - 2
Source/cmLocalGenerator.h

@@ -175,8 +175,15 @@ public:
   {
     this->AppendDefines(defines, defines_list.c_str());
   }
-  void AppendDefines(std::set<std::string>& defines,
-                     const std::vector<std::string>& defines_vec) const;
+  void AppendDefines(std::set<BT<std::string>>& defines,
+                     const char* defines_list) const;
+  void AppendDefines(std::set<BT<std::string>>& defines,
+                     std::string const& defines_list) const
+  {
+    this->AppendDefines(defines, defines_list.c_str());
+  }
+  void AppendDefines(std::set<BT<std::string>>& defines,
+                     const std::vector<BT<std::string>>& defines_vec) const;
 
   /**
    * Encode a list of compile options for the compiler
@@ -249,6 +256,10 @@ public:
                              const std::string& config = "",
                              bool stripImplicitDirs = true,
                              bool appendAllImplicitDirs = false) const;
+  std::vector<BT<std::string>> GetIncludeDirectories(
+    cmGeneratorTarget const* target, std::string const& lang = "C",
+    std::string const& config = "", bool stripImplicitDirs = true,
+    bool appendAllImplicitDirs = false) const;
   void AddCompileOptions(std::string& flags, cmGeneratorTarget* target,
                          const std::string& lang, const std::string& config);
 
@@ -332,6 +343,9 @@ public:
   void GetTargetDefines(cmGeneratorTarget const* target,
                         std::string const& config, std::string const& lang,
                         std::set<std::string>& defines) const;
+  std::set<BT<std::string>> GetTargetDefines(cmGeneratorTarget const* target,
+                                             std::string const& config,
+                                             std::string const& lang) const;
   void GetTargetCompileFlags(cmGeneratorTarget* target,
                              std::string const& config,
                              std::string const& lang, std::string& flags);