resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmFileAPICodemodel.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmFileAPICodemodel.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstddef>
8 #include <functional>
9 #include <limits>
10 #include <map>
11 #include <memory>
12 #include <set>
13 #include <string>
14 #include <unordered_map>
15 #include <utility>
16 #include <vector>
17
18 #include <cm/string_view>
19 #include <cmext/algorithm>
20
21 #include <cm3p/json/value.h>
22
23 #include "cmCryptoHash.h"
24 #include "cmExportSet.h"
25 #include "cmFileAPI.h"
26 #include "cmFileSet.h"
27 #include "cmGeneratorExpression.h"
28 #include "cmGeneratorTarget.h"
29 #include "cmGlobalGenerator.h"
30 #include "cmInstallCxxModuleBmiGenerator.h"
31 #include "cmInstallDirectoryGenerator.h"
32 #include "cmInstallExportGenerator.h"
33 #include "cmInstallFileSetGenerator.h"
34 #include "cmInstallFilesGenerator.h"
35 #include "cmInstallGenerator.h"
36 #include "cmInstallGetRuntimeDependenciesGenerator.h"
37 #include "cmInstallImportedRuntimeArtifactsGenerator.h"
38 #include "cmInstallRuntimeDependencySet.h"
39 #include "cmInstallRuntimeDependencySetGenerator.h"
40 #include "cmInstallScriptGenerator.h"
41 #include "cmInstallSubdirectoryGenerator.h"
42 #include "cmInstallTargetGenerator.h"
43 #include "cmLinkLineComputer.h" // IWYU pragma: keep
44 #include "cmListFileCache.h"
45 #include "cmLocalGenerator.h"
46 #include "cmMakefile.h"
47 #include "cmSourceFile.h"
48 #include "cmSourceGroup.h"
49 #include "cmState.h"
50 #include "cmStateDirectory.h"
51 #include "cmStateSnapshot.h"
52 #include "cmStateTypes.h"
53 #include "cmStringAlgorithms.h"
54 #include "cmSystemTools.h"
55 #include "cmTarget.h"
56 #include "cmTargetDepend.h"
57 #include "cmTargetExport.h"
58 #include "cmValue.h"
59 #include "cmake.h"
60
61 namespace {
62
63 using TargetIndexMapType =
64   std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
65
66 std::string RelativeIfUnder(std::string const& top, std::string const& in)
67 {
68   return cmSystemTools::RelativeIfUnder(top, in);
69 }
70
71 class JBTIndex
72 {
73 public:
74   JBTIndex() = default;
75   explicit operator bool() const { return this->Index != None; }
76   Json::ArrayIndex Index = None;
77   static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1);
78 };
79
80 template <typename T>
81 class JBT
82 {
83 public:
84   JBT(T v = T(), JBTIndex bt = JBTIndex())
85     : Value(std::move(v))
86     , Backtrace(bt)
87   {
88   }
89   T Value;
90   JBTIndex Backtrace;
91   friend bool operator==(JBT<T> const& l, JBT<T> const& r)
92   {
93     return l.Value == r.Value && l.Backtrace.Index == r.Backtrace.Index;
94   }
95   static bool ValueEq(JBT<T> const& l, JBT<T> const& r)
96   {
97     return l.Value == r.Value;
98   }
99   static bool ValueLess(JBT<T> const& l, JBT<T> const& r)
100   {
101     return l.Value < r.Value;
102   }
103 };
104
105 template <typename T>
106 class JBTs
107 {
108 public:
109   JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>())
110     : Value(std::move(v))
111     , Backtraces(std::move(ids))
112   {
113   }
114   T Value;
115   std::vector<JBTIndex> Backtraces;
116   friend bool operator==(JBTs<T> const& l, JBTs<T> const& r)
117   {
118     if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) {
119       for (size_t i = 0; i < l.Backtraces.size(); i++) {
120         if (l.Backtraces[i].Index != r.Backtraces[i].Index) {
121           return false;
122         }
123       }
124     }
125     return true;
126   }
127   static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r)
128   {
129     return l.Value == r.Value;
130   }
131   static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r)
132   {
133     return l.Value < r.Value;
134   }
135 };
136
137 class BacktraceData
138 {
139   std::string TopSource;
140   std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
141   std::unordered_map<std::string, Json::ArrayIndex> FileMap;
142   std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
143   Json::Value Commands = Json::arrayValue;
144   Json::Value Files = Json::arrayValue;
145   Json::Value Nodes = Json::arrayValue;
146
147   Json::ArrayIndex AddCommand(std::string const& command)
148   {
149     auto i = this->CommandMap.find(command);
150     if (i == this->CommandMap.end()) {
151       auto cmdIndex = static_cast<Json::ArrayIndex>(this->Commands.size());
152       i = this->CommandMap.emplace(command, cmdIndex).first;
153       this->Commands.append(command);
154     }
155     return i->second;
156   }
157
158   Json::ArrayIndex AddFile(std::string const& file)
159   {
160     auto i = this->FileMap.find(file);
161     if (i == this->FileMap.end()) {
162       auto fileIndex = static_cast<Json::ArrayIndex>(this->Files.size());
163       i = this->FileMap.emplace(file, fileIndex).first;
164       this->Files.append(RelativeIfUnder(this->TopSource, file));
165     }
166     return i->second;
167   }
168
169 public:
170   BacktraceData(std::string topSource);
171   JBTIndex Add(cmListFileBacktrace const& bt);
172   Json::Value Dump();
173 };
174
175 BacktraceData::BacktraceData(std::string topSource)
176   : TopSource(std::move(topSource))
177 {
178 }
179
180 JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt)
181 {
182   JBTIndex index;
183   if (bt.Empty()) {
184     return index;
185   }
186   cmListFileContext const* top = &bt.Top();
187   auto found = this->NodeMap.find(top);
188   if (found != this->NodeMap.end()) {
189     index.Index = found->second;
190     return index;
191   }
192   Json::Value entry = Json::objectValue;
193   entry["file"] = this->AddFile(top->FilePath);
194   if (top->Line) {
195     entry["line"] = static_cast<int>(top->Line);
196   }
197   if (!top->Name.empty()) {
198     entry["command"] = this->AddCommand(top->Name);
199   }
200   if (JBTIndex parent = this->Add(bt.Pop())) {
201     entry["parent"] = parent.Index;
202   }
203   index.Index = this->NodeMap[top] = this->Nodes.size();
204   this->Nodes.append(std::move(entry)); // NOLINT(*)
205   return index;
206 }
207
208 Json::Value BacktraceData::Dump()
209 {
210   Json::Value backtraceGraph;
211   this->CommandMap.clear();
212   this->FileMap.clear();
213   this->NodeMap.clear();
214   backtraceGraph["commands"] = std::move(this->Commands);
215   backtraceGraph["files"] = std::move(this->Files);
216   backtraceGraph["nodes"] = std::move(this->Nodes);
217   return backtraceGraph;
218 }
219
220 class Codemodel
221 {
222   cmFileAPI& FileAPI;
223   unsigned long Version;
224
225   Json::Value DumpPaths();
226   Json::Value DumpConfigurations();
227   Json::Value DumpConfiguration(std::string const& config);
228
229 public:
230   Codemodel(cmFileAPI& fileAPI, unsigned long version);
231   Json::Value Dump();
232 };
233
234 class CodemodelConfig
235 {
236   cmFileAPI& FileAPI;
237   unsigned long Version;
238   std::string const& Config;
239   std::string TopSource;
240   std::string TopBuild;
241
242   struct Directory
243   {
244     cmStateSnapshot Snapshot;
245     cmLocalGenerator const* LocalGenerator = nullptr;
246     Json::Value TargetIndexes = Json::arrayValue;
247     Json::ArrayIndex ProjectIndex;
248     bool HasInstallRule = false;
249   };
250   std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
251     DirectoryMap;
252   std::vector<Directory> Directories;
253
254   struct Project
255   {
256     cmStateSnapshot Snapshot;
257     static const Json::ArrayIndex NoParentIndex =
258       static_cast<Json::ArrayIndex>(-1);
259     Json::ArrayIndex ParentIndex = NoParentIndex;
260     Json::Value ChildIndexes = Json::arrayValue;
261     Json::Value DirectoryIndexes = Json::arrayValue;
262     Json::Value TargetIndexes = Json::arrayValue;
263   };
264   std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
265     ProjectMap;
266   std::vector<Project> Projects;
267
268   TargetIndexMapType TargetIndexMap;
269
270   void ProcessDirectories();
271
272   Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
273   Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
274
275   Json::ArrayIndex AddProject(cmStateSnapshot s);
276
277   Json::Value DumpTargets();
278   Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
279
280   Json::Value DumpDirectories();
281   Json::Value DumpDirectory(Directory& d);
282   Json::Value DumpDirectoryObject(Directory& d);
283
284   Json::Value DumpProjects();
285   Json::Value DumpProject(Project& p);
286
287   Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
288
289 public:
290   CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
291                   std::string const& config);
292   Json::Value Dump();
293 };
294
295 std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
296 {
297   cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
298   std::string path = RelativeIfUnder(
299     topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
300   std::string hash = hasher.HashString(path);
301   hash.resize(20, '0');
302   return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
303 }
304
305 struct CompileData
306 {
307   struct IncludeEntry
308   {
309     JBT<std::string> Path;
310     bool IsSystem = false;
311     IncludeEntry(JBT<std::string> path, bool isSystem)
312       : Path(std::move(path))
313       , IsSystem(isSystem)
314     {
315     }
316     friend bool operator==(IncludeEntry const& l, IncludeEntry const& r)
317     {
318       return l.Path == r.Path && l.IsSystem == r.IsSystem;
319     }
320   };
321
322   std::string Language;
323   std::string Sysroot;
324   JBTs<std::string> LanguageStandard;
325   std::vector<JBT<std::string>> Flags;
326   std::vector<JBT<std::string>> Defines;
327   std::vector<JBT<std::string>> PrecompileHeaders;
328   std::vector<IncludeEntry> Includes;
329
330   friend bool operator==(CompileData const& l, CompileData const& r)
331   {
332     return (l.Language == r.Language && l.Sysroot == r.Sysroot &&
333             l.Flags == r.Flags && l.Defines == r.Defines &&
334             l.PrecompileHeaders == r.PrecompileHeaders &&
335             l.LanguageStandard == r.LanguageStandard &&
336             l.Includes == r.Includes);
337   }
338 };
339 }
340
341 namespace std {
342
343 template <>
344 struct hash<CompileData>
345 {
346   std::size_t operator()(CompileData const& in) const
347   {
348     using std::hash;
349     size_t result =
350       hash<std::string>()(in.Language) ^ hash<std::string>()(in.Sysroot);
351     for (auto const& i : in.Includes) {
352       result = result ^
353         (hash<std::string>()(i.Path.Value) ^
354          hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
355          (i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
356     }
357     for (auto const& i : in.Flags) {
358       result = result ^ hash<std::string>()(i.Value) ^
359         hash<Json::ArrayIndex>()(i.Backtrace.Index);
360     }
361     for (auto const& i : in.Defines) {
362       result = result ^ hash<std::string>()(i.Value) ^
363         hash<Json::ArrayIndex>()(i.Backtrace.Index);
364     }
365     for (auto const& i : in.PrecompileHeaders) {
366       result = result ^ hash<std::string>()(i.Value) ^
367         hash<Json::ArrayIndex>()(i.Backtrace.Index);
368     }
369     if (!in.LanguageStandard.Value.empty()) {
370       result = result ^ hash<std::string>()(in.LanguageStandard.Value);
371       for (JBTIndex backtrace : in.LanguageStandard.Backtraces) {
372         result = result ^ hash<Json::ArrayIndex>()(backtrace.Index);
373       }
374     }
375     return result;
376   }
377 };
378
379 } // namespace std
380
381 namespace {
382 class DirectoryObject
383 {
384   cmLocalGenerator const* LG = nullptr;
385   std::string const& Config;
386   TargetIndexMapType& TargetIndexMap;
387   std::string TopSource;
388   std::string TopBuild;
389   BacktraceData Backtraces;
390
391   void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
392
393   Json::Value DumpPaths();
394   Json::Value DumpInstallers();
395   Json::Value DumpInstaller(cmInstallGenerator* gen);
396   Json::Value DumpInstallerExportTargets(cmExportSet* exp);
397   Json::Value DumpInstallerPath(std::string const& top,
398                                 std::string const& fromPathIn,
399                                 std::string const& toPath);
400
401 public:
402   DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
403                   TargetIndexMapType& targetIndexMap);
404   Json::Value Dump();
405 };
406
407 class Target
408 {
409   cmGeneratorTarget* GT;
410   std::string const& Config;
411   std::string TopSource;
412   std::string TopBuild;
413   std::vector<cmSourceGroup> SourceGroupsLocal;
414   BacktraceData Backtraces;
415
416   std::map<std::string, CompileData> CompileDataMap;
417
418   std::unordered_map<cmSourceFile const*, Json::ArrayIndex> SourceMap;
419   Json::Value Sources = Json::arrayValue;
420
421   struct SourceGroup
422   {
423     std::string Name;
424     Json::Value SourceIndexes = Json::arrayValue;
425   };
426   std::unordered_map<cmSourceGroup const*, Json::ArrayIndex> SourceGroupsMap;
427   std::vector<SourceGroup> SourceGroups;
428
429   struct CompileGroup
430   {
431     std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry;
432     Json::Value SourceIndexes = Json::arrayValue;
433   };
434   std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
435   std::vector<CompileGroup> CompileGroups;
436
437   template <typename T>
438   JBT<T> ToJBT(BT<T> const& bt)
439   {
440     return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
441   }
442
443   template <typename T>
444   JBTs<T> ToJBTs(BTs<T> const& bts)
445   {
446     std::vector<JBTIndex> ids;
447     for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
448       ids.emplace_back(this->Backtraces.Add(backtrace));
449     }
450     return JBTs<T>(bts.Value, ids);
451   }
452
453   void ProcessLanguages();
454   void ProcessLanguage(std::string const& lang);
455
456   Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si);
457   CompileData BuildCompileData(cmSourceFile* sf);
458   CompileData MergeCompileData(CompileData const& fd);
459   Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf,
460                                          Json::ArrayIndex si);
461   void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
462   void AddBacktrace(Json::Value& object, JBTIndex bt);
463   Json::Value DumpPaths();
464   Json::Value DumpCompileData(CompileData const& cd);
465   Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
466   Json::Value DumpPrecompileHeader(JBT<std::string> const& header);
467   Json::Value DumpLanguageStandard(JBTs<std::string> const& standard);
468   Json::Value DumpDefine(JBT<std::string> const& def);
469   Json::Value DumpSources();
470   Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
471                          Json::ArrayIndex si);
472   Json::Value DumpSourceGroups();
473   Json::Value DumpSourceGroup(SourceGroup& sg);
474   Json::Value DumpCompileGroups();
475   Json::Value DumpCompileGroup(CompileGroup& cg);
476   Json::Value DumpSysroot(std::string const& path);
477   Json::Value DumpInstall();
478   Json::Value DumpInstallPrefix();
479   Json::Value DumpInstallDestinations();
480   Json::Value DumpInstallDestination(cmInstallTargetGenerator* itGen);
481   Json::Value DumpArtifacts();
482   Json::Value DumpLink();
483   Json::Value DumpArchive();
484   Json::Value DumpLinkCommandFragments();
485   Json::Value DumpCommandFragments(std::vector<JBT<std::string>> const& frags);
486   Json::Value DumpCommandFragment(JBT<std::string> const& frag,
487                                   std::string const& role = std::string());
488   Json::Value DumpDependencies();
489   Json::Value DumpDependency(cmTargetDepend const& td);
490   Json::Value DumpFolder();
491
492 public:
493   Target(cmGeneratorTarget* gt, std::string const& config);
494   Json::Value Dump();
495 };
496
497 Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned long version)
498   : FileAPI(fileAPI)
499   , Version(version)
500 {
501 }
502
503 Json::Value Codemodel::Dump()
504 {
505   Json::Value codemodel = Json::objectValue;
506
507   codemodel["paths"] = this->DumpPaths();
508   codemodel["configurations"] = this->DumpConfigurations();
509
510   return codemodel;
511 }
512
513 Json::Value Codemodel::DumpPaths()
514 {
515   Json::Value paths = Json::objectValue;
516   paths["source"] = this->FileAPI.GetCMakeInstance()->GetHomeDirectory();
517   paths["build"] = this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory();
518   return paths;
519 }
520
521 Json::Value Codemodel::DumpConfigurations()
522 {
523   Json::Value configurations = Json::arrayValue;
524   cmGlobalGenerator* gg =
525     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
526   const auto& makefiles = gg->GetMakefiles();
527   if (!makefiles.empty()) {
528     std::vector<std::string> const& configs =
529       makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
530     for (std::string const& config : configs) {
531       configurations.append(this->DumpConfiguration(config));
532     }
533   }
534   return configurations;
535 }
536
537 Json::Value Codemodel::DumpConfiguration(std::string const& config)
538 {
539   CodemodelConfig configuration(this->FileAPI, this->Version, config);
540   return configuration.Dump();
541 }
542
543 CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
544                                  std::string const& config)
545   : FileAPI(fileAPI)
546   , Version(version)
547   , Config(config)
548   , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
549   , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
550 {
551   static_cast<void>(this->Version);
552 }
553
554 Json::Value CodemodelConfig::Dump()
555 {
556   Json::Value configuration = Json::objectValue;
557   configuration["name"] = this->Config;
558   this->ProcessDirectories();
559   configuration["targets"] = this->DumpTargets();
560   configuration["directories"] = this->DumpDirectories();
561   configuration["projects"] = this->DumpProjects();
562   return configuration;
563 }
564
565 void CodemodelConfig::ProcessDirectories()
566 {
567   cmGlobalGenerator* gg =
568     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
569   auto const& localGens = gg->GetLocalGenerators();
570
571   // Add directories in forward order to process parents before children.
572   this->Directories.reserve(localGens.size());
573   for (const auto& lg : localGens) {
574     auto directoryIndex =
575       static_cast<Json::ArrayIndex>(this->Directories.size());
576     this->Directories.emplace_back();
577     Directory& d = this->Directories[directoryIndex];
578     d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory();
579     d.LocalGenerator = lg.get();
580     this->DirectoryMap[d.Snapshot] = directoryIndex;
581
582     d.ProjectIndex = this->AddProject(d.Snapshot);
583     this->Projects[d.ProjectIndex].DirectoryIndexes.append(directoryIndex);
584   }
585
586   // Update directories in reverse order to process children before parents.
587   for (auto di = this->Directories.rbegin(); di != this->Directories.rend();
588        ++di) {
589     Directory& d = *di;
590
591     // Accumulate the presence of install rules on the way up.
592     for (const auto& gen :
593          d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
594       if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) {
595         d.HasInstallRule = true;
596         break;
597       }
598     }
599     if (!d.HasInstallRule) {
600       for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
601         cmStateSnapshot childDir = child.GetBuildsystemDirectory();
602         Json::ArrayIndex const childIndex = this->GetDirectoryIndex(childDir);
603         if (this->Directories[childIndex].HasInstallRule) {
604           d.HasInstallRule = true;
605           break;
606         }
607       }
608     }
609   }
610 }
611
612 Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmLocalGenerator const* lg)
613 {
614   return this->GetDirectoryIndex(
615     lg->GetStateSnapshot().GetBuildsystemDirectory());
616 }
617
618 Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmStateSnapshot s)
619 {
620   auto i = this->DirectoryMap.find(s);
621   assert(i != this->DirectoryMap.end());
622   return i->second;
623 }
624
625 Json::ArrayIndex CodemodelConfig::AddProject(cmStateSnapshot s)
626 {
627   cmStateSnapshot ps = s.GetBuildsystemDirectoryParent();
628   if (ps.IsValid() && ps.GetProjectName() == s.GetProjectName()) {
629     // This directory is part of its parent directory project.
630     Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
631     return this->Directories[parentDirIndex].ProjectIndex;
632   }
633
634   // This directory starts a new project.
635   auto projectIndex = static_cast<Json::ArrayIndex>(this->Projects.size());
636   this->Projects.emplace_back();
637   Project& p = this->Projects[projectIndex];
638   p.Snapshot = s;
639   this->ProjectMap[s] = projectIndex;
640   if (ps.IsValid()) {
641     Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
642     p.ParentIndex = this->Directories[parentDirIndex].ProjectIndex;
643     this->Projects[p.ParentIndex].ChildIndexes.append(projectIndex);
644   }
645   return projectIndex;
646 }
647
648 Json::Value CodemodelConfig::DumpTargets()
649 {
650   Json::Value targets = Json::arrayValue;
651
652   std::vector<cmGeneratorTarget*> targetList;
653   cmGlobalGenerator* gg =
654     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
655   for (const auto& lg : gg->GetLocalGenerators()) {
656     cm::append(targetList, lg->GetGeneratorTargets());
657   }
658   std::sort(targetList.begin(), targetList.end(),
659             [](cmGeneratorTarget* l, cmGeneratorTarget* r) {
660               return l->GetName() < r->GetName();
661             });
662
663   for (cmGeneratorTarget* gt : targetList) {
664     if (gt->GetType() == cmStateEnums::GLOBAL_TARGET ||
665         !gt->IsInBuildSystem()) {
666       continue;
667     }
668
669     targets.append(this->DumpTarget(gt, targets.size()));
670   }
671
672   return targets;
673 }
674
675 Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
676                                         Json::ArrayIndex ti)
677 {
678   Target t(gt, this->Config);
679   std::string prefix = "target-" + gt->GetName();
680   for (char& c : prefix) {
681     // CMP0037 OLD behavior allows slashes in target names.  Remove them.
682     if (c == '/' || c == '\\') {
683       c = '_';
684     }
685   }
686   if (!this->Config.empty()) {
687     prefix += "-" + this->Config;
688   }
689   Json::Value target = this->FileAPI.MaybeJsonFile(t.Dump(), prefix);
690   target["name"] = gt->GetName();
691   target["id"] = TargetId(gt, this->TopBuild);
692
693   // Cross-reference directory containing target.
694   Json::ArrayIndex di = this->GetDirectoryIndex(gt->GetLocalGenerator());
695   target["directoryIndex"] = di;
696   this->Directories[di].TargetIndexes.append(ti);
697
698   // Cross-reference project containing target.
699   Json::ArrayIndex pi = this->Directories[di].ProjectIndex;
700   target["projectIndex"] = pi;
701   this->Projects[pi].TargetIndexes.append(ti);
702
703   this->TargetIndexMap[gt] = ti;
704
705   return target;
706 }
707
708 Json::Value CodemodelConfig::DumpDirectories()
709 {
710   Json::Value directories = Json::arrayValue;
711   for (Directory& d : this->Directories) {
712     directories.append(this->DumpDirectory(d));
713   }
714   return directories;
715 }
716
717 Json::Value CodemodelConfig::DumpDirectory(Directory& d)
718 {
719   Json::Value directory = this->DumpDirectoryObject(d);
720
721   std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
722   directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
723
724   std::string buildDir = d.Snapshot.GetDirectory().GetCurrentBinary();
725   directory["build"] = RelativeIfUnder(this->TopBuild, buildDir);
726
727   cmStateSnapshot parentDir = d.Snapshot.GetBuildsystemDirectoryParent();
728   if (parentDir.IsValid()) {
729     directory["parentIndex"] = this->GetDirectoryIndex(parentDir);
730   }
731
732   Json::Value childIndexes = Json::arrayValue;
733   for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
734     childIndexes.append(
735       this->GetDirectoryIndex(child.GetBuildsystemDirectory()));
736   }
737   if (!childIndexes.empty()) {
738     directory["childIndexes"] = std::move(childIndexes);
739   }
740
741   directory["projectIndex"] = d.ProjectIndex;
742
743   if (!d.TargetIndexes.empty()) {
744     directory["targetIndexes"] = std::move(d.TargetIndexes);
745   }
746
747   Json::Value minimumCMakeVersion = this->DumpMinimumCMakeVersion(d.Snapshot);
748   if (!minimumCMakeVersion.isNull()) {
749     directory["minimumCMakeVersion"] = std::move(minimumCMakeVersion);
750   }
751
752   if (d.HasInstallRule) {
753     directory["hasInstallRule"] = true;
754   }
755
756   return directory;
757 }
758
759 Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
760 {
761   std::string prefix = "directory";
762   std::string sourceDirRel = RelativeIfUnder(
763     this->TopSource, d.Snapshot.GetDirectory().GetCurrentSource());
764   std::string buildDirRel = RelativeIfUnder(
765     this->TopBuild, d.Snapshot.GetDirectory().GetCurrentBinary());
766   if (!cmSystemTools::FileIsFullPath(buildDirRel)) {
767     prefix = cmStrCat(prefix, '-', buildDirRel);
768   } else if (!cmSystemTools::FileIsFullPath(sourceDirRel)) {
769     prefix = cmStrCat(prefix, '-', sourceDirRel);
770   }
771   for (char& c : prefix) {
772     if (c == '/' || c == '\\') {
773       c = '.';
774     }
775   }
776   if (!this->Config.empty()) {
777     prefix += "-" + this->Config;
778   }
779
780   DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
781   return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
782 }
783
784 Json::Value CodemodelConfig::DumpProjects()
785 {
786   Json::Value projects = Json::arrayValue;
787   for (Project& p : this->Projects) {
788     projects.append(this->DumpProject(p));
789   }
790   return projects;
791 }
792
793 Json::Value CodemodelConfig::DumpProject(Project& p)
794 {
795   Json::Value project = Json::objectValue;
796
797   project["name"] = p.Snapshot.GetProjectName();
798
799   if (p.ParentIndex != Project::NoParentIndex) {
800     project["parentIndex"] = p.ParentIndex;
801   }
802
803   if (!p.ChildIndexes.empty()) {
804     project["childIndexes"] = std::move(p.ChildIndexes);
805   }
806
807   project["directoryIndexes"] = std::move(p.DirectoryIndexes);
808
809   if (!p.TargetIndexes.empty()) {
810     project["targetIndexes"] = std::move(p.TargetIndexes);
811   }
812
813   return project;
814 }
815
816 Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
817 {
818   Json::Value minimumCMakeVersion;
819   if (cmValue def = s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
820     minimumCMakeVersion = Json::objectValue;
821     minimumCMakeVersion["string"] = *def;
822   }
823   return minimumCMakeVersion;
824 }
825
826 DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
827                                  std::string const& config,
828                                  TargetIndexMapType& targetIndexMap)
829   : LG(lg)
830   , Config(config)
831   , TargetIndexMap(targetIndexMap)
832   , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
833   , TopBuild(
834       lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
835   , Backtraces(this->TopSource)
836 {
837 }
838
839 Json::Value DirectoryObject::Dump()
840 {
841   Json::Value directoryObject = Json::objectValue;
842   directoryObject["paths"] = this->DumpPaths();
843   directoryObject["installers"] = this->DumpInstallers();
844   directoryObject["backtraceGraph"] = this->Backtraces.Dump();
845   return directoryObject;
846 }
847
848 void DirectoryObject::AddBacktrace(Json::Value& object,
849                                    cmListFileBacktrace const& bt)
850 {
851   if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
852     object["backtrace"] = backtrace.Index;
853   }
854 }
855
856 Json::Value DirectoryObject::DumpPaths()
857 {
858   Json::Value paths = Json::objectValue;
859
860   std::string const& sourceDir = this->LG->GetCurrentSourceDirectory();
861   paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
862
863   std::string const& buildDir = this->LG->GetCurrentBinaryDirectory();
864   paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
865
866   return paths;
867 }
868
869 Json::Value DirectoryObject::DumpInstallers()
870 {
871   Json::Value installers = Json::arrayValue;
872   for (const auto& gen : this->LG->GetMakefile()->GetInstallGenerators()) {
873     Json::Value installer = this->DumpInstaller(gen.get());
874     if (!installer.empty()) {
875       installers.append(std::move(installer)); // NOLINT(*)
876     }
877   }
878   return installers;
879 }
880
881 Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
882 {
883   assert(gen);
884   Json::Value installer = Json::objectValue;
885
886   // Exclude subdirectory installers and file(GET_RUNTIME_DEPENDENCIES)
887   // installers. They are implementation details.
888   if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen) ||
889       dynamic_cast<cmInstallGetRuntimeDependenciesGenerator*>(gen)) {
890     return installer;
891   }
892
893   // Exclude installers not used in this configuration.
894   if (!gen->InstallsForConfig(this->Config)) {
895     return installer;
896   }
897
898   // Add fields specific to each kind of install generator.
899   if (auto* installTarget = dynamic_cast<cmInstallTargetGenerator*>(gen)) {
900     cmInstallTargetGenerator::Files const& files =
901       installTarget->GetFiles(this->Config);
902     if (files.From.empty()) {
903       return installer;
904     }
905
906     installer["type"] = "target";
907     installer["destination"] = installTarget->GetDestination(this->Config);
908     installer["targetId"] =
909       TargetId(installTarget->GetTarget(), this->TopBuild);
910     installer["targetIndex"] =
911       this->TargetIndexMap[installTarget->GetTarget()];
912
913     std::string fromDir = files.FromDir;
914     if (!fromDir.empty()) {
915       fromDir.push_back('/');
916     }
917
918     std::string toDir = files.ToDir;
919     if (!toDir.empty()) {
920       toDir.push_back('/');
921     }
922
923     Json::Value paths = Json::arrayValue;
924     for (size_t i = 0; i < files.From.size(); ++i) {
925       std::string const& fromPath = cmStrCat(fromDir, files.From[i]);
926       std::string const& toPath = cmStrCat(toDir, files.To[i]);
927       paths.append(this->DumpInstallerPath(this->TopBuild, fromPath, toPath));
928     }
929     installer["paths"] = std::move(paths);
930
931     if (installTarget->GetOptional()) {
932       installer["isOptional"] = true;
933     }
934
935     if (installTarget->IsImportLibrary()) {
936       installer["targetIsImportLibrary"] = true;
937     }
938
939     switch (files.NamelinkMode) {
940       case cmInstallTargetGenerator::NamelinkModeNone:
941         break;
942       case cmInstallTargetGenerator::NamelinkModeOnly:
943         installer["targetInstallNamelink"] = "only";
944         break;
945       case cmInstallTargetGenerator::NamelinkModeSkip:
946         installer["targetInstallNamelink"] = "skip";
947         break;
948     }
949
950     // FIXME: Parse FilePermissions to provide structured information.
951     // FIXME: Thread EXPORT name through from install() call.
952   } else if (auto* installFiles =
953                dynamic_cast<cmInstallFilesGenerator*>(gen)) {
954     std::vector<std::string> const& files =
955       installFiles->GetFiles(this->Config);
956     if (files.empty()) {
957       return installer;
958     }
959
960     installer["type"] = "file";
961     installer["destination"] = installFiles->GetDestination(this->Config);
962     Json::Value paths = Json::arrayValue;
963     std::string const& rename = installFiles->GetRename(this->Config);
964     if (!rename.empty() && files.size() == 1) {
965       paths.append(this->DumpInstallerPath(this->TopSource, files[0], rename));
966     } else {
967       for (std::string const& file : installFiles->GetFiles(this->Config)) {
968         paths.append(RelativeIfUnder(this->TopSource, file));
969       }
970     }
971     installer["paths"] = std::move(paths);
972     if (installFiles->GetOptional()) {
973       installer["isOptional"] = true;
974     }
975     // FIXME: Parse FilePermissions to provide structured information.
976   } else if (auto* installDir =
977                dynamic_cast<cmInstallDirectoryGenerator*>(gen)) {
978     std::vector<std::string> const& dirs =
979       installDir->GetDirectories(this->Config);
980     if (dirs.empty()) {
981       return installer;
982     }
983
984     installer["type"] = "directory";
985     installer["destination"] = installDir->GetDestination(this->Config);
986     Json::Value paths = Json::arrayValue;
987     for (std::string const& dir : dirs) {
988       if (cmHasLiteralSuffix(dir, "/")) {
989         paths.append(this->DumpInstallerPath(
990           this->TopSource, dir.substr(0, dir.size() - 1), "."));
991       } else {
992         paths.append(this->DumpInstallerPath(
993           this->TopSource, dir, cmSystemTools::GetFilenameName(dir)));
994       }
995     }
996     installer["paths"] = std::move(paths);
997     if (installDir->GetOptional()) {
998       installer["isOptional"] = true;
999     }
1000     // FIXME: Parse FilePermissions, DirPermissions, and LiteralArguments.
1001     // to provide structured information.
1002   } else if (auto* installExport =
1003                dynamic_cast<cmInstallExportGenerator*>(gen)) {
1004     installer["type"] = "export";
1005     installer["destination"] = installExport->GetDestination();
1006     cmExportSet* exportSet = installExport->GetExportSet();
1007     installer["exportName"] = exportSet->GetName();
1008     installer["exportTargets"] = this->DumpInstallerExportTargets(exportSet);
1009     Json::Value paths = Json::arrayValue;
1010     paths.append(
1011       RelativeIfUnder(this->TopBuild, installExport->GetMainImportFile()));
1012     installer["paths"] = std::move(paths);
1013   } else if (auto* installScript =
1014                dynamic_cast<cmInstallScriptGenerator*>(gen)) {
1015     if (installScript->IsCode()) {
1016       installer["type"] = "code";
1017     } else {
1018       installer["type"] = "script";
1019       installer["scriptFile"] = RelativeIfUnder(
1020         this->TopSource, installScript->GetScript(this->Config));
1021     }
1022   } else if (auto* installImportedRuntimeArtifacts =
1023                dynamic_cast<cmInstallImportedRuntimeArtifactsGenerator*>(
1024                  gen)) {
1025     installer["type"] = "importedRuntimeArtifacts";
1026     installer["destination"] =
1027       installImportedRuntimeArtifacts->GetDestination(this->Config);
1028     if (installImportedRuntimeArtifacts->GetOptional()) {
1029       installer["isOptional"] = true;
1030     }
1031   } else if (auto* installRuntimeDependencySet =
1032                dynamic_cast<cmInstallRuntimeDependencySetGenerator*>(gen)) {
1033     installer["type"] = "runtimeDependencySet";
1034     installer["destination"] =
1035       installRuntimeDependencySet->GetDestination(this->Config);
1036     std::string name(
1037       installRuntimeDependencySet->GetRuntimeDependencySet()->GetName());
1038     if (!name.empty()) {
1039       installer["runtimeDependencySetName"] = name;
1040     }
1041     switch (installRuntimeDependencySet->GetDependencyType()) {
1042       case cmInstallRuntimeDependencySetGenerator::DependencyType::Framework:
1043         installer["runtimeDependencySetType"] = "framework";
1044         break;
1045       case cmInstallRuntimeDependencySetGenerator::DependencyType::Library:
1046         installer["runtimeDependencySetType"] = "library";
1047         break;
1048     }
1049   } else if (auto* installFileSet =
1050                dynamic_cast<cmInstallFileSetGenerator*>(gen)) {
1051     installer["type"] = "fileSet";
1052     installer["destination"] = installFileSet->GetDestination(this->Config);
1053
1054     auto* fileSet = installFileSet->GetFileSet();
1055     auto* target = installFileSet->GetTarget();
1056
1057     auto dirCges = fileSet->CompileDirectoryEntries();
1058     auto dirs = fileSet->EvaluateDirectoryEntries(
1059       dirCges, target->GetLocalGenerator(), this->Config, target);
1060
1061     auto entryCges = fileSet->CompileFileEntries();
1062     std::map<std::string, std::vector<std::string>> entries;
1063     for (auto const& entryCge : entryCges) {
1064       fileSet->EvaluateFileEntry(dirs, entries, entryCge,
1065                                  target->GetLocalGenerator(), this->Config,
1066                                  target);
1067     }
1068
1069     Json::Value files = Json::arrayValue;
1070     for (auto const& it : entries) {
1071       auto dir = it.first;
1072       if (!dir.empty()) {
1073         dir += '/';
1074       }
1075       for (auto const& file : it.second) {
1076         files.append(this->DumpInstallerPath(
1077           this->TopSource, file,
1078           cmStrCat(dir, cmSystemTools::GetFilenameName(file))));
1079       }
1080     }
1081     installer["paths"] = std::move(files);
1082     installer["fileSetName"] = fileSet->GetName();
1083     installer["fileSetType"] = fileSet->GetType();
1084     installer["fileSetDirectories"] = Json::arrayValue;
1085     for (auto const& dir : dirs) {
1086       installer["fileSetDirectories"].append(
1087         RelativeIfUnder(this->TopSource, dir));
1088     }
1089     installer["fileSetTarget"] = Json::objectValue;
1090     installer["fileSetTarget"]["id"] = TargetId(target, this->TopBuild);
1091     installer["fileSetTarget"]["index"] = this->TargetIndexMap[target];
1092
1093     if (installFileSet->GetOptional()) {
1094       installer["isOptional"] = true;
1095     }
1096   } else if (auto* cxxModuleBmi =
1097                dynamic_cast<cmInstallCxxModuleBmiGenerator*>(gen)) {
1098     installer["type"] = "cxxModuleBmi";
1099     installer["destination"] = cxxModuleBmi->GetDestination(this->Config);
1100
1101     auto const* target = cxxModuleBmi->GetTarget();
1102     installer["cxxModuleBmiTarget"] = Json::objectValue;
1103     installer["cxxModuleBmiTarget"]["id"] = TargetId(target, this->TopBuild);
1104     installer["cxxModuleBmiTarget"]["index"] = this->TargetIndexMap[target];
1105
1106     // FIXME: Parse FilePermissions.
1107     // FIXME: Parse MessageLevel.
1108     if (cxxModuleBmi->GetOptional()) {
1109       installer["isOptional"] = true;
1110     }
1111   }
1112
1113   // Add fields common to all install generators.
1114   installer["component"] = gen->GetComponent();
1115   if (gen->GetExcludeFromAll()) {
1116     installer["isExcludeFromAll"] = true;
1117   }
1118
1119   if (gen->GetAllComponentsFlag()) {
1120     installer["isForAllComponents"] = true;
1121   }
1122
1123   this->AddBacktrace(installer, gen->GetBacktrace());
1124
1125   return installer;
1126 }
1127
1128 Json::Value DirectoryObject::DumpInstallerExportTargets(cmExportSet* exp)
1129 {
1130   Json::Value targets = Json::arrayValue;
1131   for (auto const& targetExport : exp->GetTargetExports()) {
1132     Json::Value target = Json::objectValue;
1133     target["id"] = TargetId(targetExport->Target, this->TopBuild);
1134     target["index"] = this->TargetIndexMap[targetExport->Target];
1135     targets.append(std::move(target)); // NOLINT(*)
1136   }
1137   return targets;
1138 }
1139
1140 Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
1141                                                std::string const& fromPathIn,
1142                                                std::string const& toPath)
1143 {
1144   Json::Value installPath;
1145
1146   std::string fromPath = RelativeIfUnder(top, fromPathIn);
1147
1148   // If toPath is the last component of fromPath, use just fromPath.
1149   if (toPath.find_first_of('/') == std::string::npos &&
1150       cmHasSuffix(fromPath, toPath) &&
1151       (fromPath.size() == toPath.size() ||
1152        fromPath[fromPath.size() - toPath.size() - 1] == '/')) {
1153     installPath = fromPath;
1154   } else {
1155     installPath = Json::objectValue;
1156     installPath["from"] = fromPath;
1157     installPath["to"] = toPath;
1158   }
1159
1160   return installPath;
1161 }
1162
1163 Target::Target(cmGeneratorTarget* gt, std::string const& config)
1164   : GT(gt)
1165   , Config(config)
1166   , TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
1167   , TopBuild(
1168       gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
1169   , SourceGroupsLocal(this->GT->Makefile->GetSourceGroups())
1170   , Backtraces(this->TopSource)
1171 {
1172 }
1173
1174 Json::Value Target::Dump()
1175 {
1176   Json::Value target = Json::objectValue;
1177
1178   cmStateEnums::TargetType const type = this->GT->GetType();
1179
1180   target["name"] = this->GT->GetName();
1181   target["type"] = cmState::GetTargetTypeName(type);
1182   target["id"] = TargetId(this->GT, this->TopBuild);
1183   target["paths"] = this->DumpPaths();
1184   if (this->GT->Target->GetIsGeneratorProvided()) {
1185     target["isGeneratorProvided"] = true;
1186   }
1187
1188   this->AddBacktrace(target, this->GT->GetBacktrace());
1189
1190   if (this->GT->Target->GetHaveInstallRule()) {
1191     target["install"] = this->DumpInstall();
1192   }
1193
1194   if (this->GT->HaveWellDefinedOutputFiles()) {
1195     Json::Value artifacts = this->DumpArtifacts();
1196     if (!artifacts.empty()) {
1197       target["artifacts"] = std::move(artifacts);
1198     }
1199   }
1200
1201   if (type == cmStateEnums::EXECUTABLE ||
1202       type == cmStateEnums::SHARED_LIBRARY ||
1203       type == cmStateEnums::MODULE_LIBRARY) {
1204     target["nameOnDisk"] = this->GT->GetFullName(this->Config);
1205     target["link"] = this->DumpLink();
1206   } else if (type == cmStateEnums::STATIC_LIBRARY) {
1207     target["nameOnDisk"] = this->GT->GetFullName(this->Config);
1208     target["archive"] = this->DumpArchive();
1209   }
1210
1211   Json::Value dependencies = this->DumpDependencies();
1212   if (!dependencies.empty()) {
1213     target["dependencies"] = dependencies;
1214   }
1215
1216   {
1217     this->ProcessLanguages();
1218
1219     target["sources"] = this->DumpSources();
1220
1221     Json::Value folder = this->DumpFolder();
1222     if (!folder.isNull()) {
1223       target["folder"] = std::move(folder);
1224     }
1225
1226     Json::Value sourceGroups = this->DumpSourceGroups();
1227     if (!sourceGroups.empty()) {
1228       target["sourceGroups"] = std::move(sourceGroups);
1229     }
1230
1231     Json::Value compileGroups = this->DumpCompileGroups();
1232     if (!compileGroups.empty()) {
1233       target["compileGroups"] = std::move(compileGroups);
1234     }
1235   }
1236
1237   target["backtraceGraph"] = this->Backtraces.Dump();
1238
1239   return target;
1240 }
1241
1242 void Target::ProcessLanguages()
1243 {
1244   std::set<std::string> languages;
1245   this->GT->GetLanguages(languages, this->Config);
1246   for (std::string const& lang : languages) {
1247     this->ProcessLanguage(lang);
1248   }
1249 }
1250
1251 void Target::ProcessLanguage(std::string const& lang)
1252 {
1253   CompileData& cd = this->CompileDataMap[lang];
1254   cd.Language = lang;
1255   if (cmValue sysrootCompile =
1256         this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
1257     cd.Sysroot = *sysrootCompile;
1258   } else if (cmValue sysroot =
1259                this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
1260     cd.Sysroot = *sysroot;
1261   }
1262   cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1263   {
1264     // FIXME: Add flags from end section of ExpandRuleVariable,
1265     // which may need to be factored out.
1266     std::vector<BT<std::string>> flags =
1267       lg->GetTargetCompileFlags(this->GT, this->Config, lang);
1268
1269     cd.Flags.reserve(flags.size());
1270     for (const BT<std::string>& f : flags) {
1271       cd.Flags.emplace_back(this->ToJBT(f));
1272     }
1273   }
1274   std::set<BT<std::string>> defines =
1275     lg->GetTargetDefines(this->GT, this->Config, lang);
1276   cd.Defines.reserve(defines.size());
1277   for (BT<std::string> const& d : defines) {
1278     cd.Defines.emplace_back(this->ToJBT(d));
1279   }
1280   std::vector<BT<std::string>> includePathList =
1281     lg->GetIncludeDirectories(this->GT, lang, this->Config);
1282   for (BT<std::string> const& i : includePathList) {
1283     cd.Includes.emplace_back(
1284       this->ToJBT(i),
1285       this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
1286   }
1287   std::vector<BT<std::string>> precompileHeaders =
1288     this->GT->GetPrecompileHeaders(this->Config, lang);
1289   for (BT<std::string> const& pch : precompileHeaders) {
1290     cd.PrecompileHeaders.emplace_back(this->ToJBT(pch));
1291   }
1292   BTs<std::string> const* languageStandard =
1293     this->GT->GetLanguageStandardProperty(lang, this->Config);
1294   if (languageStandard) {
1295     cd.LanguageStandard = this->ToJBTs(*languageStandard);
1296   }
1297 }
1298
1299 Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si)
1300 {
1301   auto i = this->SourceGroupsMap.find(sg);
1302   if (i == this->SourceGroupsMap.end()) {
1303     auto sgIndex = static_cast<Json::ArrayIndex>(this->SourceGroups.size());
1304     i = this->SourceGroupsMap.emplace(sg, sgIndex).first;
1305     SourceGroup g;
1306     g.Name = sg->GetFullName();
1307     this->SourceGroups.push_back(std::move(g));
1308   }
1309   this->SourceGroups[i->second].SourceIndexes.append(si);
1310   return i->second;
1311 }
1312
1313 CompileData Target::BuildCompileData(cmSourceFile* sf)
1314 {
1315   CompileData fd;
1316
1317   fd.Language = sf->GetOrDetermineLanguage();
1318   if (fd.Language.empty()) {
1319     return fd;
1320   }
1321
1322   cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1323   cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT,
1324                                                     fd.Language);
1325
1326   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
1327   if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
1328     std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
1329     fd.Flags.emplace_back(std::move(flags), JBTIndex());
1330   }
1331   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
1332   for (BT<std::string> tmpOpt : sf->GetCompileOptions()) {
1333     tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
1334     // After generator evaluation we need to use the AppendCompileOptions
1335     // method so we handle situations where backtrace entries have lists
1336     // and properly escape flags.
1337     std::string tmp;
1338     lg->AppendCompileOptions(tmp, tmpOpt.Value);
1339     BT<std::string> opt(tmp, tmpOpt.Backtrace);
1340     fd.Flags.emplace_back(this->ToJBT(opt));
1341   }
1342
1343   // Add precompile headers compile options.
1344   std::vector<std::string> architectures;
1345   this->GT->GetAppleArchs(this->Config, architectures);
1346   if (architectures.empty()) {
1347     architectures.emplace_back();
1348   }
1349
1350   std::unordered_map<std::string, std::string> pchSources;
1351   for (const std::string& arch : architectures) {
1352     const std::string pchSource =
1353       this->GT->GetPchSource(this->Config, fd.Language, arch);
1354     if (!pchSource.empty()) {
1355       pchSources.insert(std::make_pair(pchSource, arch));
1356     }
1357   }
1358
1359   if (!pchSources.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
1360     std::string pchOptions;
1361     auto pchIt = pchSources.find(sf->ResolveFullPath());
1362     if (pchIt != pchSources.end()) {
1363       pchOptions = this->GT->GetPchCreateCompileOptions(
1364         this->Config, fd.Language, pchIt->second);
1365     } else {
1366       pchOptions =
1367         this->GT->GetPchUseCompileOptions(this->Config, fd.Language);
1368     }
1369
1370     BT<std::string> tmpOpt(pchOptions);
1371     tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
1372
1373     // After generator evaluation we need to use the AppendCompileOptions
1374     // method so we handle situations where backtrace entries have lists
1375     // and properly escape flags.
1376     std::string tmp;
1377     lg->AppendCompileOptions(tmp, tmpOpt.Value);
1378     BT<std::string> opt(tmp, tmpOpt.Backtrace);
1379     fd.Flags.emplace_back(this->ToJBT(opt));
1380   }
1381
1382   // Add include directories from source file properties.
1383   {
1384     const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
1385     for (BT<std::string> tmpInclude : sf->GetIncludeDirectories()) {
1386       tmpInclude.Value =
1387         genexInterpreter.Evaluate(tmpInclude.Value, INCLUDE_DIRECTORIES);
1388
1389       // After generator evaluation we need to use the AppendIncludeDirectories
1390       // method so we handle situations where backtrace entries have lists.
1391       std::vector<std::string> tmp;
1392       lg->AppendIncludeDirectories(tmp, tmpInclude.Value, *sf);
1393       for (std::string& i : tmp) {
1394         bool const isSystemInclude =
1395           this->GT->IsSystemIncludeDirectory(i, this->Config, fd.Language);
1396         BT<std::string> include(i, tmpInclude.Backtrace);
1397         fd.Includes.emplace_back(this->ToJBT(include), isSystemInclude);
1398       }
1399     }
1400   }
1401
1402   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
1403   std::set<BT<std::string>> fileDefines;
1404   for (BT<std::string> tmpDef : sf->GetCompileDefinitions()) {
1405     tmpDef.Value =
1406       genexInterpreter.Evaluate(tmpDef.Value, COMPILE_DEFINITIONS);
1407
1408     // After generator evaluation we need to use the AppendDefines method
1409     // so we handle situations where backtrace entries have lists.
1410     std::set<std::string> tmp;
1411     lg->AppendDefines(tmp, tmpDef.Value);
1412     for (const std::string& i : tmp) {
1413       BT<std::string> def(i, tmpDef.Backtrace);
1414       fileDefines.insert(def);
1415     }
1416   }
1417
1418   std::set<std::string> configFileDefines;
1419   const std::string defPropName =
1420     "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config);
1421   if (cmValue config_defs = sf->GetProperty(defPropName)) {
1422     lg->AppendDefines(
1423       configFileDefines,
1424       genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
1425   }
1426
1427   fd.Defines.reserve(fileDefines.size() + configFileDefines.size());
1428
1429   for (BT<std::string> const& def : fileDefines) {
1430     fd.Defines.emplace_back(this->ToJBT(def));
1431   }
1432
1433   for (std::string const& d : configFileDefines) {
1434     fd.Defines.emplace_back(d, JBTIndex());
1435   }
1436
1437   return fd;
1438 }
1439
1440 CompileData Target::MergeCompileData(CompileData const& fd)
1441 {
1442   CompileData cd;
1443   cd.Language = fd.Language;
1444   if (cd.Language.empty()) {
1445     return cd;
1446   }
1447   CompileData const& td = this->CompileDataMap.at(cd.Language);
1448
1449   // All compile groups share the sysroot of the target.
1450   cd.Sysroot = td.Sysroot;
1451
1452   // All compile groups share the precompile headers of the target.
1453   cd.PrecompileHeaders = td.PrecompileHeaders;
1454
1455   // All compile groups share the language standard of the target.
1456   cd.LanguageStandard = td.LanguageStandard;
1457
1458   // Use target-wide flags followed by source-specific flags.
1459   cd.Flags.reserve(td.Flags.size() + fd.Flags.size());
1460   cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end());
1461   cd.Flags.insert(cd.Flags.end(), fd.Flags.begin(), fd.Flags.end());
1462
1463   // Use source-specific includes followed by target-wide includes.
1464   cd.Includes.reserve(fd.Includes.size() + td.Includes.size());
1465   cd.Includes.insert(cd.Includes.end(), fd.Includes.begin(),
1466                      fd.Includes.end());
1467   cd.Includes.insert(cd.Includes.end(), td.Includes.begin(),
1468                      td.Includes.end());
1469
1470   // Use target-wide defines followed by source-specific defines.
1471   cd.Defines.reserve(td.Defines.size() + fd.Defines.size());
1472   cd.Defines.insert(cd.Defines.end(), td.Defines.begin(), td.Defines.end());
1473   cd.Defines.insert(cd.Defines.end(), fd.Defines.begin(), fd.Defines.end());
1474
1475   // De-duplicate defines.
1476   std::stable_sort(cd.Defines.begin(), cd.Defines.end(),
1477                    JBT<std::string>::ValueLess);
1478   auto end = std::unique(cd.Defines.begin(), cd.Defines.end(),
1479                          JBT<std::string>::ValueEq);
1480   cd.Defines.erase(end, cd.Defines.end());
1481
1482   return cd;
1483 }
1484
1485 Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf,
1486                                                Json::ArrayIndex si)
1487 {
1488   CompileData compileData = this->BuildCompileData(sf);
1489   auto i = this->CompileGroupMap.find(compileData);
1490   if (i == this->CompileGroupMap.end()) {
1491     Json::ArrayIndex cgIndex =
1492       static_cast<Json::ArrayIndex>(this->CompileGroups.size());
1493     i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first;
1494     CompileGroup g;
1495     g.Entry = i;
1496     this->CompileGroups.push_back(std::move(g));
1497   }
1498   this->CompileGroups[i->second].SourceIndexes.append(si);
1499   return i->second;
1500 }
1501
1502 void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt)
1503 {
1504   if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
1505     object["backtrace"] = backtrace.Index;
1506   }
1507 }
1508
1509 void Target::AddBacktrace(Json::Value& object, JBTIndex bt)
1510 {
1511   if (bt) {
1512     object["backtrace"] = bt.Index;
1513   }
1514 }
1515
1516 Json::Value Target::DumpPaths()
1517 {
1518   Json::Value paths = Json::objectValue;
1519   cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1520
1521   std::string const& sourceDir = lg->GetCurrentSourceDirectory();
1522   paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
1523
1524   std::string const& buildDir = lg->GetCurrentBinaryDirectory();
1525   paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
1526
1527   return paths;
1528 }
1529
1530 Json::Value Target::DumpSources()
1531 {
1532   Json::Value sources = Json::arrayValue;
1533   cmGeneratorTarget::KindedSources const& kinded =
1534     this->GT->GetKindedSources(this->Config);
1535   for (cmGeneratorTarget::SourceAndKind const& sk : kinded.Sources) {
1536     sources.append(this->DumpSource(sk, sources.size()));
1537   }
1538   return sources;
1539 }
1540
1541 Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
1542                                Json::ArrayIndex si)
1543 {
1544   Json::Value source = Json::objectValue;
1545
1546   std::string const path = sk.Source.Value->ResolveFullPath();
1547   source["path"] = RelativeIfUnder(this->TopSource, path);
1548   if (sk.Source.Value->GetIsGenerated()) {
1549     source["isGenerated"] = true;
1550   }
1551   this->AddBacktrace(source, sk.Source.Backtrace);
1552
1553   if (cmSourceGroup* sg =
1554         this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) {
1555     source["sourceGroupIndex"] = this->AddSourceGroup(sg, si);
1556   }
1557
1558   switch (sk.Kind) {
1559     case cmGeneratorTarget::SourceKindObjectSource: {
1560       source["compileGroupIndex"] =
1561         this->AddSourceCompileGroup(sk.Source.Value, si);
1562     } break;
1563     case cmGeneratorTarget::SourceKindAppManifest:
1564     case cmGeneratorTarget::SourceKindCertificate:
1565     case cmGeneratorTarget::SourceKindCustomCommand:
1566     case cmGeneratorTarget::SourceKindExternalObject:
1567     case cmGeneratorTarget::SourceKindExtra:
1568     case cmGeneratorTarget::SourceKindHeader:
1569     case cmGeneratorTarget::SourceKindIDL:
1570     case cmGeneratorTarget::SourceKindManifest:
1571     case cmGeneratorTarget::SourceKindModuleDefinition:
1572     case cmGeneratorTarget::SourceKindResx:
1573     case cmGeneratorTarget::SourceKindXaml:
1574     case cmGeneratorTarget::SourceKindUnityBatched:
1575       break;
1576   }
1577
1578   return source;
1579 }
1580
1581 Json::Value Target::DumpCompileData(CompileData const& cd)
1582 {
1583   Json::Value result = Json::objectValue;
1584
1585   if (!cd.Language.empty()) {
1586     result["language"] = cd.Language;
1587   }
1588   if (!cd.Sysroot.empty()) {
1589     result["sysroot"] = this->DumpSysroot(cd.Sysroot);
1590   }
1591   if (!cd.Flags.empty()) {
1592     result["compileCommandFragments"] = this->DumpCommandFragments(cd.Flags);
1593   }
1594   if (!cd.Includes.empty()) {
1595     Json::Value includes = Json::arrayValue;
1596     for (auto const& i : cd.Includes) {
1597       includes.append(this->DumpInclude(i));
1598     }
1599     result["includes"] = includes;
1600   }
1601   if (!cd.Defines.empty()) {
1602     Json::Value defines = Json::arrayValue;
1603     for (JBT<std::string> const& d : cd.Defines) {
1604       defines.append(this->DumpDefine(d));
1605     }
1606     result["defines"] = std::move(defines);
1607   }
1608   if (!cd.PrecompileHeaders.empty()) {
1609     Json::Value precompileHeaders = Json::arrayValue;
1610     for (JBT<std::string> const& pch : cd.PrecompileHeaders) {
1611       precompileHeaders.append(this->DumpPrecompileHeader(pch));
1612     }
1613     result["precompileHeaders"] = std::move(precompileHeaders);
1614   }
1615   if (!cd.LanguageStandard.Value.empty()) {
1616     result["languageStandard"] =
1617       this->DumpLanguageStandard(cd.LanguageStandard);
1618   }
1619
1620   return result;
1621 }
1622
1623 Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc)
1624 {
1625   Json::Value include = Json::objectValue;
1626   include["path"] = inc.Path.Value;
1627   if (inc.IsSystem) {
1628     include["isSystem"] = true;
1629   }
1630   this->AddBacktrace(include, inc.Path.Backtrace);
1631   return include;
1632 }
1633
1634 Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header)
1635 {
1636   Json::Value precompileHeader = Json::objectValue;
1637   precompileHeader["header"] = header.Value;
1638   this->AddBacktrace(precompileHeader, header.Backtrace);
1639   return precompileHeader;
1640 }
1641
1642 Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard)
1643 {
1644   Json::Value languageStandard = Json::objectValue;
1645   languageStandard["standard"] = standard.Value;
1646   if (!standard.Backtraces.empty()) {
1647     Json::Value backtraces = Json::arrayValue;
1648     for (JBTIndex backtrace : standard.Backtraces) {
1649       backtraces.append(backtrace.Index);
1650     }
1651     languageStandard["backtraces"] = backtraces;
1652   }
1653   return languageStandard;
1654 }
1655
1656 Json::Value Target::DumpDefine(JBT<std::string> const& def)
1657 {
1658   Json::Value define = Json::objectValue;
1659   define["define"] = def.Value;
1660   this->AddBacktrace(define, def.Backtrace);
1661   return define;
1662 }
1663
1664 Json::Value Target::DumpSourceGroups()
1665 {
1666   Json::Value sourceGroups = Json::arrayValue;
1667   for (auto& sg : this->SourceGroups) {
1668     sourceGroups.append(this->DumpSourceGroup(sg));
1669   }
1670   return sourceGroups;
1671 }
1672
1673 Json::Value Target::DumpSourceGroup(SourceGroup& sg)
1674 {
1675   Json::Value group = Json::objectValue;
1676   group["name"] = sg.Name;
1677   group["sourceIndexes"] = std::move(sg.SourceIndexes);
1678   return group;
1679 }
1680
1681 Json::Value Target::DumpCompileGroups()
1682 {
1683   Json::Value compileGroups = Json::arrayValue;
1684   for (auto& cg : this->CompileGroups) {
1685     compileGroups.append(this->DumpCompileGroup(cg));
1686   }
1687   return compileGroups;
1688 }
1689
1690 Json::Value Target::DumpCompileGroup(CompileGroup& cg)
1691 {
1692   Json::Value group =
1693     this->DumpCompileData(this->MergeCompileData(cg.Entry->first));
1694   group["sourceIndexes"] = std::move(cg.SourceIndexes);
1695   return group;
1696 }
1697
1698 Json::Value Target::DumpSysroot(std::string const& path)
1699 {
1700   Json::Value sysroot = Json::objectValue;
1701   sysroot["path"] = path;
1702   return sysroot;
1703 }
1704
1705 Json::Value Target::DumpInstall()
1706 {
1707   Json::Value install = Json::objectValue;
1708   install["prefix"] = this->DumpInstallPrefix();
1709   install["destinations"] = this->DumpInstallDestinations();
1710   return install;
1711 }
1712
1713 Json::Value Target::DumpInstallPrefix()
1714 {
1715   Json::Value prefix = Json::objectValue;
1716   std::string p =
1717     this->GT->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
1718   cmSystemTools::ConvertToUnixSlashes(p);
1719   prefix["path"] = p;
1720   return prefix;
1721 }
1722
1723 Json::Value Target::DumpInstallDestinations()
1724 {
1725   Json::Value destinations = Json::arrayValue;
1726   auto installGens = this->GT->Target->GetInstallGenerators();
1727   for (auto* itGen : installGens) {
1728     destinations.append(this->DumpInstallDestination(itGen));
1729   }
1730   return destinations;
1731 }
1732
1733 Json::Value Target::DumpInstallDestination(cmInstallTargetGenerator* itGen)
1734 {
1735   Json::Value destination = Json::objectValue;
1736   destination["path"] = itGen->GetDestination(this->Config);
1737   this->AddBacktrace(destination, itGen->GetBacktrace());
1738   return destination;
1739 }
1740
1741 Json::Value Target::DumpArtifacts()
1742 {
1743   Json::Value artifacts = Json::arrayValue;
1744
1745   // Object libraries have only object files as artifacts.
1746   if (this->GT->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1747     if (!this->GT->Target->HasKnownObjectFileLocation(nullptr)) {
1748       return artifacts;
1749     }
1750     std::vector<cmSourceFile const*> objectSources;
1751     this->GT->GetObjectSources(objectSources, this->Config);
1752     std::string const obj_dir = this->GT->GetObjectDirectory(this->Config);
1753     for (cmSourceFile const* sf : objectSources) {
1754       const std::string& obj = this->GT->GetObjectName(sf);
1755       Json::Value artifact = Json::objectValue;
1756       artifact["path"] = RelativeIfUnder(this->TopBuild, obj_dir + obj);
1757       artifacts.append(std::move(artifact)); // NOLINT(*)
1758     }
1759     return artifacts;
1760   }
1761
1762   // Other target types always have a "main" artifact.
1763   {
1764     Json::Value artifact = Json::objectValue;
1765     artifact["path"] =
1766       RelativeIfUnder(this->TopBuild,
1767                       this->GT->GetFullPath(
1768                         this->Config, cmStateEnums::RuntimeBinaryArtifact));
1769     artifacts.append(std::move(artifact)); // NOLINT(*)
1770   }
1771
1772   // Add Windows-specific artifacts produced by the linker.
1773   if (this->GT->HasImportLibrary(this->Config)) {
1774     Json::Value artifact = Json::objectValue;
1775     artifact["path"] =
1776       RelativeIfUnder(this->TopBuild,
1777                       this->GT->GetFullPath(
1778                         this->Config, cmStateEnums::ImportLibraryArtifact));
1779     artifacts.append(std::move(artifact)); // NOLINT(*)
1780   }
1781   if (this->GT->IsDLLPlatform() &&
1782       this->GT->GetType() != cmStateEnums::STATIC_LIBRARY) {
1783     cmGeneratorTarget::OutputInfo const* output =
1784       this->GT->GetOutputInfo(this->Config);
1785     if (output && !output->PdbDir.empty()) {
1786       Json::Value artifact = Json::objectValue;
1787       artifact["path"] = RelativeIfUnder(this->TopBuild,
1788                                          output->PdbDir + '/' +
1789                                            this->GT->GetPDBName(this->Config));
1790       artifacts.append(std::move(artifact)); // NOLINT(*)
1791     }
1792   }
1793   return artifacts;
1794 }
1795
1796 Json::Value Target::DumpLink()
1797 {
1798   Json::Value link = Json::objectValue;
1799   std::string lang = this->GT->GetLinkerLanguage(this->Config);
1800   link["language"] = lang;
1801   {
1802     Json::Value commandFragments = this->DumpLinkCommandFragments();
1803     if (!commandFragments.empty()) {
1804       link["commandFragments"] = std::move(commandFragments);
1805     }
1806   }
1807   if (cmValue sysrootLink =
1808         this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
1809     link["sysroot"] = this->DumpSysroot(*sysrootLink);
1810   } else if (cmValue sysroot =
1811                this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
1812     link["sysroot"] = this->DumpSysroot(*sysroot);
1813   }
1814   if (this->GT->IsIPOEnabled(lang, this->Config)) {
1815     link["lto"] = true;
1816   }
1817   return link;
1818 }
1819
1820 Json::Value Target::DumpArchive()
1821 {
1822   Json::Value archive = Json::objectValue;
1823   {
1824     // The "link" fragments not relevant to static libraries are empty.
1825     Json::Value commandFragments = this->DumpLinkCommandFragments();
1826     if (!commandFragments.empty()) {
1827       archive["commandFragments"] = std::move(commandFragments);
1828     }
1829   }
1830   std::string lang = this->GT->GetLinkerLanguage(this->Config);
1831   if (this->GT->IsIPOEnabled(lang, this->Config)) {
1832     archive["lto"] = true;
1833   }
1834   return archive;
1835 }
1836
1837 Json::Value Target::DumpLinkCommandFragments()
1838 {
1839   Json::Value linkFragments = Json::arrayValue;
1840
1841   std::string linkLanguageFlags;
1842   std::vector<BT<std::string>> linkFlags;
1843   std::string frameworkPath;
1844   std::vector<BT<std::string>> linkPath;
1845   std::vector<BT<std::string>> linkLibs;
1846   cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1847   cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
1848   std::unique_ptr<cmLinkLineComputer> linkLineComputer =
1849     gg->CreateLinkLineComputer(lg, lg->GetStateSnapshot().GetDirectory());
1850   lg->GetTargetFlags(linkLineComputer.get(), this->Config, linkLibs,
1851                      linkLanguageFlags, linkFlags, frameworkPath, linkPath,
1852                      this->GT);
1853   linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
1854   frameworkPath = cmTrimWhitespace(frameworkPath);
1855
1856   if (!linkLanguageFlags.empty()) {
1857     linkFragments.append(
1858       this->DumpCommandFragment(std::move(linkLanguageFlags), "flags"));
1859   }
1860
1861   if (!linkFlags.empty()) {
1862     for (BT<std::string> frag : linkFlags) {
1863       frag.Value = cmTrimWhitespace(frag.Value);
1864       linkFragments.append(
1865         this->DumpCommandFragment(this->ToJBT(frag), "flags"));
1866     }
1867   }
1868
1869   if (!frameworkPath.empty()) {
1870     linkFragments.append(
1871       this->DumpCommandFragment(std::move(frameworkPath), "frameworkPath"));
1872   }
1873
1874   if (!linkPath.empty()) {
1875     for (BT<std::string> frag : linkPath) {
1876       frag.Value = cmTrimWhitespace(frag.Value);
1877       linkFragments.append(
1878         this->DumpCommandFragment(this->ToJBT(frag), "libraryPath"));
1879     }
1880   }
1881
1882   if (!linkLibs.empty()) {
1883     for (BT<std::string> frag : linkLibs) {
1884       frag.Value = cmTrimWhitespace(frag.Value);
1885       linkFragments.append(
1886         this->DumpCommandFragment(this->ToJBT(frag), "libraries"));
1887     }
1888   }
1889
1890   return linkFragments;
1891 }
1892
1893 Json::Value Target::DumpCommandFragments(
1894   std::vector<JBT<std::string>> const& frags)
1895 {
1896   Json::Value commandFragments = Json::arrayValue;
1897   for (JBT<std::string> const& f : frags) {
1898     commandFragments.append(this->DumpCommandFragment(f));
1899   }
1900   return commandFragments;
1901 }
1902
1903 Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag,
1904                                         std::string const& role)
1905 {
1906   Json::Value fragment = Json::objectValue;
1907   fragment["fragment"] = frag.Value;
1908   if (!role.empty()) {
1909     fragment["role"] = role;
1910   }
1911   this->AddBacktrace(fragment, frag.Backtrace);
1912   return fragment;
1913 }
1914
1915 Json::Value Target::DumpDependencies()
1916 {
1917   Json::Value dependencies = Json::arrayValue;
1918   cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
1919   for (cmTargetDepend const& td : gg->GetTargetDirectDepends(this->GT)) {
1920     dependencies.append(this->DumpDependency(td));
1921   }
1922   return dependencies;
1923 }
1924
1925 Json::Value Target::DumpDependency(cmTargetDepend const& td)
1926 {
1927   Json::Value dependency = Json::objectValue;
1928   dependency["id"] = TargetId(td, this->TopBuild);
1929   this->AddBacktrace(dependency, td.GetBacktrace());
1930   return dependency;
1931 }
1932
1933 Json::Value Target::DumpFolder()
1934 {
1935   Json::Value folder;
1936   if (cmValue f = this->GT->GetProperty("FOLDER")) {
1937     folder = Json::objectValue;
1938     folder["name"] = *f;
1939   }
1940   return folder;
1941 }
1942 }
1943
1944 Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned long version)
1945 {
1946   Codemodel codemodel(fileAPI, version);
1947   return codemodel.Dump();
1948 }