Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmFileAPICodemodel.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst 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 "cmFileSetMetadata.h"
27
#include "cmGenExContext.h"
28
#include "cmGeneratorExpression.h"
29
#include "cmGeneratorExpressionDAGChecker.h"
30
#include "cmGeneratorFileSet.h"
31
#include "cmGeneratorTarget.h"
32
#include "cmGlobalGenerator.h"
33
#include "cmInstallCxxModuleBmiGenerator.h"
34
#include "cmInstallDirectoryGenerator.h"
35
#include "cmInstallExportGenerator.h"
36
#include "cmInstallFileSetGenerator.h"
37
#include "cmInstallFilesGenerator.h"
38
#include "cmInstallGenerator.h"
39
#include "cmInstallGetRuntimeDependenciesGenerator.h"
40
#include "cmInstallImportedRuntimeArtifactsGenerator.h"
41
#include "cmInstallRuntimeDependencySet.h"
42
#include "cmInstallRuntimeDependencySetGenerator.h"
43
#include "cmInstallScriptGenerator.h"
44
#include "cmInstallSubdirectoryGenerator.h"
45
#include "cmInstallTargetGenerator.h"
46
#include "cmLinkItem.h"
47
#include "cmLinkLineComputer.h" // IWYU pragma: keep
48
#include "cmList.h"
49
#include "cmListFileCache.h"
50
#include "cmLocalGenerator.h"
51
#include "cmMakefile.h"
52
#include "cmRange.h"
53
#include "cmSourceFile.h"
54
#include "cmSourceGroup.h"
55
#include "cmState.h"
56
#include "cmStateDirectory.h"
57
#include "cmStateSnapshot.h"
58
#include "cmStateTypes.h"
59
#include "cmStringAlgorithms.h"
60
#include "cmSystemTools.h"
61
#include "cmTarget.h"
62
#include "cmTargetDepend.h"
63
#include "cmTargetExport.h"
64
#include "cmTargetTypes.h"
65
#include "cmValue.h"
66
#include "cmake.h"
67
68
namespace {
69
70
using TargetIndexMapType =
71
  std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
72
73
std::string RelativeIfUnder(std::string const& top, std::string const& in)
74
0
{
75
0
  return cmSystemTools::RelativeIfUnder(top, in);
76
0
}
77
78
class JBTIndex
79
{
80
public:
81
0
  JBTIndex() = default;
82
0
  explicit operator bool() const { return this->Index != None; }
83
  Json::ArrayIndex Index = None;
84
  static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1);
85
};
86
87
template <typename T>
88
class JBT
89
{
90
public:
91
  JBT(T v = T(), JBTIndex bt = JBTIndex())
92
0
    : Value(std::move(v))
93
0
    , Backtrace(bt)
94
0
  {
95
0
  }
96
  T Value;
97
  JBTIndex Backtrace;
98
  friend bool operator==(JBT<T> const& l, JBT<T> const& r)
99
0
  {
100
0
    return l.Value == r.Value && l.Backtrace.Index == r.Backtrace.Index;
101
0
  }
102
  static bool ValueEq(JBT<T> const& l, JBT<T> const& r)
103
0
  {
104
0
    return l.Value == r.Value;
105
0
  }
106
  static bool ValueLess(JBT<T> const& l, JBT<T> const& r)
107
0
  {
108
0
    return l.Value < r.Value;
109
0
  }
110
};
111
112
template <typename T>
113
class JBTs
114
{
115
public:
116
  JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>())
117
0
    : Value(std::move(v))
118
0
    , Backtraces(std::move(ids))
119
0
  {
120
0
  }
121
  T Value;
122
  std::vector<JBTIndex> Backtraces;
123
  friend bool operator==(JBTs<T> const& l, JBTs<T> const& r)
124
0
  {
125
0
    if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) {
126
0
      for (size_t i = 0; i < l.Backtraces.size(); i++) {
127
0
        if (l.Backtraces[i].Index != r.Backtraces[i].Index) {
128
0
          return false;
129
0
        }
130
0
      }
131
0
    }
132
0
    return true;
133
0
  }
134
  static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r)
135
  {
136
    return l.Value == r.Value;
137
  }
138
  static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r)
139
  {
140
    return l.Value < r.Value;
141
  }
142
};
143
144
class BacktraceData
145
{
146
  std::string TopSource;
147
  std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
148
  std::unordered_map<std::string, Json::ArrayIndex> FileMap;
149
  std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
150
  Json::Value Commands = Json::arrayValue;
151
  Json::Value Files = Json::arrayValue;
152
  Json::Value Nodes = Json::arrayValue;
153
154
  Json::ArrayIndex AddCommand(std::string const& command)
155
0
  {
156
0
    auto i = this->CommandMap.find(command);
157
0
    if (i == this->CommandMap.end()) {
158
0
      auto cmdIndex = static_cast<Json::ArrayIndex>(this->Commands.size());
159
0
      i = this->CommandMap.emplace(command, cmdIndex).first;
160
0
      this->Commands.append(command);
161
0
    }
162
0
    return i->second;
163
0
  }
164
165
  Json::ArrayIndex AddFile(std::string const& file)
166
0
  {
167
0
    auto i = this->FileMap.find(file);
168
0
    if (i == this->FileMap.end()) {
169
0
      auto fileIndex = static_cast<Json::ArrayIndex>(this->Files.size());
170
0
      i = this->FileMap.emplace(file, fileIndex).first;
171
0
      this->Files.append(RelativeIfUnder(this->TopSource, file));
172
0
    }
173
0
    return i->second;
174
0
  }
175
176
public:
177
  BacktraceData(std::string topSource);
178
  JBTIndex Add(cmListFileBacktrace const& bt);
179
  Json::Value Dump();
180
};
181
182
BacktraceData::BacktraceData(std::string topSource)
183
0
  : TopSource(std::move(topSource))
184
0
{
185
0
}
186
187
JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt)
188
0
{
189
0
  JBTIndex index;
190
0
  if (bt.Empty()) {
191
0
    return index;
192
0
  }
193
0
  cmListFileContext const* top = &bt.Top();
194
0
  auto found = this->NodeMap.find(top);
195
0
  if (found != this->NodeMap.end()) {
196
0
    index.Index = found->second;
197
0
    return index;
198
0
  }
199
0
  Json::Value entry = Json::objectValue;
200
0
  entry["file"] = this->AddFile(top->FilePath);
201
0
  if (top->Line) {
202
0
    entry["line"] = static_cast<int>(top->Line);
203
0
  }
204
0
  if (!top->Name.empty()) {
205
0
    entry["command"] = this->AddCommand(top->Name);
206
0
  }
207
0
  if (JBTIndex parent = this->Add(bt.Pop())) {
208
0
    entry["parent"] = parent.Index;
209
0
  }
210
0
  index.Index = this->NodeMap[top] = this->Nodes.size();
211
0
  this->Nodes.append(std::move(entry)); // NOLINT(*)
212
0
  return index;
213
0
}
214
215
Json::Value BacktraceData::Dump()
216
0
{
217
0
  Json::Value backtraceGraph;
218
0
  this->CommandMap.clear();
219
0
  this->FileMap.clear();
220
0
  this->NodeMap.clear();
221
0
  backtraceGraph["commands"] = std::move(this->Commands);
222
0
  backtraceGraph["files"] = std::move(this->Files);
223
0
  backtraceGraph["nodes"] = std::move(this->Nodes);
224
0
  return backtraceGraph;
225
0
}
226
227
class Codemodel
228
{
229
  cmFileAPI& FileAPI;
230
  unsigned int VersionMajor;
231
  unsigned int VersionMinor;
232
233
  Json::Value DumpPaths();
234
  Json::Value DumpConfigurations();
235
  Json::Value DumpConfiguration(std::string const& config);
236
237
public:
238
  Codemodel(cmFileAPI& fileAPI, unsigned int versionMajor,
239
            unsigned int versionMinor);
240
  Json::Value Dump();
241
};
242
243
class CodemodelConfig
244
{
245
  cmFileAPI& FileAPI;
246
  unsigned int VersionMajor;
247
  unsigned int VersionMinor;
248
  std::string const& Config;
249
  std::string TopSource;
250
  std::string TopBuild;
251
252
  struct Directory
253
  {
254
    cmStateSnapshot Snapshot;
255
    cmLocalGenerator const* LocalGenerator = nullptr;
256
    Json::Value BuildSystemTargetIndexes = Json::arrayValue;
257
    Json::Value AbstractTargetIndexes = Json::arrayValue;
258
    Json::ArrayIndex ProjectIndex;
259
    bool HasInstallRule = false;
260
  };
261
  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
262
    DirectoryMap;
263
  std::vector<Directory> Directories;
264
265
  struct Project
266
  {
267
    cmStateSnapshot Snapshot;
268
    static Json::ArrayIndex const NoParentIndex =
269
      static_cast<Json::ArrayIndex>(-1);
270
    Json::ArrayIndex ParentIndex = NoParentIndex;
271
    Json::Value ChildIndexes = Json::arrayValue;
272
    Json::Value DirectoryIndexes = Json::arrayValue;
273
    Json::Value BuildSystemTargetIndexes = Json::arrayValue;
274
    Json::Value AbstractTargetIndexes = Json::arrayValue;
275
  };
276
  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
277
    ProjectMap;
278
  std::vector<Project> Projects;
279
280
  TargetIndexMapType TargetIndexMap;
281
282
  struct DumpedTargets
283
  {
284
    Json::Value BuildSystemTargets = Json::arrayValue;
285
    Json::Value AbstractTargets = Json::arrayValue;
286
  };
287
288
  void ProcessDirectories();
289
290
  Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
291
  Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
292
293
  Json::ArrayIndex AddProject(cmStateSnapshot s);
294
295
  DumpedTargets DumpTargets();
296
  Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
297
298
  Json::Value DumpDirectories();
299
  Json::Value DumpDirectory(Directory& d);
300
  Json::Value DumpDirectoryObject(Directory& d);
301
302
  Json::Value DumpProjects();
303
  Json::Value DumpProject(Project& p);
304
305
  Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
306
307
public:
308
  CodemodelConfig(cmFileAPI& fileAPI, unsigned int versionMajor,
309
                  unsigned int versionMinor, std::string const& config);
310
  Json::Value Dump();
311
};
312
313
std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
314
0
{
315
0
  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
316
0
  std::string path = RelativeIfUnder(
317
0
    topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
318
0
  std::string hash = hasher.HashString(path);
319
0
  hash.resize(20, '0');
320
0
  return cmStrCat(gt->GetName(), CMAKE_DIRECTORY_ID_SEP, hash);
321
0
}
322
323
struct CompileData
324
{
325
  struct IncludeEntry
326
  {
327
    JBT<std::string> Path;
328
    bool IsSystem = false;
329
    IncludeEntry(JBT<std::string> path, bool isSystem)
330
0
      : Path(std::move(path))
331
0
      , IsSystem(isSystem)
332
0
    {
333
0
    }
334
    friend bool operator==(IncludeEntry const& l, IncludeEntry const& r)
335
0
    {
336
0
      return l.Path == r.Path && l.IsSystem == r.IsSystem;
337
0
    }
338
  };
339
340
  std::string Language;
341
  std::string Sysroot;
342
  JBTs<std::string> LanguageStandard;
343
  std::vector<JBT<std::string>> Flags;
344
  std::vector<JBT<std::string>> Defines;
345
  std::vector<JBT<std::string>> PrecompileHeaders;
346
  std::vector<IncludeEntry> Includes;
347
  std::vector<IncludeEntry> Frameworks;
348
349
  friend bool operator==(CompileData const& l, CompileData const& r)
350
0
  {
351
0
    return (l.Language == r.Language && l.Sysroot == r.Sysroot &&
352
0
            l.Flags == r.Flags && l.Defines == r.Defines &&
353
0
            l.PrecompileHeaders == r.PrecompileHeaders &&
354
0
            l.LanguageStandard == r.LanguageStandard &&
355
0
            l.Includes == r.Includes && l.Frameworks == r.Frameworks);
356
0
  }
357
};
358
}
359
360
namespace std {
361
362
template <>
363
struct hash<CompileData>
364
{
365
  std::size_t operator()(CompileData const& in) const
366
0
  {
367
0
    using std::hash;
368
0
    size_t result =
369
0
      hash<std::string>()(in.Language) ^ hash<std::string>()(in.Sysroot);
370
0
    for (auto const& i : in.Includes) {
371
0
      result = result ^
372
0
        (hash<std::string>()(i.Path.Value) ^
373
0
         hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
374
0
         (i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
375
0
    }
376
0
    for (auto const& i : in.Frameworks) {
377
0
      result = result ^
378
0
        (hash<std::string>()(i.Path.Value) ^
379
0
         hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
380
0
         (i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
381
0
    }
382
0
    for (auto const& i : in.Flags) {
383
0
      result = result ^ hash<std::string>()(i.Value) ^
384
0
        hash<Json::ArrayIndex>()(i.Backtrace.Index);
385
0
    }
386
0
    for (auto const& i : in.Defines) {
387
0
      result = result ^ hash<std::string>()(i.Value) ^
388
0
        hash<Json::ArrayIndex>()(i.Backtrace.Index);
389
0
    }
390
0
    for (auto const& i : in.PrecompileHeaders) {
391
0
      result = result ^ hash<std::string>()(i.Value) ^
392
0
        hash<Json::ArrayIndex>()(i.Backtrace.Index);
393
0
    }
394
0
    if (!in.LanguageStandard.Value.empty()) {
395
0
      result = result ^ hash<std::string>()(in.LanguageStandard.Value);
396
0
      for (JBTIndex backtrace : in.LanguageStandard.Backtraces) {
397
0
        result = result ^ hash<Json::ArrayIndex>()(backtrace.Index);
398
0
      }
399
0
    }
400
0
    return result;
401
0
  }
402
};
403
404
} // namespace std
405
406
namespace {
407
class DirectoryObject
408
{
409
  cmLocalGenerator const* LG = nullptr;
410
  unsigned int VersionMajor;
411
  unsigned int VersionMinor;
412
  std::string const& Config;
413
  TargetIndexMapType& TargetIndexMap;
414
  std::string TopSource;
415
  std::string TopBuild;
416
  BacktraceData Backtraces;
417
418
  void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
419
420
  Json::Value DumpPaths();
421
  Json::Value DumpInstallers();
422
  Json::Value DumpInstaller(cmInstallGenerator* gen);
423
  Json::Value DumpInstallerExportTargets(cmExportSet* exp);
424
  Json::Value DumpInstallerPath(std::string const& top,
425
                                std::string const& fromPathIn,
426
                                std::string const& toPath);
427
428
public:
429
  DirectoryObject(cmLocalGenerator const* lg, unsigned int versionMajor,
430
                  unsigned int versionMinor, std::string const& config,
431
                  TargetIndexMapType& targetIndexMap);
432
  Json::Value Dump();
433
};
434
435
class Target
436
{
437
  cmGeneratorTarget* GT;
438
  unsigned int VersionMajor;
439
  unsigned int VersionMinor;
440
  std::string const& Config;
441
  std::string TopSource;
442
  std::string TopBuild;
443
  BacktraceData Backtraces;
444
445
  std::map<std::string, CompileData> CompileDataMap;
446
447
  std::unordered_map<cmSourceFile const*, Json::ArrayIndex> SourceMap;
448
  Json::Value Sources = Json::arrayValue;
449
450
  struct SourceGroup
451
  {
452
    std::string Name;
453
    Json::Value SourceIndexes = Json::arrayValue;
454
    Json::Value InterfaceSourceIndexes = Json::arrayValue;
455
  };
456
  std::unordered_map<cmSourceGroup const*, Json::ArrayIndex> SourceGroupsMap;
457
  std::vector<SourceGroup> SourceGroups;
458
459
  struct CompileGroup
460
  {
461
    std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry;
462
    Json::Value SourceIndexes = Json::arrayValue;
463
  };
464
  std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
465
  std::vector<CompileGroup> CompileGroups;
466
467
  using FileSetDatabase = std::map<std::string, std::vector<Json::ArrayIndex>>;
468
469
  using FileSetBacktraceDatabase =
470
    std::unordered_map<std::string, std::vector<cmListFileBacktrace>>;
471
472
  std::vector<cm::FileSetMetadata::Visibility> FileSetVisibilities;
473
  FileSetBacktraceDatabase FileSetBacktraces;
474
475
  template <typename T>
476
  JBT<T> ToJBT(BT<T> const& bt)
477
0
  {
478
0
    return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
479
0
  }
480
481
  template <typename T>
482
  JBTs<T> ToJBTs(BTs<T> const& bts)
483
0
  {
484
0
    std::vector<JBTIndex> ids;
485
0
    ids.reserve(bts.Backtraces.size());
486
0
    for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
487
0
      ids.emplace_back(this->Backtraces.Add(backtrace));
488
0
    }
489
0
    return JBTs<T>(bts.Value, ids);
490
0
  }
491
492
  void ProcessLanguages();
493
  void ProcessLanguage(std::string const& lang);
494
495
  Json::ArrayIndex AddSourceGroup(cmSourceGroup const* sg);
496
  CompileData BuildCompileData(cmSourceFile* sf);
497
  CompileData MergeCompileData(CompileData const& fd);
498
  Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf,
499
                                         Json::ArrayIndex si);
500
  void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
501
  void AddBacktrace(Json::Value& object, JBTIndex bt);
502
  Json::Value DumpPaths();
503
  Json::Value DumpCompileData(CompileData const& cd);
504
  Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
505
  Json::Value DumpFramework(CompileData::IncludeEntry const& fw);
506
  Json::Value DumpPrecompileHeader(JBT<std::string> const& header);
507
  Json::Value DumpLanguageStandard(JBTs<std::string> const& standard);
508
  Json::Value DumpDefine(JBT<std::string> const& def);
509
  std::pair<Json::Value, FileSetDatabase> DumpFileSets();
510
  Json::Value DumpFileSet(cmGeneratorFileSet const* fs,
511
                          std::vector<std::string> const& directories);
512
  Json::Value DumpSources(FileSetDatabase const& fsdb);
513
  Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
514
                         Json::ArrayIndex si, FileSetDatabase const& fsdb);
515
  Json::Value DumpInterfaceIncludes();
516
  Json::Value DumpInterfaceSources(FileSetDatabase const& fsdb);
517
  Json::Value DumpInterfaceSource(std::string path, Json::ArrayIndex si,
518
                                  FileSetDatabase const& fsdb);
519
  Json::Value DumpSourceGroups();
520
  Json::Value DumpSourceGroup(SourceGroup& sg);
521
  Json::Value DumpCompileGroups();
522
  Json::Value DumpCompileGroup(CompileGroup& cg);
523
  Json::Value DumpSysroot(std::string const& path);
524
  Json::Value DumpInstall();
525
  Json::Value DumpInstallPrefix();
526
  Json::Value DumpInstallDestinations();
527
  Json::Value DumpInstallDestination(cmInstallTargetGenerator* itGen);
528
  Json::Value DumpArtifacts();
529
  Json::Value DumpLink();
530
  Json::Value DumpArchive();
531
  Json::Value DumpLinkCommandFragments();
532
  Json::Value DumpCommandFragments(std::vector<JBT<std::string>> const& frags);
533
  Json::Value DumpCommandFragment(JBT<std::string> const& frag,
534
                                  std::string const& role = std::string());
535
  Json::Value DumpDependencies();
536
  Json::Value DumpDependency(cmTargetDepend const& td);
537
538
  Json::Value DumpLinkItem(cmLinkItem const& linkItem);
539
  Json::Value DumpLinkImplementationLibraries(cmGeneratorTarget::UseTo usage);
540
  Json::Value DumpLinkInterfaceLibraries(cmGeneratorTarget::UseTo usage);
541
  Json::Value DumpObjectDependencies();
542
  Json::Value DumpOrderDependencies();
543
544
  Json::Value DumpFolder();
545
  Json::Value DumpLauncher(char const* name, char const* type);
546
  Json::Value DumpLaunchers();
547
548
  Json::Value DumpDebugger();
549
550
public:
551
  Target(cmGeneratorTarget* gt, unsigned int versionMajor,
552
         unsigned int versionMinor, std::string const& config);
553
  Json::Value Dump();
554
};
555
556
Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned int versionMajor,
557
                     unsigned int versionMinor)
558
0
  : FileAPI(fileAPI)
559
0
  , VersionMajor(versionMajor)
560
0
  , VersionMinor(versionMinor)
561
0
{
562
0
}
563
564
Json::Value Codemodel::Dump()
565
0
{
566
0
  Json::Value codemodel = Json::objectValue;
567
568
0
  codemodel["paths"] = this->DumpPaths();
569
0
  codemodel["configurations"] = this->DumpConfigurations();
570
571
0
  return codemodel;
572
0
}
573
574
Json::Value Codemodel::DumpPaths()
575
0
{
576
0
  Json::Value paths = Json::objectValue;
577
0
  paths["source"] = this->FileAPI.GetCMakeInstance()->GetHomeDirectory();
578
0
  paths["build"] = this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory();
579
0
  return paths;
580
0
}
581
582
Json::Value Codemodel::DumpConfigurations()
583
0
{
584
0
  Json::Value configurations = Json::arrayValue;
585
0
  cmGlobalGenerator* gg =
586
0
    this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
587
0
  auto const& makefiles = gg->GetMakefiles();
588
0
  if (!makefiles.empty()) {
589
0
    std::vector<std::string> const& configs =
590
0
      makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
591
0
    for (std::string const& config : configs) {
592
0
      configurations.append(this->DumpConfiguration(config));
593
0
    }
594
0
  }
595
0
  return configurations;
596
0
}
597
598
Json::Value Codemodel::DumpConfiguration(std::string const& config)
599
0
{
600
0
  CodemodelConfig configuration(this->FileAPI, this->VersionMajor,
601
0
                                this->VersionMinor, config);
602
0
  return configuration.Dump();
603
0
}
604
605
CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned int versionMajor,
606
                                 unsigned int versionMinor,
607
                                 std::string const& config)
608
0
  : FileAPI(fileAPI)
609
0
  , VersionMajor(versionMajor)
610
0
  , VersionMinor(versionMinor)
611
0
  , Config(config)
612
0
  , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
613
0
  , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
614
0
{
615
0
}
616
617
Json::Value CodemodelConfig::Dump()
618
0
{
619
0
  Json::Value configuration = Json::objectValue;
620
0
  configuration["name"] = this->Config;
621
0
  this->ProcessDirectories();
622
623
0
  DumpedTargets dumpedTargets = this->DumpTargets();
624
0
  configuration["targets"] = dumpedTargets.BuildSystemTargets;
625
0
  configuration["abstractTargets"] = dumpedTargets.AbstractTargets;
626
627
0
  configuration["directories"] = this->DumpDirectories();
628
0
  configuration["projects"] = this->DumpProjects();
629
630
0
  return configuration;
631
0
}
632
633
void CodemodelConfig::ProcessDirectories()
634
0
{
635
0
  cmGlobalGenerator* gg =
636
0
    this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
637
0
  auto const& localGens = gg->GetLocalGenerators();
638
639
  // Add directories in forward order to process parents before children.
640
0
  this->Directories.reserve(localGens.size());
641
0
  for (auto const& lg : localGens) {
642
0
    auto directoryIndex =
643
0
      static_cast<Json::ArrayIndex>(this->Directories.size());
644
0
    this->Directories.emplace_back();
645
0
    Directory& d = this->Directories[directoryIndex];
646
0
    d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory();
647
0
    d.LocalGenerator = lg.get();
648
0
    this->DirectoryMap[d.Snapshot] = directoryIndex;
649
650
0
    d.ProjectIndex = this->AddProject(d.Snapshot);
651
0
    this->Projects[d.ProjectIndex].DirectoryIndexes.append(directoryIndex);
652
0
  }
653
654
  // Update directories in reverse order to process children before parents.
655
0
  for (auto di = this->Directories.rbegin(); di != this->Directories.rend();
656
0
       ++di) {
657
0
    Directory& d = *di;
658
659
    // Accumulate the presence of install rules on the way up.
660
0
    for (auto const& gen :
661
0
         d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
662
0
      if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) {
663
0
        d.HasInstallRule = true;
664
0
        break;
665
0
      }
666
0
    }
667
0
    if (!d.HasInstallRule) {
668
0
      for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
669
0
        cmStateSnapshot childDir = child.GetBuildsystemDirectory();
670
0
        Json::ArrayIndex const childIndex = this->GetDirectoryIndex(childDir);
671
0
        if (this->Directories[childIndex].HasInstallRule) {
672
0
          d.HasInstallRule = true;
673
0
          break;
674
0
        }
675
0
      }
676
0
    }
677
0
  }
678
0
}
679
680
Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmLocalGenerator const* lg)
681
0
{
682
0
  return this->GetDirectoryIndex(
683
0
    lg->GetStateSnapshot().GetBuildsystemDirectory());
684
0
}
685
686
Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmStateSnapshot s)
687
0
{
688
0
  auto i = this->DirectoryMap.find(s);
689
0
  assert(i != this->DirectoryMap.end());
690
0
  return i->second;
691
0
}
692
693
Json::ArrayIndex CodemodelConfig::AddProject(cmStateSnapshot s)
694
0
{
695
0
  cmStateSnapshot ps = s.GetBuildsystemDirectoryParent();
696
0
  if (ps.IsValid() && ps.GetProjectName() == s.GetProjectName()) {
697
    // This directory is part of its parent directory project.
698
0
    Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
699
0
    return this->Directories[parentDirIndex].ProjectIndex;
700
0
  }
701
702
  // This directory starts a new project.
703
0
  auto projectIndex = static_cast<Json::ArrayIndex>(this->Projects.size());
704
0
  this->Projects.emplace_back();
705
0
  Project& p = this->Projects[projectIndex];
706
0
  p.Snapshot = s;
707
0
  this->ProjectMap[s] = projectIndex;
708
0
  if (ps.IsValid()) {
709
0
    Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
710
0
    p.ParentIndex = this->Directories[parentDirIndex].ProjectIndex;
711
0
    this->Projects[p.ParentIndex].ChildIndexes.append(projectIndex);
712
0
  }
713
0
  return projectIndex;
714
0
}
715
716
CodemodelConfig::DumpedTargets CodemodelConfig::DumpTargets()
717
0
{
718
0
  DumpedTargets dumpedTargets;
719
720
0
  std::vector<cmGeneratorTarget*> targetList;
721
0
  cmGlobalGenerator* gg =
722
0
    this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
723
0
  for (auto const& lg : gg->GetLocalGenerators()) {
724
0
    cm::append(targetList, lg->GetGeneratorTargets());
725
0
    cm::append(targetList, lg->GetOwnedImportedGeneratorTargets());
726
0
  }
727
0
  std::sort(targetList.begin(), targetList.end(),
728
0
            [](cmGeneratorTarget* l, cmGeneratorTarget* r) {
729
0
              return l->GetName() < r->GetName();
730
0
            });
731
732
0
  for (cmGeneratorTarget* gt : targetList) {
733
0
    if (gt->GetType() == cm::TargetType::GLOBAL_TARGET) {
734
0
      continue;
735
0
    }
736
737
    // Ignore targets starting with `__cmake_` as they are internal.
738
0
    if (cmHasLiteralPrefix(gt->GetName(), "__cmake_")) {
739
0
      continue;
740
0
    }
741
742
0
    Json::Value& targets = gt->IsInBuildSystem()
743
0
      ? dumpedTargets.BuildSystemTargets
744
0
      : dumpedTargets.AbstractTargets;
745
0
    targets.append(this->DumpTarget(gt, targets.size()));
746
0
  }
747
748
0
  return dumpedTargets;
749
0
}
750
751
Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
752
                                        Json::ArrayIndex ti)
753
0
{
754
0
  Target t(gt, this->VersionMajor, this->VersionMinor, this->Config);
755
0
  std::string safeTargetName = gt->GetName();
756
0
  std::replace(safeTargetName.begin(), safeTargetName.end(), ':', '_');
757
0
  std::string prefix = "target-" + safeTargetName;
758
0
  if (!this->Config.empty()) {
759
0
    prefix = cmStrCat(std::move(prefix), '-', this->Config);
760
0
  }
761
0
  Json::Value target = this->FileAPI.MaybeJsonFile(t.Dump(), prefix);
762
0
  target["name"] = gt->GetName();
763
0
  target["id"] = TargetId(gt, this->TopBuild);
764
765
  // Cross-reference directory containing target.
766
0
  Json::ArrayIndex di = this->GetDirectoryIndex(gt->GetLocalGenerator());
767
0
  target["directoryIndex"] = di;
768
0
  if (gt->IsInBuildSystem()) {
769
0
    this->Directories[di].BuildSystemTargetIndexes.append(ti);
770
0
  } else {
771
0
    this->Directories[di].AbstractTargetIndexes.append(ti);
772
0
  }
773
774
  // Cross-reference project containing target.
775
0
  Json::ArrayIndex pi = this->Directories[di].ProjectIndex;
776
0
  target["projectIndex"] = pi;
777
0
  if (gt->IsInBuildSystem()) {
778
0
    this->Projects[pi].BuildSystemTargetIndexes.append(ti);
779
0
  } else {
780
0
    this->Projects[pi].AbstractTargetIndexes.append(ti);
781
0
  }
782
783
0
  this->TargetIndexMap[gt] = ti;
784
785
0
  return target;
786
0
}
787
788
Json::Value CodemodelConfig::DumpDirectories()
789
0
{
790
0
  Json::Value directories = Json::arrayValue;
791
0
  for (Directory& d : this->Directories) {
792
0
    directories.append(this->DumpDirectory(d));
793
0
  }
794
0
  return directories;
795
0
}
796
797
Json::Value CodemodelConfig::DumpDirectory(Directory& d)
798
0
{
799
0
  Json::Value directory = this->DumpDirectoryObject(d);
800
801
0
  std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
802
0
  directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
803
804
0
  std::string buildDir = d.Snapshot.GetDirectory().GetCurrentBinary();
805
0
  directory["build"] = RelativeIfUnder(this->TopBuild, buildDir);
806
807
0
  cmStateSnapshot parentDir = d.Snapshot.GetBuildsystemDirectoryParent();
808
0
  if (parentDir.IsValid()) {
809
0
    directory["parentIndex"] = this->GetDirectoryIndex(parentDir);
810
0
  }
811
812
0
  Json::Value childIndexes = Json::arrayValue;
813
0
  for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
814
0
    childIndexes.append(
815
0
      this->GetDirectoryIndex(child.GetBuildsystemDirectory()));
816
0
  }
817
0
  if (!childIndexes.empty()) {
818
0
    directory["childIndexes"] = std::move(childIndexes);
819
0
  }
820
821
0
  directory["projectIndex"] = d.ProjectIndex;
822
823
0
  if (!d.BuildSystemTargetIndexes.empty()) {
824
0
    directory["targetIndexes"] = std::move(d.BuildSystemTargetIndexes);
825
0
  }
826
0
  if (!d.AbstractTargetIndexes.empty()) {
827
0
    directory["abstractTargetIndexes"] = std::move(d.AbstractTargetIndexes);
828
0
  }
829
830
0
  Json::Value minimumCMakeVersion = this->DumpMinimumCMakeVersion(d.Snapshot);
831
0
  if (!minimumCMakeVersion.isNull()) {
832
0
    directory["minimumCMakeVersion"] = std::move(minimumCMakeVersion);
833
0
  }
834
835
0
  if (d.HasInstallRule) {
836
0
    directory["hasInstallRule"] = true;
837
0
  }
838
839
0
  return directory;
840
0
}
841
842
Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
843
0
{
844
0
  std::string prefix = "directory";
845
0
  std::string sourceDirRel = RelativeIfUnder(
846
0
    this->TopSource, d.Snapshot.GetDirectory().GetCurrentSource());
847
0
  std::string buildDirRel = RelativeIfUnder(
848
0
    this->TopBuild, d.Snapshot.GetDirectory().GetCurrentBinary());
849
0
  if (!cmSystemTools::FileIsFullPath(buildDirRel)) {
850
0
    prefix = cmStrCat(std::move(prefix), '-', buildDirRel);
851
0
  } else if (!cmSystemTools::FileIsFullPath(sourceDirRel)) {
852
0
    prefix = cmStrCat(std::move(prefix), '-', sourceDirRel);
853
0
  }
854
0
  for (char& c : prefix) {
855
0
    if (c == '/' || c == '\\') {
856
0
      c = '.';
857
0
    }
858
0
  }
859
0
  if (!this->Config.empty()) {
860
0
    prefix = cmStrCat(std::move(prefix), '-', this->Config);
861
0
  }
862
863
0
  DirectoryObject dir(d.LocalGenerator, this->VersionMajor, this->VersionMinor,
864
0
                      this->Config, this->TargetIndexMap);
865
0
  return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
866
0
}
867
868
Json::Value CodemodelConfig::DumpProjects()
869
0
{
870
0
  Json::Value projects = Json::arrayValue;
871
0
  for (Project& p : this->Projects) {
872
0
    projects.append(this->DumpProject(p));
873
0
  }
874
0
  return projects;
875
0
}
876
877
Json::Value CodemodelConfig::DumpProject(Project& p)
878
0
{
879
0
  Json::Value project = Json::objectValue;
880
881
0
  project["name"] = p.Snapshot.GetProjectName();
882
883
0
  if (p.ParentIndex != Project::NoParentIndex) {
884
0
    project["parentIndex"] = p.ParentIndex;
885
0
  }
886
887
0
  if (!p.ChildIndexes.empty()) {
888
0
    project["childIndexes"] = std::move(p.ChildIndexes);
889
0
  }
890
891
0
  project["directoryIndexes"] = std::move(p.DirectoryIndexes);
892
893
0
  if (!p.BuildSystemTargetIndexes.empty()) {
894
0
    project["targetIndexes"] = std::move(p.BuildSystemTargetIndexes);
895
0
  }
896
0
  if (!p.AbstractTargetIndexes.empty()) {
897
0
    project["abstractTargetIndexes"] = std::move(p.AbstractTargetIndexes);
898
0
  }
899
900
0
  return project;
901
0
}
902
903
Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
904
0
{
905
0
  Json::Value minimumCMakeVersion;
906
0
  if (cmValue def = s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
907
0
    minimumCMakeVersion = Json::objectValue;
908
0
    minimumCMakeVersion["string"] = *def;
909
0
  }
910
0
  return minimumCMakeVersion;
911
0
}
912
913
DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
914
                                 unsigned int versionMajor,
915
                                 unsigned int versionMinor,
916
                                 std::string const& config,
917
                                 TargetIndexMapType& targetIndexMap)
918
0
  : LG(lg)
919
0
  , VersionMajor(versionMajor)
920
0
  , VersionMinor(versionMinor)
921
0
  , Config(config)
922
0
  , TargetIndexMap(targetIndexMap)
923
0
  , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
924
0
  , TopBuild(
925
0
      lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
926
0
  , Backtraces(this->TopSource)
927
0
{
928
0
}
929
930
Json::Value DirectoryObject::Dump()
931
0
{
932
0
  Json::Value directoryObject = Json::objectValue;
933
0
  directoryObject["codemodelVersion"] =
934
0
    cmFileAPI::BuildVersion(this->VersionMajor, this->VersionMinor);
935
0
  directoryObject["paths"] = this->DumpPaths();
936
0
  directoryObject["installers"] = this->DumpInstallers();
937
0
  directoryObject["backtraceGraph"] = this->Backtraces.Dump();
938
0
  return directoryObject;
939
0
}
940
941
void DirectoryObject::AddBacktrace(Json::Value& object,
942
                                   cmListFileBacktrace const& bt)
943
0
{
944
0
  if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
945
0
    object["backtrace"] = backtrace.Index;
946
0
  }
947
0
}
948
949
Json::Value DirectoryObject::DumpPaths()
950
0
{
951
0
  Json::Value paths = Json::objectValue;
952
953
0
  std::string const& sourceDir = this->LG->GetCurrentSourceDirectory();
954
0
  paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
955
956
0
  std::string const& buildDir = this->LG->GetCurrentBinaryDirectory();
957
0
  paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
958
959
0
  return paths;
960
0
}
961
962
Json::Value DirectoryObject::DumpInstallers()
963
0
{
964
0
  Json::Value installers = Json::arrayValue;
965
0
  for (auto const& gen : this->LG->GetMakefile()->GetInstallGenerators()) {
966
0
    Json::Value installer = this->DumpInstaller(gen.get());
967
0
    if (!installer.empty()) {
968
0
      installers.append(std::move(installer)); // NOLINT(*)
969
0
    }
970
0
  }
971
0
  return installers;
972
0
}
973
974
Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
975
0
{
976
0
  assert(gen);
977
0
  Json::Value installer = Json::objectValue;
978
979
  // Exclude subdirectory installers and file(GET_RUNTIME_DEPENDENCIES)
980
  // installers. They are implementation details.
981
0
  if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen) ||
982
0
      dynamic_cast<cmInstallGetRuntimeDependenciesGenerator*>(gen)) {
983
0
    return installer;
984
0
  }
985
986
  // Exclude installers not used in this configuration.
987
0
  if (!gen->InstallsForConfig(this->Config)) {
988
0
    return installer;
989
0
  }
990
991
  // Add fields specific to each kind of install generator.
992
0
  if (auto* installTarget = dynamic_cast<cmInstallTargetGenerator*>(gen)) {
993
0
    cmInstallTargetGenerator::Files const& files =
994
0
      installTarget->GetFiles(this->Config);
995
0
    if (files.From.empty()) {
996
0
      return installer;
997
0
    }
998
999
0
    installer["type"] = "target";
1000
0
    installer["destination"] = installTarget->GetDestination(this->Config);
1001
0
    installer["targetId"] =
1002
0
      TargetId(installTarget->GetTarget(), this->TopBuild);
1003
0
    installer["targetIndex"] =
1004
0
      this->TargetIndexMap[installTarget->GetTarget()];
1005
1006
0
    std::string fromDir = files.FromDir;
1007
0
    if (!fromDir.empty()) {
1008
0
      fromDir.push_back('/');
1009
0
    }
1010
1011
0
    std::string toDir = files.ToDir;
1012
0
    if (!toDir.empty()) {
1013
0
      toDir.push_back('/');
1014
0
    }
1015
1016
0
    Json::Value paths = Json::arrayValue;
1017
0
    for (size_t i = 0; i < files.From.size(); ++i) {
1018
0
      std::string const& fromPath = cmStrCat(fromDir, files.From[i]);
1019
0
      std::string const& toPath = cmStrCat(toDir, files.To[i]);
1020
0
      paths.append(this->DumpInstallerPath(this->TopBuild, fromPath, toPath));
1021
0
    }
1022
0
    installer["paths"] = std::move(paths);
1023
1024
0
    if (installTarget->GetOptional()) {
1025
0
      installer["isOptional"] = true;
1026
0
    }
1027
1028
0
    if (installTarget->IsImportLibrary()) {
1029
0
      installer["targetIsImportLibrary"] = true;
1030
0
    }
1031
1032
0
    switch (files.NamelinkMode) {
1033
0
      case cmInstallTargetGenerator::NamelinkModeNone:
1034
0
        break;
1035
0
      case cmInstallTargetGenerator::NamelinkModeOnly:
1036
0
        installer["targetInstallNamelink"] = "only";
1037
0
        break;
1038
0
      case cmInstallTargetGenerator::NamelinkModeSkip:
1039
0
        installer["targetInstallNamelink"] = "skip";
1040
0
        break;
1041
0
    }
1042
1043
    // FIXME: Parse FilePermissions to provide structured information.
1044
    // FIXME: Thread EXPORT name through from install() call.
1045
0
  } else if (auto* installFiles =
1046
0
               dynamic_cast<cmInstallFilesGenerator*>(gen)) {
1047
0
    std::vector<std::string> const& files =
1048
0
      installFiles->GetFiles(this->Config);
1049
0
    if (files.empty()) {
1050
0
      return installer;
1051
0
    }
1052
1053
0
    installer["type"] = "file";
1054
0
    installer["destination"] = installFiles->GetDestination(this->Config);
1055
0
    Json::Value paths = Json::arrayValue;
1056
0
    std::string const& rename = installFiles->GetRename(this->Config);
1057
0
    if (!rename.empty() && files.size() == 1) {
1058
0
      paths.append(this->DumpInstallerPath(this->TopSource, files[0], rename));
1059
0
    } else {
1060
0
      for (std::string const& file : installFiles->GetFiles(this->Config)) {
1061
0
        paths.append(RelativeIfUnder(this->TopSource, file));
1062
0
      }
1063
0
    }
1064
0
    installer["paths"] = std::move(paths);
1065
0
    if (installFiles->GetOptional()) {
1066
0
      installer["isOptional"] = true;
1067
0
    }
1068
    // FIXME: Parse FilePermissions to provide structured information.
1069
0
  } else if (auto* installDir =
1070
0
               dynamic_cast<cmInstallDirectoryGenerator*>(gen)) {
1071
0
    std::vector<std::string> const& dirs =
1072
0
      installDir->GetDirectories(this->Config);
1073
0
    if (dirs.empty()) {
1074
0
      return installer;
1075
0
    }
1076
1077
0
    installer["type"] = "directory";
1078
0
    installer["destination"] = installDir->GetDestination(this->Config);
1079
0
    Json::Value paths = Json::arrayValue;
1080
0
    for (std::string const& dir : dirs) {
1081
0
      if (cmHasSuffix(dir, '/')) {
1082
0
        paths.append(this->DumpInstallerPath(
1083
0
          this->TopSource, dir.substr(0, dir.size() - 1), "."));
1084
0
      } else {
1085
0
        paths.append(this->DumpInstallerPath(
1086
0
          this->TopSource, dir, cmSystemTools::GetFilenameName(dir)));
1087
0
      }
1088
0
    }
1089
0
    installer["paths"] = std::move(paths);
1090
0
    if (installDir->GetOptional()) {
1091
0
      installer["isOptional"] = true;
1092
0
    }
1093
    // FIXME: Parse FilePermissions, DirPermissions, and LiteralArguments.
1094
    // to provide structured information.
1095
0
  } else if (auto* installExport =
1096
0
               dynamic_cast<cmInstallExportGenerator*>(gen)) {
1097
0
    installer["type"] = "export";
1098
0
    installer["destination"] = installExport->GetDestination();
1099
0
    cmExportSet* exportSet = installExport->GetExportSet();
1100
0
    installer["exportName"] = exportSet->GetName();
1101
0
    installer["exportTargets"] = this->DumpInstallerExportTargets(exportSet);
1102
0
    Json::Value paths = Json::arrayValue;
1103
0
    paths.append(
1104
0
      RelativeIfUnder(this->TopBuild, installExport->GetMainImportFile()));
1105
0
    installer["paths"] = std::move(paths);
1106
0
  } else if (auto* installScript =
1107
0
               dynamic_cast<cmInstallScriptGenerator*>(gen)) {
1108
0
    if (installScript->IsCode()) {
1109
0
      installer["type"] = "code";
1110
0
    } else {
1111
0
      installer["type"] = "script";
1112
0
      installer["scriptFile"] = RelativeIfUnder(
1113
0
        this->TopSource, installScript->GetScript(this->Config));
1114
0
    }
1115
0
  } else if (auto* installImportedRuntimeArtifacts =
1116
0
               dynamic_cast<cmInstallImportedRuntimeArtifactsGenerator*>(
1117
0
                 gen)) {
1118
0
    installer["type"] = "importedRuntimeArtifacts";
1119
0
    installer["destination"] =
1120
0
      installImportedRuntimeArtifacts->GetDestination(this->Config);
1121
0
    if (installImportedRuntimeArtifacts->GetOptional()) {
1122
0
      installer["isOptional"] = true;
1123
0
    }
1124
0
  } else if (auto* installRuntimeDependencySet =
1125
0
               dynamic_cast<cmInstallRuntimeDependencySetGenerator*>(gen)) {
1126
0
    installer["type"] = "runtimeDependencySet";
1127
0
    installer["destination"] =
1128
0
      installRuntimeDependencySet->GetDestination(this->Config);
1129
0
    std::string name(
1130
0
      installRuntimeDependencySet->GetRuntimeDependencySet()->GetName());
1131
0
    if (!name.empty()) {
1132
0
      installer["runtimeDependencySetName"] = name;
1133
0
    }
1134
0
    switch (installRuntimeDependencySet->GetDependencyType()) {
1135
0
      case cmInstallRuntimeDependencySetGenerator::DependencyType::Framework:
1136
0
        installer["runtimeDependencySetType"] = "framework";
1137
0
        break;
1138
0
      case cmInstallRuntimeDependencySetGenerator::DependencyType::Library:
1139
0
        installer["runtimeDependencySetType"] = "library";
1140
0
        break;
1141
0
    }
1142
0
  } else if (auto* installFileSet =
1143
0
               dynamic_cast<cmInstallFileSetGenerator*>(gen)) {
1144
0
    auto const* fileSet = installFileSet->GetFileSet();
1145
1146
    // No fileSet by that name exists for the associated target
1147
0
    if (!fileSet) {
1148
0
      return installer;
1149
0
    }
1150
1151
0
    installer["type"] = "fileSet";
1152
0
    installer["destination"] = installFileSet->GetDestination(this->Config);
1153
1154
0
    auto* target = installFileSet->GetTarget();
1155
1156
0
    cm::GenEx::Context context(target->LocalGenerator, this->Config);
1157
0
    auto dirs = fileSet->GetDirectories(context, target);
1158
0
    auto entries = fileSet->GetFiles(context, target);
1159
1160
0
    Json::Value files = Json::arrayValue;
1161
0
    for (auto const& it : entries.first) {
1162
0
      auto dir = it.first;
1163
0
      if (!dir.empty()) {
1164
0
        dir += '/';
1165
0
      }
1166
0
      for (auto const& file : it.second) {
1167
0
        files.append(this->DumpInstallerPath(
1168
0
          this->TopSource, file,
1169
0
          cmStrCat(dir, cmSystemTools::GetFilenameNameView(file))));
1170
0
      }
1171
0
    }
1172
0
    installer["paths"] = std::move(files);
1173
0
    installer["fileSetName"] = fileSet->GetName();
1174
0
    installer["fileSetType"] = fileSet->GetType();
1175
0
    installer["fileSetDirectories"] = Json::arrayValue;
1176
0
    for (auto const& dir : dirs.first) {
1177
0
      installer["fileSetDirectories"].append(
1178
0
        RelativeIfUnder(this->TopSource, dir));
1179
0
    }
1180
0
    installer["fileSetTarget"] = Json::objectValue;
1181
0
    installer["fileSetTarget"]["id"] = TargetId(target, this->TopBuild);
1182
0
    installer["fileSetTarget"]["index"] = this->TargetIndexMap[target];
1183
1184
0
    if (installFileSet->GetOptional()) {
1185
0
      installer["isOptional"] = true;
1186
0
    }
1187
0
  } else if (auto* cxxModuleBmi =
1188
0
               dynamic_cast<cmInstallCxxModuleBmiGenerator*>(gen)) {
1189
0
    installer["type"] = "cxxModuleBmi";
1190
0
    installer["destination"] = cxxModuleBmi->GetDestination(this->Config);
1191
1192
0
    auto const* target = cxxModuleBmi->GetTarget();
1193
0
    installer["cxxModuleBmiTarget"] = Json::objectValue;
1194
0
    installer["cxxModuleBmiTarget"]["id"] = TargetId(target, this->TopBuild);
1195
0
    installer["cxxModuleBmiTarget"]["index"] = this->TargetIndexMap[target];
1196
1197
    // FIXME: Parse FilePermissions.
1198
    // FIXME: Parse MessageLevel.
1199
0
    if (cxxModuleBmi->GetOptional()) {
1200
0
      installer["isOptional"] = true;
1201
0
    }
1202
0
  }
1203
1204
  // Add fields common to all install generators.
1205
0
  installer["component"] = gen->GetComponent();
1206
0
  if (gen->GetExcludeFromAll()) {
1207
0
    installer["isExcludeFromAll"] = true;
1208
0
  }
1209
1210
0
  if (gen->GetAllComponentsFlag()) {
1211
0
    installer["isForAllComponents"] = true;
1212
0
  }
1213
1214
0
  this->AddBacktrace(installer, gen->GetBacktrace());
1215
1216
0
  return installer;
1217
0
}
1218
1219
Json::Value DirectoryObject::DumpInstallerExportTargets(cmExportSet* exp)
1220
0
{
1221
0
  Json::Value targets = Json::arrayValue;
1222
0
  for (auto const& targetExport : exp->GetTargetExports()) {
1223
0
    Json::Value target = Json::objectValue;
1224
0
    target["id"] = TargetId(targetExport->Target, this->TopBuild);
1225
0
    target["index"] = this->TargetIndexMap[targetExport->Target];
1226
0
    targets.append(std::move(target)); // NOLINT(*)
1227
0
  }
1228
0
  return targets;
1229
0
}
1230
1231
Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
1232
                                               std::string const& fromPathIn,
1233
                                               std::string const& toPath)
1234
0
{
1235
0
  Json::Value installPath;
1236
1237
0
  std::string fromPath = RelativeIfUnder(top, fromPathIn);
1238
1239
  // If toPath is the last component of fromPath, use just fromPath.
1240
0
  if (toPath.find_first_of('/') == std::string::npos &&
1241
0
      cmHasSuffix(fromPath, toPath) &&
1242
0
      (fromPath.size() == toPath.size() ||
1243
0
       fromPath[fromPath.size() - toPath.size() - 1] == '/')) {
1244
0
    installPath = fromPath;
1245
0
  } else {
1246
0
    installPath = Json::objectValue;
1247
0
    installPath["from"] = fromPath;
1248
0
    installPath["to"] = toPath;
1249
0
  }
1250
1251
0
  return installPath;
1252
0
}
1253
1254
Target::Target(cmGeneratorTarget* gt, unsigned int versionMajor,
1255
               unsigned int versionMinor, std::string const& config)
1256
0
  : GT(gt)
1257
0
  , VersionMajor(versionMajor)
1258
0
  , VersionMinor(versionMinor)
1259
0
  , Config(config)
1260
0
  , TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
1261
0
  , TopBuild(
1262
0
      gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
1263
0
  , Backtraces(this->TopSource)
1264
0
{
1265
0
}
1266
1267
Json::Value Target::Dump()
1268
0
{
1269
0
  Json::Value target = Json::objectValue;
1270
1271
0
  cm::TargetType const type = this->GT->GetType();
1272
1273
0
  target["codemodelVersion"] =
1274
0
    cmFileAPI::BuildVersion(this->VersionMajor, this->VersionMinor);
1275
0
  target["name"] = this->GT->GetName();
1276
0
  target["type"] = cmState::GetTargetTypeName(type);
1277
0
  target["id"] = TargetId(this->GT, this->TopBuild);
1278
0
  if (this->GT->IsImported()) {
1279
0
    target["imported"] = true;
1280
0
    if (!this->GT->IsImportedGloballyVisible()) {
1281
0
      target["local"] = true;
1282
0
    }
1283
0
  }
1284
0
  if (this->GT->IsSymbolic()) {
1285
0
    target["symbolic"] = true;
1286
0
  }
1287
0
  if (!this->GT->IsInBuildSystem()) {
1288
0
    target["abstract"] = true;
1289
0
  }
1290
0
  target["paths"] = this->DumpPaths();
1291
0
  if (this->GT->Target->GetIsGeneratorProvided()) {
1292
0
    target["isGeneratorProvided"] = true;
1293
0
  }
1294
1295
0
  this->AddBacktrace(target, this->GT->GetBacktrace());
1296
1297
0
  if (this->GT->Target->GetHaveInstallRule()) {
1298
0
    target["install"] = this->DumpInstall();
1299
0
  }
1300
1301
0
  if (this->GT->HaveWellDefinedOutputFiles()) {
1302
0
    Json::Value artifacts = this->DumpArtifacts();
1303
0
    if (!artifacts.empty()) {
1304
0
      target["artifacts"] = std::move(artifacts);
1305
0
    }
1306
0
  }
1307
1308
0
  if (type == cm::TargetType::EXECUTABLE ||
1309
0
      type == cm::TargetType::SHARED_LIBRARY ||
1310
0
      type == cm::TargetType::MODULE_LIBRARY) {
1311
0
    target["nameOnDisk"] = this->GT->GetFullName(this->Config);
1312
0
    if (!this->GT->IsImported()) {
1313
0
      target["link"] = this->DumpLink();
1314
0
    }
1315
0
  } else if (type == cm::TargetType::STATIC_LIBRARY) {
1316
0
    target["nameOnDisk"] = this->GT->GetFullName(this->Config);
1317
0
    if (!this->GT->IsImported()) {
1318
0
      target["archive"] = this->DumpArchive();
1319
0
    }
1320
0
  }
1321
1322
0
  if (type == cm::TargetType::EXECUTABLE) {
1323
0
    Json::Value launchers = this->DumpLaunchers();
1324
0
    if (!launchers.empty()) {
1325
0
      target["launchers"] = std::move(launchers);
1326
0
    }
1327
0
  }
1328
1329
0
  if (!this->GT->IsImported()) {
1330
0
    Json::Value dependencies = this->DumpDependencies();
1331
0
    if (!dependencies.empty()) {
1332
0
      target["dependencies"] = dependencies;
1333
0
    }
1334
0
  }
1335
1336
0
  {
1337
0
    Json::Value linkLibraries =
1338
0
      this->DumpLinkImplementationLibraries(cmGeneratorTarget::UseTo::Link);
1339
0
    if (!linkLibraries.empty()) {
1340
0
      target["linkLibraries"] = std::move(linkLibraries);
1341
0
    }
1342
0
    Json::Value ifaceLinkLibraries =
1343
0
      this->DumpLinkInterfaceLibraries(cmGeneratorTarget::UseTo::Link);
1344
0
    if (!ifaceLinkLibraries.empty()) {
1345
0
      target["interfaceLinkLibraries"] = std::move(ifaceLinkLibraries);
1346
0
    }
1347
0
    Json::Value compileDependencies =
1348
0
      this->DumpLinkImplementationLibraries(cmGeneratorTarget::UseTo::Compile);
1349
0
    if (!compileDependencies.empty()) {
1350
0
      target["compileDependencies"] = std::move(compileDependencies);
1351
0
    }
1352
0
    Json::Value ifaceCompileDependencies =
1353
0
      this->DumpLinkInterfaceLibraries(cmGeneratorTarget::UseTo::Compile);
1354
0
    if (!ifaceCompileDependencies.empty()) {
1355
0
      target["interfaceCompileDependencies"] =
1356
0
        std::move(ifaceCompileDependencies);
1357
0
    }
1358
0
    Json::Value objectDependencies = this->DumpObjectDependencies();
1359
0
    if (!objectDependencies.empty()) {
1360
0
      target["objectDependencies"] = std::move(objectDependencies);
1361
0
    }
1362
0
    Json::Value orderDependencies = this->DumpOrderDependencies();
1363
0
    if (!orderDependencies.empty()) {
1364
0
      target["orderDependencies"] = std::move(orderDependencies);
1365
0
    }
1366
1367
0
    if (!this->GT->IsImported()) {
1368
0
      this->ProcessLanguages();
1369
0
    }
1370
1371
0
    auto fileSetInfo = this->DumpFileSets();
1372
1373
0
    if (!fileSetInfo.first.isNull()) {
1374
0
      target["fileSets"] = fileSetInfo.first;
1375
0
    }
1376
1377
    // Even though some types of targets can't have sources, we have to always
1378
    // output a sources array to preserve backward compatibility
1379
0
    target["sources"] = this->DumpSources(fileSetInfo.second);
1380
1381
0
    auto interfaceSources = this->DumpInterfaceSources(fileSetInfo.second);
1382
0
    if (!interfaceSources.empty()) {
1383
0
      target["interfaceSources"] = std::move(interfaceSources);
1384
0
    }
1385
1386
0
    auto interfaceIncludes = this->DumpInterfaceIncludes();
1387
0
    if (!interfaceIncludes.empty()) {
1388
0
      target["interfaceIncludes"] = std::move(interfaceIncludes);
1389
0
    }
1390
1391
0
    Json::Value folder = this->DumpFolder();
1392
0
    if (!folder.isNull()) {
1393
0
      target["folder"] = std::move(folder);
1394
0
    }
1395
1396
0
    if (!this->GT->IsImported()) {
1397
0
      Json::Value sourceGroups = this->DumpSourceGroups();
1398
0
      if (!sourceGroups.empty()) {
1399
0
        target["sourceGroups"] = std::move(sourceGroups);
1400
0
      }
1401
1402
0
      Json::Value compileGroups = this->DumpCompileGroups();
1403
0
      if (!compileGroups.empty()) {
1404
0
        target["compileGroups"] = std::move(compileGroups);
1405
0
      }
1406
0
    }
1407
0
  }
1408
1409
0
  target["backtraceGraph"] = this->Backtraces.Dump();
1410
1411
0
  if (!this->GT->IsImported()) {
1412
0
    Json::Value debugger = this->DumpDebugger();
1413
0
    if (!debugger.isNull()) {
1414
0
      target["debugger"] = std::move(debugger);
1415
0
    }
1416
0
  }
1417
1418
0
  return target;
1419
0
}
1420
1421
void Target::ProcessLanguages()
1422
0
{
1423
0
  std::set<std::string> languages;
1424
0
  this->GT->GetLanguages(languages, this->Config);
1425
0
  for (std::string const& lang : languages) {
1426
0
    this->ProcessLanguage(lang);
1427
0
  }
1428
0
}
1429
1430
void Target::ProcessLanguage(std::string const& lang)
1431
0
{
1432
0
  CompileData& cd = this->CompileDataMap[lang];
1433
0
  cd.Language = lang;
1434
0
  if (cmValue sysrootCompile =
1435
0
        this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
1436
0
    cd.Sysroot = *sysrootCompile;
1437
0
  } else if (cmValue sysroot =
1438
0
               this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
1439
0
    cd.Sysroot = *sysroot;
1440
0
  }
1441
0
  cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1442
0
  {
1443
    // FIXME: Add flags from end section of ExpandRuleVariable,
1444
    // which may need to be factored out.
1445
0
    std::vector<BT<std::string>> flags =
1446
0
      lg->GetTargetCompileFlags(this->GT, this->Config, lang);
1447
1448
0
    cd.Flags.reserve(flags.size());
1449
0
    for (const BT<std::string>& f : flags) {
1450
0
      cd.Flags.emplace_back(this->ToJBT(f));
1451
0
    }
1452
0
  }
1453
0
  std::set<BT<std::string>> defines =
1454
0
    lg->GetTargetDefines(this->GT, this->Config, lang);
1455
0
  cd.Defines.reserve(defines.size());
1456
0
  for (BT<std::string> const& d : defines) {
1457
0
    cd.Defines.emplace_back(this->ToJBT(d));
1458
0
  }
1459
0
  std::vector<BT<std::string>> includePathList =
1460
0
    lg->GetIncludeDirectories(this->GT, lang, this->Config);
1461
0
  for (BT<std::string> const& i : includePathList) {
1462
0
    if (this->GT->IsApple() && cmSystemTools::IsPathToFramework(i.Value)) {
1463
0
      cd.Frameworks.emplace_back(
1464
0
        this->ToJBT(i),
1465
0
        this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
1466
0
    } else {
1467
0
      cd.Includes.emplace_back(
1468
0
        this->ToJBT(i),
1469
0
        this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
1470
0
    }
1471
0
  }
1472
0
  std::vector<BT<std::string>> precompileHeaders =
1473
0
    this->GT->GetPrecompileHeaders(this->Config, lang);
1474
0
  for (BT<std::string> const& pch : precompileHeaders) {
1475
0
    cd.PrecompileHeaders.emplace_back(this->ToJBT(pch));
1476
0
  }
1477
0
  BTs<std::string> const* languageStandard =
1478
0
    this->GT->GetLanguageStandardProperty(lang, this->Config);
1479
0
  if (languageStandard) {
1480
0
    cd.LanguageStandard = this->ToJBTs(*languageStandard);
1481
0
  }
1482
0
}
1483
1484
Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup const* sg)
1485
0
{
1486
0
  auto i = this->SourceGroupsMap.find(sg);
1487
0
  if (i == this->SourceGroupsMap.end()) {
1488
0
    auto sgIndex = static_cast<Json::ArrayIndex>(this->SourceGroups.size());
1489
0
    i = this->SourceGroupsMap.emplace(sg, sgIndex).first;
1490
0
    SourceGroup g;
1491
0
    g.Name = sg->GetFullName();
1492
0
    this->SourceGroups.push_back(std::move(g));
1493
0
  }
1494
0
  return i->second;
1495
0
}
1496
1497
CompileData Target::BuildCompileData(cmSourceFile* sf)
1498
0
{
1499
0
  CompileData fd;
1500
1501
0
  fd.Language = this->GT->GetSourceFileLanguage(sf, this->Config);
1502
0
  if (fd.Language.empty()) {
1503
0
    return fd;
1504
0
  }
1505
1506
0
  cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1507
0
  cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT,
1508
0
                                                    fd.Language);
1509
1510
0
  cmGeneratorFileSet const* fileSet =
1511
0
    GT->GetFileSetForSource(this->Config, sf);
1512
1513
0
  std::string const COMPILE_FLAGS("COMPILE_FLAGS");
1514
0
  if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
1515
0
    std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
1516
0
    fd.Flags.emplace_back(std::move(flags), JBTIndex());
1517
0
  }
1518
0
  std::string const COMPILE_OPTIONS("COMPILE_OPTIONS");
1519
0
  for (BT<std::string> tmpOpt : sf->GetCompileOptions()) {
1520
0
    tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
1521
    // After generator evaluation we need to use the AppendCompileOptions
1522
    // method so we handle situations where backtrace entries have lists
1523
    // and properly escape flags.
1524
0
    std::string tmp;
1525
0
    lg->AppendCompileOptions(tmp, tmpOpt.Value);
1526
0
    BT<std::string> opt(tmp, tmpOpt.Backtrace);
1527
0
    fd.Flags.emplace_back(this->ToJBT(opt));
1528
0
  }
1529
  // File set compile options, if any
1530
0
  if (fileSet) {
1531
0
    for (BT<std::string> const& tmpOpt : fileSet->BelongsTo(this->GT)
1532
0
           ? fileSet->GetCompileOptions(this->Config, fd.Language)
1533
0
           : fileSet->GetInterfaceCompileOptions(this->Config, fd.Language)) {
1534
      // We need to use the AppendCompileOptions method so we handle situations
1535
      // where backtrace entries have list and properly escape flags.
1536
0
      std::string tmp;
1537
0
      lg->AppendCompileOptions(tmp, tmpOpt.Value);
1538
0
      BT<std::string> opt(tmp, tmpOpt.Backtrace);
1539
0
      fd.Flags.emplace_back(this->ToJBT(opt));
1540
0
    }
1541
0
  }
1542
1543
  // Add precompile headers compile options.
1544
0
  std::vector<std::string> pchArchs =
1545
0
    this->GT->GetPchArchs(this->Config, fd.Language);
1546
1547
0
  std::unordered_map<std::string, std::string> pchSources;
1548
0
  for (std::string const& arch : pchArchs) {
1549
0
    std::string const pchSource =
1550
0
      this->GT->GetPchSource(this->Config, fd.Language, arch);
1551
0
    if (!pchSource.empty()) {
1552
0
      pchSources.insert(std::make_pair(pchSource, arch));
1553
0
    }
1554
0
  }
1555
1556
0
  if (!pchSources.empty() &&
1557
0
      !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) ||
1558
0
        sf->GetProperty("SKIP_PRECOMPILE_HEADERS"))) {
1559
0
    std::string pchOptions;
1560
0
    auto pchIt = pchSources.find(sf->ResolveFullPath());
1561
0
    if (pchIt != pchSources.end()) {
1562
0
      pchOptions = this->GT->GetPchCreateCompileOptions(
1563
0
        this->Config, fd.Language, pchIt->second);
1564
0
    } else {
1565
0
      pchOptions =
1566
0
        this->GT->GetPchUseCompileOptions(this->Config, fd.Language);
1567
0
    }
1568
1569
0
    BT<std::string> tmpOpt(pchOptions);
1570
0
    tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
1571
1572
    // After generator evaluation we need to use the AppendCompileOptions
1573
    // method so we handle situations where backtrace entries have lists
1574
    // and properly escape flags.
1575
0
    std::string tmp;
1576
0
    lg->AppendCompileOptions(tmp, tmpOpt.Value);
1577
0
    BT<std::string> opt(tmp, tmpOpt.Backtrace);
1578
0
    fd.Flags.emplace_back(this->ToJBT(opt));
1579
0
  }
1580
1581
0
  std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
1582
  // Add include directories from file set properties.
1583
0
  if (fileSet) {
1584
0
    for (BT<std::string> const& tmpInclude : fileSet->BelongsTo(this->GT)
1585
0
           ? fileSet->GetIncludeDirectories(this->Config, fd.Language)
1586
0
           : fileSet->GetInterfaceIncludeDirectories(this->Config,
1587
0
                                                     fd.Language)) {
1588
      // We need to use the AppendIncludeDirectories method so we handle
1589
      // situations where backtrace entries have lists.
1590
0
      std::vector<std::string> tmp;
1591
0
      lg->AppendIncludeDirectories(tmp, tmpInclude.Value, *sf);
1592
0
      for (std::string& i : tmp) {
1593
0
        bool const isSystemInclude =
1594
0
          this->GT->IsSystemIncludeDirectory(i, this->Config, fd.Language);
1595
0
        BT<std::string> include(i, tmpInclude.Backtrace);
1596
0
        if (this->GT->IsApple() && cmSystemTools::IsPathToFramework(i)) {
1597
0
          fd.Frameworks.emplace_back(this->ToJBT(include), isSystemInclude);
1598
0
        } else {
1599
0
          fd.Includes.emplace_back(this->ToJBT(include), isSystemInclude);
1600
0
        }
1601
0
      }
1602
0
    }
1603
0
  }
1604
  // Add include directories from source file properties.
1605
0
  {
1606
0
    for (BT<std::string> tmpInclude : sf->GetIncludeDirectories()) {
1607
0
      tmpInclude.Value =
1608
0
        genexInterpreter.Evaluate(tmpInclude.Value, INCLUDE_DIRECTORIES);
1609
1610
      // After generator evaluation we need to use the AppendIncludeDirectories
1611
      // method so we handle situations where backtrace entries have lists.
1612
0
      std::vector<std::string> tmp;
1613
0
      lg->AppendIncludeDirectories(tmp, tmpInclude.Value, *sf);
1614
0
      for (std::string& i : tmp) {
1615
0
        bool const isSystemInclude =
1616
0
          this->GT->IsSystemIncludeDirectory(i, this->Config, fd.Language);
1617
0
        BT<std::string> include(i, tmpInclude.Backtrace);
1618
0
        if (this->GT->IsApple() && cmSystemTools::IsPathToFramework(i)) {
1619
0
          fd.Frameworks.emplace_back(this->ToJBT(include), isSystemInclude);
1620
0
        } else {
1621
0
          fd.Includes.emplace_back(this->ToJBT(include), isSystemInclude);
1622
0
        }
1623
0
      }
1624
0
    }
1625
0
  }
1626
1627
0
  std::string const COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
1628
0
  std::set<BT<std::string>> fileDefines;
1629
0
  for (BT<std::string> tmpDef : sf->GetCompileDefinitions()) {
1630
0
    tmpDef.Value =
1631
0
      genexInterpreter.Evaluate(tmpDef.Value, COMPILE_DEFINITIONS);
1632
1633
    // After generator evaluation we need to use the AppendDefines method
1634
    // so we handle situations where backtrace entries have lists.
1635
0
    std::set<std::string> tmp;
1636
0
    lg->AppendDefines(tmp, tmpDef.Value);
1637
0
    for (std::string const& i : tmp) {
1638
0
      BT<std::string> def(i, tmpDef.Backtrace);
1639
0
      fileDefines.insert(def);
1640
0
    }
1641
0
  }
1642
1643
0
  std::set<std::string> configFileDefines;
1644
0
  std::string const defPropName =
1645
0
    "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config);
1646
0
  if (cmValue config_defs = sf->GetProperty(defPropName)) {
1647
0
    lg->AppendDefines(
1648
0
      configFileDefines,
1649
0
      genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
1650
0
  }
1651
1652
0
  std::set<BT<std::string>> fileSetDefines;
1653
0
  if (fileSet) {
1654
0
    for (BT<std::string> const& tmpDef : fileSet->BelongsTo(this->GT)
1655
0
           ? fileSet->GetCompileDefinitions(this->Config, fd.Language)
1656
0
           : fileSet->GetInterfaceCompileDefinitions(this->Config,
1657
0
                                                     fd.Language)) {
1658
      // We need to use the AppendDefines method so we handle situations where
1659
      // backtrace entries have lists.
1660
0
      std::set<std::string> tmp;
1661
0
      lg->AppendDefines(tmp, tmpDef.Value);
1662
0
      for (std::string const& i : tmp) {
1663
0
        BT<std::string> def(i, tmpDef.Backtrace);
1664
0
        fileSetDefines.insert(def);
1665
0
      }
1666
0
    }
1667
0
  }
1668
1669
0
  fd.Defines.reserve(fileDefines.size() + configFileDefines.size() +
1670
0
                     fileSetDefines.size());
1671
1672
0
  for (BT<std::string> const& def : fileDefines) {
1673
0
    fd.Defines.emplace_back(this->ToJBT(def));
1674
0
  }
1675
1676
0
  for (std::string const& d : configFileDefines) {
1677
0
    fd.Defines.emplace_back(d, JBTIndex());
1678
0
  }
1679
1680
0
  for (BT<std::string> const& def : fileSetDefines) {
1681
0
    fd.Defines.emplace_back(this->ToJBT(def));
1682
0
  }
1683
1684
0
  return fd;
1685
0
}
1686
1687
CompileData Target::MergeCompileData(CompileData const& fd)
1688
0
{
1689
0
  CompileData cd;
1690
0
  cd.Language = fd.Language;
1691
0
  if (cd.Language.empty()) {
1692
0
    return cd;
1693
0
  }
1694
0
  CompileData const& td = this->CompileDataMap.at(cd.Language);
1695
1696
  // All compile groups share the sysroot of the target.
1697
0
  cd.Sysroot = td.Sysroot;
1698
1699
  // All compile groups share the precompile headers of the target.
1700
0
  cd.PrecompileHeaders = td.PrecompileHeaders;
1701
1702
  // All compile groups share the language standard of the target.
1703
0
  cd.LanguageStandard = td.LanguageStandard;
1704
1705
  // Use target-wide flags followed by source-specific flags.
1706
0
  cd.Flags.reserve(td.Flags.size() + fd.Flags.size());
1707
0
  cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end());
1708
0
  cd.Flags.insert(cd.Flags.end(), fd.Flags.begin(), fd.Flags.end());
1709
1710
  // Use source-specific includes followed by target-wide includes.
1711
0
  cd.Includes.reserve(fd.Includes.size() + td.Includes.size());
1712
0
  cd.Includes.insert(cd.Includes.end(), fd.Includes.begin(),
1713
0
                     fd.Includes.end());
1714
0
  cd.Includes.insert(cd.Includes.end(), td.Includes.begin(),
1715
0
                     td.Includes.end());
1716
1717
  // Use source-specific frameworks followed by target-wide frameworks.
1718
0
  cd.Frameworks.reserve(fd.Frameworks.size() + td.Frameworks.size());
1719
0
  cd.Frameworks.insert(cd.Frameworks.end(), fd.Frameworks.begin(),
1720
0
                       fd.Frameworks.end());
1721
0
  cd.Frameworks.insert(cd.Frameworks.end(), td.Frameworks.begin(),
1722
0
                       td.Frameworks.end());
1723
1724
  // Use target-wide defines followed by source-specific defines.
1725
0
  cd.Defines.reserve(td.Defines.size() + fd.Defines.size());
1726
0
  cd.Defines.insert(cd.Defines.end(), td.Defines.begin(), td.Defines.end());
1727
0
  cd.Defines.insert(cd.Defines.end(), fd.Defines.begin(), fd.Defines.end());
1728
1729
  // De-duplicate defines.
1730
0
  std::stable_sort(cd.Defines.begin(), cd.Defines.end(),
1731
0
                   JBT<std::string>::ValueLess);
1732
0
  auto end = std::unique(cd.Defines.begin(), cd.Defines.end(),
1733
0
                         JBT<std::string>::ValueEq);
1734
0
  cd.Defines.erase(end, cd.Defines.end());
1735
1736
0
  return cd;
1737
0
}
1738
1739
Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf,
1740
                                               Json::ArrayIndex si)
1741
0
{
1742
0
  CompileData compileData = this->BuildCompileData(sf);
1743
0
  auto i = this->CompileGroupMap.find(compileData);
1744
0
  if (i == this->CompileGroupMap.end()) {
1745
0
    Json::ArrayIndex cgIndex =
1746
0
      static_cast<Json::ArrayIndex>(this->CompileGroups.size());
1747
0
    i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first;
1748
0
    CompileGroup g;
1749
0
    g.Entry = i;
1750
0
    this->CompileGroups.push_back(std::move(g));
1751
0
  }
1752
0
  this->CompileGroups[i->second].SourceIndexes.append(si);
1753
0
  return i->second;
1754
0
}
1755
1756
void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt)
1757
0
{
1758
0
  if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
1759
0
    object["backtrace"] = backtrace.Index;
1760
0
  }
1761
0
}
1762
1763
void Target::AddBacktrace(Json::Value& object, JBTIndex bt)
1764
0
{
1765
0
  if (bt) {
1766
0
    object["backtrace"] = bt.Index;
1767
0
  }
1768
0
}
1769
1770
Json::Value Target::DumpPaths()
1771
0
{
1772
0
  Json::Value paths = Json::objectValue;
1773
0
  cmLocalGenerator* lg = this->GT->GetLocalGenerator();
1774
1775
0
  std::string const& sourceDir = lg->GetCurrentSourceDirectory();
1776
0
  paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
1777
1778
0
  std::string const& buildDir = lg->GetCurrentBinaryDirectory();
1779
0
  paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
1780
1781
0
  return paths;
1782
0
}
1783
1784
std::pair<Json::Value, Target::FileSetDatabase> Target::DumpFileSets()
1785
0
{
1786
0
  Json::Value fsJson = Json::nullValue;
1787
0
  FileSetDatabase fsdb;
1788
1789
  // We record the visibility of each file set for later use when dumping
1790
  // interface sources, which needs to map files to file set visibility
1791
  // with only an index available. Those indexes match this vector.
1792
0
  this->FileSetVisibilities.clear();
1793
0
  this->FileSetBacktraces.clear();
1794
1795
  // Build the fileset database.
1796
0
  auto const& fileSets = this->GT->GetAllFileSets();
1797
1798
0
  if (!fileSets.empty()) {
1799
0
    fsJson = Json::arrayValue;
1800
0
    size_t fsIndex = 0;
1801
0
    for (auto const* fs : fileSets) {
1802
0
      cm::GenEx::Context context(this->GT->LocalGenerator, this->Config);
1803
1804
0
      auto directories = fs->GetDirectories(context, this->GT);
1805
1806
0
      fsJson.append(this->DumpFileSet(fs, directories.first));
1807
0
      this->FileSetVisibilities.push_back(fs->GetVisibility());
1808
1809
0
      auto files_per_dirs = fs->GetFiles(context, this->GT);
1810
1811
0
      for (auto const& files_per_dir : files_per_dirs.first) {
1812
0
        auto const& dir = files_per_dir.first;
1813
0
        for (auto const& file : files_per_dir.second) {
1814
0
          std::string sf_path;
1815
0
          if (dir.empty() || cmSystemTools::FileIsFullPath(file)) {
1816
0
            sf_path = file;
1817
0
          } else {
1818
0
            sf_path = cmStrCat(dir, '/', file);
1819
0
          }
1820
0
          fsdb[sf_path].emplace_back(static_cast<Json::ArrayIndex>(fsIndex));
1821
0
        }
1822
0
      }
1823
1824
      // Collect backtraces from each original file set FILES entry so that
1825
      // source backtraces preserve line metadata and can include repeated
1826
      // additions from multiple file sets.
1827
0
      auto const& fileEntries = fs->GetFileEntries();
1828
0
      for (BT<std::string> const& fileEntry : fileEntries) {
1829
0
        cmGeneratorExpression ge(
1830
0
          *this->GT->GetLocalGenerator()->GetCMakeInstance(),
1831
0
          fileEntry.Backtrace);
1832
0
        for (std::string const& ex : cmList{ fileEntry.Value }) {
1833
0
          std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(ex);
1834
0
          std::map<std::string, std::vector<std::string>> filesForEntry;
1835
0
          fs->EvaluateFileEntry(directories.first, filesForEntry, cge, context,
1836
0
                                this->GT);
1837
0
          for (auto const& filesPerDir : filesForEntry) {
1838
0
            std::string const& dir = filesPerDir.first;
1839
0
            for (std::string const& file : filesPerDir.second) {
1840
0
              std::string sf_path;
1841
0
              if (dir.empty() || cmSystemTools::FileIsFullPath(file)) {
1842
0
                sf_path = file;
1843
0
              } else {
1844
0
                sf_path = cmStrCat(dir, '/', file);
1845
0
              }
1846
0
              this->FileSetBacktraces[sf_path].push_back(fileEntry.Backtrace);
1847
0
            }
1848
0
          }
1849
0
        }
1850
0
      }
1851
1852
0
      ++fsIndex;
1853
0
    }
1854
0
  }
1855
1856
0
  return std::make_pair(fsJson, fsdb);
1857
0
}
1858
1859
Json::Value Target::DumpFileSet(cmGeneratorFileSet const* fs,
1860
                                std::vector<std::string> const& directories)
1861
0
{
1862
0
  Json::Value fileSet = Json::objectValue;
1863
1864
0
  fileSet["name"] = fs->GetName();
1865
0
  fileSet["type"] = fs->GetType();
1866
0
  fileSet["visibility"] =
1867
0
    std::string(cm::FileSetMetadata::VisibilityToName(fs->GetVisibility()));
1868
1869
0
  Json::Value baseDirs = Json::arrayValue;
1870
0
  for (auto const& directory : directories) {
1871
0
    baseDirs.append(RelativeIfUnder(this->TopSource, directory));
1872
0
  }
1873
0
  fileSet["baseDirectories"] = baseDirs;
1874
1875
0
  return fileSet;
1876
0
}
1877
1878
Json::Value Target::DumpSources(FileSetDatabase const& fsdb)
1879
0
{
1880
0
  Json::Value sources = Json::arrayValue;
1881
0
  cmGeneratorTarget::KindedSources const& kinded =
1882
0
    this->GT->GetKindedSources(this->Config);
1883
0
  for (cmGeneratorTarget::SourceAndKind const& sk : kinded.Sources) {
1884
0
    sources.append(this->DumpSource(sk, sources.size(), fsdb));
1885
0
  }
1886
0
  return sources;
1887
0
}
1888
1889
Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
1890
                               Json::ArrayIndex si,
1891
                               FileSetDatabase const& fsdb)
1892
0
{
1893
0
  Json::Value source = Json::objectValue;
1894
1895
0
  cmSourceFile* sf = sk.Source.Value;
1896
0
  std::string const path = sf->ResolveFullPath();
1897
0
  source["path"] = RelativeIfUnder(this->TopSource, path);
1898
0
  if (sk.Source.Value->GetIsGenerated()) {
1899
0
    source["isGenerated"] = true;
1900
0
  }
1901
1902
0
  JBTIndex sourceBacktrace = this->Backtraces.Add(sk.Source.Backtrace);
1903
0
  JBTIndex primaryBacktrace = sourceBacktrace;
1904
0
  Json::Value backtraces = Json::arrayValue;
1905
0
  auto const fileSetBacktraces = this->FileSetBacktraces.find(path);
1906
0
  if (fileSetBacktraces != this->FileSetBacktraces.end() &&
1907
0
      !fileSetBacktraces->second.empty()) {
1908
0
    for (cmListFileBacktrace const& fsbt : fileSetBacktraces->second) {
1909
0
      if (JBTIndex bt = this->Backtraces.Add(fsbt)) {
1910
0
        if (!primaryBacktrace) {
1911
0
          primaryBacktrace = bt;
1912
0
        }
1913
0
        backtraces.append(bt.Index);
1914
0
      }
1915
0
    }
1916
0
  } else {
1917
0
    if (sourceBacktrace) {
1918
0
      backtraces.append(sourceBacktrace.Index);
1919
0
    }
1920
0
  }
1921
1922
0
  this->AddBacktrace(source, primaryBacktrace);
1923
1924
0
  if (!backtraces.empty()) {
1925
0
    source["backtraces"] = std::move(backtraces);
1926
0
  }
1927
1928
0
  auto fsit = fsdb.find(path);
1929
0
  if (fsit != fsdb.end()) {
1930
0
    source["fileSetIndex"] = fsit->second.back();
1931
0
    source["fileSetIndexes"] = Json::arrayValue;
1932
0
    for (Json::ArrayIndex const& fsIndex : fsit->second) {
1933
0
      source["fileSetIndexes"].append(fsIndex);
1934
0
    }
1935
0
  }
1936
1937
0
  if (cmSourceGroup const* sg = this->GT->LocalGenerator->FindSourceGroup(
1938
0
        this->GT, sf, this->Config)) {
1939
0
    Json::ArrayIndex const groupIndex = this->AddSourceGroup(sg);
1940
0
    source["sourceGroupIndex"] = groupIndex;
1941
0
    this->SourceGroups[groupIndex].SourceIndexes.append(si);
1942
0
  }
1943
1944
0
  switch (sk.Kind) {
1945
0
    case cmGeneratorTarget::SourceKindCxxModuleSource:
1946
0
    case cmGeneratorTarget::SourceKindObjectSource: {
1947
0
      source["compileGroupIndex"] =
1948
0
        this->AddSourceCompileGroup(sk.Source.Value, si);
1949
0
    } break;
1950
0
    case cmGeneratorTarget::SourceKindAppManifest:
1951
0
    case cmGeneratorTarget::SourceKindCertificate:
1952
0
    case cmGeneratorTarget::SourceKindCustomCommand:
1953
0
    case cmGeneratorTarget::SourceKindExternalObject:
1954
0
    case cmGeneratorTarget::SourceKindExtra:
1955
0
    case cmGeneratorTarget::SourceKindHeader:
1956
0
    case cmGeneratorTarget::SourceKindIDL:
1957
0
    case cmGeneratorTarget::SourceKindManifest:
1958
0
    case cmGeneratorTarget::SourceKindModuleDefinition:
1959
0
    case cmGeneratorTarget::SourceKindResx:
1960
0
    case cmGeneratorTarget::SourceKindXaml:
1961
0
    case cmGeneratorTarget::SourceKindUnityBatched:
1962
0
    case cmGeneratorTarget::SourceKindRustMainCrateRoot:
1963
0
      break;
1964
0
  }
1965
1966
0
  return source;
1967
0
}
1968
1969
Json::Value Target::DumpInterfaceSources(FileSetDatabase const& fsdb)
1970
0
{
1971
0
  Json::Value interfaceSources = Json::arrayValue;
1972
0
  auto dumpFile = [this, &interfaceSources, &fsdb](std::string const& file) {
1973
0
    std::string path = file;
1974
0
    if (!cmSystemTools::FileIsFullPath(path)) {
1975
0
      path = cmStrCat(
1976
0
        this->GT->GetLocalGenerator()->GetCurrentSourceDirectory(), '/', file);
1977
0
    }
1978
0
    path = cmSystemTools::CollapseFullPath(path);
1979
1980
0
    interfaceSources.append(
1981
0
      this->DumpInterfaceSource(path, interfaceSources.size(), fsdb));
1982
0
  };
1983
1984
0
  cmValue prop = this->GT->GetProperty("INTERFACE_SOURCES");
1985
0
  if (prop) {
1986
0
    cmList files{ cmGeneratorExpression::Evaluate(
1987
0
      *prop, this->GT->GetLocalGenerator(), this->Config, this->GT) };
1988
1989
0
    for (std::string const& file : files) {
1990
0
      dumpFile(file);
1991
0
    }
1992
0
  }
1993
1994
0
  for (auto const& fsIter : fsdb) {
1995
0
    Json::ArrayIndex const index = fsIter.second.back();
1996
    // FileSetVisibilities was populated by DumpFileSets() and will always
1997
    // have the same size as the file sets array that index is indexing into
1998
0
    if (this->FileSetVisibilities[index] !=
1999
0
        cm::FileSetMetadata::Visibility::Private) {
2000
0
      dumpFile(fsIter.first);
2001
0
    }
2002
0
  }
2003
2004
0
  return interfaceSources;
2005
0
}
2006
2007
Json::Value Target::DumpInterfaceIncludes()
2008
0
{
2009
0
  Json::Value interfaceIncludes = Json::arrayValue;
2010
2011
0
  cmValue prop = this->GT->GetProperty("INTERFACE_INCLUDE_DIRECTORIES");
2012
0
  cmValue systemIncludesProp =
2013
0
    this->GT->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES");
2014
0
  if (!prop) {
2015
0
    return interfaceIncludes;
2016
0
  }
2017
2018
0
  struct InterfaceInclude
2019
0
  {
2020
0
    std::string Path;
2021
0
    bool IsSystem;
2022
0
    std::set<std::string> Languages;
2023
0
  };
2024
2025
  // Get enabled languages
2026
0
  std::vector<std::string> languages =
2027
0
    this->GT->Makefile->GetState()->GetEnabledLanguages();
2028
0
  languages.erase(std::remove(languages.begin(), languages.end(), "NONE"),
2029
0
                  languages.end());
2030
0
  if (languages.empty()) {
2031
0
    languages.emplace_back();
2032
0
  }
2033
2034
  // Evaluate an INCLUDE_DIRECTORIES property with language context
2035
0
  auto evaluateIncludes =
2036
0
    [this](cmCompiledGeneratorExpression const& expression,
2037
0
           cm::GenEx::Context const& context) {
2038
0
      cmGeneratorExpressionDAGChecker dagChecker{ this->GT,
2039
0
                                                  "INCLUDE_DIRECTORIES",
2040
0
                                                  nullptr, nullptr, context };
2041
0
      return cmList{ expression.Evaluate(context, &dagChecker, this->GT,
2042
0
                                         this->GT) };
2043
0
    };
2044
2045
0
  cmGeneratorExpression ge(*this->GT->Makefile->GetCMakeInstance());
2046
0
  auto includesExpression = ge.Parse(*prop);
2047
0
  auto systemIncludesExpression =
2048
0
    systemIncludesProp ? ge.Parse(*systemIncludesProp) : nullptr;
2049
0
  bool const targetTreatsOwnIncludesAsSystem =
2050
0
    this->GT->GetPropertyAsBool("SYSTEM") &&
2051
0
    (!this->GT->IsImported() ||
2052
0
     !this->GT->GetPropertyAsBool("IMPORTED_NO_SYSTEM"));
2053
0
  std::vector<InterfaceInclude> includes;
2054
2055
  // Get includes for each enabled language and merge results
2056
0
  for (std::string const& language : languages) {
2057
0
    cm::GenEx::Context context(this->GT->GetLocalGenerator(), this->Config,
2058
0
                               language);
2059
    // Get per-language system include set
2060
0
    std::set<std::string> systemIncludes;
2061
0
    if (systemIncludesExpression) {
2062
0
      for (std::string include :
2063
0
           evaluateIncludes(*systemIncludesExpression, context)) {
2064
0
        cmSystemTools::ConvertToUnixSlashes(include);
2065
0
        systemIncludes.emplace(std::move(include));
2066
0
      }
2067
0
    }
2068
2069
    // Get per-language includes
2070
0
    for (std::string include :
2071
0
         evaluateIncludes(*includesExpression, context)) {
2072
0
      cmSystemTools::ConvertToUnixSlashes(include);
2073
0
      bool const isSystem = targetTreatsOwnIncludesAsSystem ||
2074
0
        systemIncludes.find(include) != systemIncludes.end();
2075
0
      auto entry = std::find_if(
2076
0
        includes.begin(), includes.end(),
2077
0
        [&include, isSystem](InterfaceInclude const& candidate) {
2078
0
          return candidate.Path == include && candidate.IsSystem == isSystem;
2079
0
        });
2080
0
      if (entry == includes.end()) {
2081
0
        entry = includes.insert(includes.end(),
2082
0
                                { std::move(include), isSystem, {} });
2083
0
      }
2084
0
      entry->Languages.insert(language);
2085
0
    }
2086
0
  }
2087
2088
  // Build JSON from InterfaceInclude vector
2089
0
  for (InterfaceInclude const& include : includes) {
2090
0
    Json::Value entry =
2091
0
      this->DumpInclude({ JBT<std::string>(include.Path), include.IsSystem });
2092
0
    if (include.Languages.size() != languages.size()) {
2093
0
      Json::Value entryLanguages = Json::arrayValue;
2094
0
      for (std::string const& language : include.Languages) {
2095
0
        entryLanguages.append(language);
2096
0
      }
2097
0
      entry["languages"] = std::move(entryLanguages);
2098
0
    }
2099
0
    interfaceIncludes.append(std::move(entry));
2100
0
  }
2101
2102
0
  return interfaceIncludes;
2103
0
}
2104
2105
Json::Value Target::DumpInterfaceSource(std::string path, Json::ArrayIndex si,
2106
                                        FileSetDatabase const& fsdb)
2107
0
{
2108
0
  Json::Value source = Json::objectValue;
2109
2110
0
  cmSourceFile* sf = this->GT->Makefile->GetOrCreateSource(path);
2111
0
  path = sf->ResolveFullPath();
2112
0
  source["path"] = RelativeIfUnder(this->TopSource, path);
2113
0
  if (sf->GetIsGenerated()) {
2114
0
    source["isGenerated"] = true;
2115
0
  }
2116
2117
0
  auto fsit = fsdb.find(path);
2118
0
  if (fsit != fsdb.end()) {
2119
0
    source["fileSetIndex"] = fsit->second.back();
2120
0
    source["fileSetIndexes"] = Json::arrayValue;
2121
0
    for (Json::ArrayIndex const& fsIndex : fsit->second) {
2122
0
      source["fileSetIndexes"].append(fsIndex);
2123
0
    }
2124
0
  }
2125
2126
0
  if (cmSourceGroup const* sg = this->GT->LocalGenerator->FindSourceGroup(
2127
0
        this->GT, sf, this->Config)) {
2128
0
    Json::ArrayIndex const groupIndex = this->AddSourceGroup(sg);
2129
0
    source["sourceGroupIndex"] = groupIndex;
2130
0
    this->SourceGroups[groupIndex].InterfaceSourceIndexes.append(si);
2131
0
  }
2132
2133
0
  return source;
2134
0
}
2135
2136
Json::Value Target::DumpCompileData(CompileData const& cd)
2137
0
{
2138
0
  Json::Value result = Json::objectValue;
2139
2140
0
  if (!cd.Language.empty()) {
2141
0
    result["language"] = cd.Language;
2142
0
  }
2143
0
  if (!cd.Sysroot.empty()) {
2144
0
    result["sysroot"] = this->DumpSysroot(cd.Sysroot);
2145
0
  }
2146
0
  if (!cd.Flags.empty()) {
2147
0
    result["compileCommandFragments"] = this->DumpCommandFragments(cd.Flags);
2148
0
  }
2149
0
  if (!cd.Includes.empty()) {
2150
0
    Json::Value includes = Json::arrayValue;
2151
0
    for (auto const& i : cd.Includes) {
2152
0
      includes.append(this->DumpInclude(i));
2153
0
    }
2154
0
    result["includes"] = includes;
2155
0
  }
2156
0
  if (!cd.Frameworks.empty()) {
2157
0
    Json::Value frameworks = Json::arrayValue;
2158
0
    for (auto const& i : cd.Frameworks) {
2159
0
      frameworks.append(this->DumpFramework(i));
2160
0
    }
2161
0
    result["frameworks"] = frameworks;
2162
0
  }
2163
0
  if (!cd.Defines.empty()) {
2164
0
    Json::Value defines = Json::arrayValue;
2165
0
    for (JBT<std::string> const& d : cd.Defines) {
2166
0
      defines.append(this->DumpDefine(d));
2167
0
    }
2168
0
    result["defines"] = std::move(defines);
2169
0
  }
2170
0
  if (!cd.PrecompileHeaders.empty()) {
2171
0
    Json::Value precompileHeaders = Json::arrayValue;
2172
0
    for (JBT<std::string> const& pch : cd.PrecompileHeaders) {
2173
0
      precompileHeaders.append(this->DumpPrecompileHeader(pch));
2174
0
    }
2175
0
    result["precompileHeaders"] = std::move(precompileHeaders);
2176
0
  }
2177
0
  if (!cd.LanguageStandard.Value.empty()) {
2178
0
    result["languageStandard"] =
2179
0
      this->DumpLanguageStandard(cd.LanguageStandard);
2180
0
  }
2181
2182
0
  return result;
2183
0
}
2184
2185
Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc)
2186
0
{
2187
0
  Json::Value include = Json::objectValue;
2188
0
  include["path"] = inc.Path.Value;
2189
0
  if (inc.IsSystem) {
2190
0
    include["isSystem"] = true;
2191
0
  }
2192
0
  this->AddBacktrace(include, inc.Path.Backtrace);
2193
0
  return include;
2194
0
}
2195
2196
Json::Value Target::DumpFramework(CompileData::IncludeEntry const& fw)
2197
0
{
2198
  // for now, idem as include
2199
0
  return this->DumpInclude(fw);
2200
0
}
2201
2202
Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header)
2203
0
{
2204
0
  Json::Value precompileHeader = Json::objectValue;
2205
0
  precompileHeader["header"] = header.Value;
2206
0
  this->AddBacktrace(precompileHeader, header.Backtrace);
2207
0
  return precompileHeader;
2208
0
}
2209
2210
Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard)
2211
0
{
2212
0
  Json::Value languageStandard = Json::objectValue;
2213
0
  languageStandard["standard"] = standard.Value;
2214
0
  if (!standard.Backtraces.empty()) {
2215
0
    Json::Value backtraces = Json::arrayValue;
2216
0
    for (JBTIndex backtrace : standard.Backtraces) {
2217
0
      backtraces.append(backtrace.Index);
2218
0
    }
2219
0
    languageStandard["backtraces"] = backtraces;
2220
0
  }
2221
0
  return languageStandard;
2222
0
}
2223
2224
Json::Value Target::DumpDefine(JBT<std::string> const& def)
2225
0
{
2226
0
  Json::Value define = Json::objectValue;
2227
0
  define["define"] = def.Value;
2228
0
  this->AddBacktrace(define, def.Backtrace);
2229
0
  return define;
2230
0
}
2231
2232
Json::Value Target::DumpSourceGroups()
2233
0
{
2234
0
  Json::Value sourceGroups = Json::arrayValue;
2235
0
  for (auto& sg : this->SourceGroups) {
2236
0
    sourceGroups.append(this->DumpSourceGroup(sg));
2237
0
  }
2238
0
  return sourceGroups;
2239
0
}
2240
2241
Json::Value Target::DumpSourceGroup(SourceGroup& sg)
2242
0
{
2243
0
  Json::Value group = Json::objectValue;
2244
0
  group["name"] = sg.Name;
2245
0
  group["sourceIndexes"] = std::move(sg.SourceIndexes);
2246
0
  if (!sg.InterfaceSourceIndexes.empty()) {
2247
0
    group["interfaceSourceIndexes"] = std::move(sg.InterfaceSourceIndexes);
2248
0
  }
2249
0
  return group;
2250
0
}
2251
2252
Json::Value Target::DumpCompileGroups()
2253
0
{
2254
0
  Json::Value compileGroups = Json::arrayValue;
2255
0
  for (auto& cg : this->CompileGroups) {
2256
0
    compileGroups.append(this->DumpCompileGroup(cg));
2257
0
  }
2258
0
  return compileGroups;
2259
0
}
2260
2261
Json::Value Target::DumpCompileGroup(CompileGroup& cg)
2262
0
{
2263
0
  Json::Value group =
2264
0
    this->DumpCompileData(this->MergeCompileData(cg.Entry->first));
2265
0
  group["sourceIndexes"] = std::move(cg.SourceIndexes);
2266
0
  return group;
2267
0
}
2268
2269
Json::Value Target::DumpSysroot(std::string const& path)
2270
0
{
2271
0
  Json::Value sysroot = Json::objectValue;
2272
0
  sysroot["path"] = path;
2273
0
  return sysroot;
2274
0
}
2275
2276
Json::Value Target::DumpInstall()
2277
0
{
2278
0
  Json::Value install = Json::objectValue;
2279
0
  install["prefix"] = this->DumpInstallPrefix();
2280
0
  install["destinations"] = this->DumpInstallDestinations();
2281
0
  return install;
2282
0
}
2283
2284
Json::Value Target::DumpInstallPrefix()
2285
0
{
2286
0
  Json::Value prefix = Json::objectValue;
2287
0
  std::string p =
2288
0
    this->GT->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2289
0
  cmSystemTools::ConvertToUnixSlashes(p);
2290
0
  prefix["path"] = p;
2291
0
  return prefix;
2292
0
}
2293
2294
Json::Value Target::DumpInstallDestinations()
2295
0
{
2296
0
  Json::Value destinations = Json::arrayValue;
2297
0
  auto installGens = this->GT->Target->GetInstallGenerators();
2298
0
  for (auto* itGen : installGens) {
2299
0
    destinations.append(this->DumpInstallDestination(itGen));
2300
0
  }
2301
0
  return destinations;
2302
0
}
2303
2304
Json::Value Target::DumpInstallDestination(cmInstallTargetGenerator* itGen)
2305
0
{
2306
0
  Json::Value destination = Json::objectValue;
2307
0
  destination["path"] = itGen->GetDestination(this->Config);
2308
0
  this->AddBacktrace(destination, itGen->GetBacktrace());
2309
0
  return destination;
2310
0
}
2311
2312
Json::Value Target::DumpArtifacts()
2313
0
{
2314
0
  Json::Value artifacts = Json::arrayValue;
2315
2316
  // Object libraries have only object files as artifacts.
2317
0
  if (this->GT->GetType() == cm::TargetType::OBJECT_LIBRARY) {
2318
0
    if (!this->GT->Target->HasKnownObjectFileLocation(nullptr)) {
2319
0
      return artifacts;
2320
0
    }
2321
0
    std::vector<cmSourceFile const*> objectSources;
2322
0
    this->GT->GetObjectSources(objectSources, this->Config);
2323
0
    std::string const obj_dir = this->GT->GetObjectDirectory(this->Config);
2324
0
    for (cmSourceFile const* sf : objectSources) {
2325
0
      std::string const& obj = this->GT->GetObjectName(sf);
2326
0
      Json::Value artifact = Json::objectValue;
2327
0
      artifact["path"] = RelativeIfUnder(this->TopBuild, obj_dir + obj);
2328
0
      artifacts.append(std::move(artifact)); // NOLINT(*)
2329
0
    }
2330
0
    return artifacts;
2331
0
  }
2332
2333
  // Other target types always have a "main" artifact.
2334
0
  {
2335
0
    Json::Value artifact = Json::objectValue;
2336
0
    artifact["path"] =
2337
0
      RelativeIfUnder(this->TopBuild,
2338
0
                      this->GT->GetFullPath(
2339
0
                        this->Config, cmStateEnums::RuntimeBinaryArtifact));
2340
0
    artifacts.append(std::move(artifact)); // NOLINT(*)
2341
0
  }
2342
2343
  // Add Windows-specific artifacts produced by the linker.
2344
  // NOTE: HasImportLibrary() only checks if the target SHOULD have an import
2345
  //       library, not whether it has one set.
2346
0
  if (this->GT->HasImportLibrary(this->Config)) {
2347
0
    std::string fullPath;
2348
0
    if (this->GT->IsImported()) {
2349
      // This imported target might not be well-formed. For Windows, it should
2350
      // have its IMPORTED_IMPLIB property set, and CMP0111's NEW behavior is
2351
      // intended to catch and report that. But if nothing uses the imported
2352
      // target, there won't have been any opportunity to detect that property
2353
      // being missing before here. Therefore, we tell ImportedGetFullPath()
2354
      // not to raise that CMP0111 error if it sees the problem. We don't want
2355
      // to trigger an error for a target that nothing uses, as that would be a
2356
      // regression compared to CMake 4.1 and earlier behavior.
2357
0
      fullPath = this->GT->Target->ImportedGetFullPath(
2358
0
        this->Config, cmStateEnums::ImportLibraryArtifact,
2359
0
        cmTarget::ImportArtifactMissingOk::Yes);
2360
0
      if (cmHasLiteralSuffix(fullPath, "-NOTFOUND")) {
2361
0
        fullPath.clear();
2362
0
      }
2363
0
    } else {
2364
0
      fullPath = this->GT->NormalGetFullPath(
2365
0
        this->Config, cmStateEnums::ImportLibraryArtifact, false);
2366
0
    }
2367
0
    if (!fullPath.empty()) {
2368
0
      Json::Value artifact = Json::objectValue;
2369
0
      artifact["path"] = RelativeIfUnder(this->TopBuild, fullPath);
2370
0
      artifacts.append(std::move(artifact)); // NOLINT(*)
2371
0
    }
2372
0
  }
2373
0
  if (this->GT->IsDLLPlatform() &&
2374
0
      this->GT->GetType() != cm::TargetType::STATIC_LIBRARY) {
2375
0
    cmGeneratorTarget::OutputInfo const* output =
2376
0
      this->GT->GetOutputInfo(this->Config);
2377
0
    if (output && !output->PdbDir.empty()) {
2378
0
      Json::Value artifact = Json::objectValue;
2379
0
      artifact["path"] = RelativeIfUnder(
2380
0
        this->TopBuild,
2381
0
        cmStrCat(output->PdbDir, '/', this->GT->GetPDBName(this->Config)));
2382
0
      artifacts.append(std::move(artifact)); // NOLINT(*)
2383
0
    }
2384
0
  }
2385
0
  return artifacts;
2386
0
}
2387
2388
Json::Value Target::DumpLink()
2389
0
{
2390
0
  Json::Value link = Json::objectValue;
2391
0
  std::string lang = this->GT->GetLinkerLanguage(this->Config);
2392
0
  link["language"] = lang;
2393
0
  {
2394
0
    Json::Value commandFragments = this->DumpLinkCommandFragments();
2395
0
    if (!commandFragments.empty()) {
2396
0
      link["commandFragments"] = std::move(commandFragments);
2397
0
    }
2398
0
  }
2399
0
  if (cmValue sysrootLink =
2400
0
        this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
2401
0
    link["sysroot"] = this->DumpSysroot(*sysrootLink);
2402
0
  } else if (cmValue sysroot =
2403
0
               this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
2404
0
    link["sysroot"] = this->DumpSysroot(*sysroot);
2405
0
  }
2406
0
  if (this->GT->IsIPOEnabled(lang, this->Config)) {
2407
0
    link["lto"] = true;
2408
0
  }
2409
0
  return link;
2410
0
}
2411
2412
Json::Value Target::DumpArchive()
2413
0
{
2414
0
  Json::Value archive = Json::objectValue;
2415
0
  {
2416
    // The "link" fragments not relevant to static libraries are empty.
2417
0
    Json::Value commandFragments = this->DumpLinkCommandFragments();
2418
0
    if (!commandFragments.empty()) {
2419
0
      archive["commandFragments"] = std::move(commandFragments);
2420
0
    }
2421
0
  }
2422
0
  std::string lang = this->GT->GetLinkerLanguage(this->Config);
2423
0
  if (this->GT->IsIPOEnabled(lang, this->Config)) {
2424
0
    archive["lto"] = true;
2425
0
  }
2426
0
  return archive;
2427
0
}
2428
2429
Json::Value Target::DumpLinkCommandFragments()
2430
0
{
2431
0
  Json::Value linkFragments = Json::arrayValue;
2432
2433
0
  std::string linkLanguageFlags;
2434
0
  std::vector<BT<std::string>> linkFlags;
2435
0
  std::string frameworkPath;
2436
0
  std::vector<BT<std::string>> linkPath;
2437
0
  std::vector<BT<std::string>> linkLibs;
2438
0
  cmLocalGenerator* lg = this->GT->GetLocalGenerator();
2439
0
  cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
2440
0
  std::unique_ptr<cmLinkLineComputer> linkLineComputer =
2441
0
    gg->CreateLinkLineComputer(lg, lg->GetStateSnapshot().GetDirectory());
2442
0
  lg->GetTargetFlags(linkLineComputer.get(), this->Config, linkLibs,
2443
0
                     linkLanguageFlags, linkFlags, frameworkPath, linkPath,
2444
0
                     this->GT);
2445
0
  linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
2446
0
  frameworkPath = cmTrimWhitespace(frameworkPath);
2447
2448
0
  if (!linkLanguageFlags.empty()) {
2449
0
    linkFragments.append(
2450
0
      this->DumpCommandFragment(std::move(linkLanguageFlags), "flags"));
2451
0
  }
2452
2453
0
  if (!linkFlags.empty()) {
2454
0
    for (BT<std::string> frag : linkFlags) {
2455
0
      frag.Value = cmTrimWhitespace(frag.Value);
2456
0
      linkFragments.append(
2457
0
        this->DumpCommandFragment(this->ToJBT(frag), "flags"));
2458
0
    }
2459
0
  }
2460
2461
0
  if (!frameworkPath.empty()) {
2462
0
    linkFragments.append(
2463
0
      this->DumpCommandFragment(std::move(frameworkPath), "frameworkPath"));
2464
0
  }
2465
2466
0
  if (!linkPath.empty()) {
2467
0
    for (BT<std::string> frag : linkPath) {
2468
0
      frag.Value = cmTrimWhitespace(frag.Value);
2469
0
      linkFragments.append(
2470
0
        this->DumpCommandFragment(this->ToJBT(frag), "libraryPath"));
2471
0
    }
2472
0
  }
2473
2474
0
  if (!linkLibs.empty()) {
2475
0
    for (BT<std::string> frag : linkLibs) {
2476
0
      frag.Value = cmTrimWhitespace(frag.Value);
2477
0
      linkFragments.append(
2478
0
        this->DumpCommandFragment(this->ToJBT(frag), "libraries"));
2479
0
    }
2480
0
  }
2481
2482
0
  return linkFragments;
2483
0
}
2484
2485
Json::Value Target::DumpCommandFragments(
2486
  std::vector<JBT<std::string>> const& frags)
2487
0
{
2488
0
  Json::Value commandFragments = Json::arrayValue;
2489
0
  for (JBT<std::string> const& f : frags) {
2490
0
    commandFragments.append(this->DumpCommandFragment(f));
2491
0
  }
2492
0
  return commandFragments;
2493
0
}
2494
2495
Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag,
2496
                                        std::string const& role)
2497
0
{
2498
0
  Json::Value fragment = Json::objectValue;
2499
0
  fragment["fragment"] = frag.Value;
2500
0
  if (!role.empty()) {
2501
0
    fragment["role"] = role;
2502
0
  }
2503
0
  this->AddBacktrace(fragment, frag.Backtrace);
2504
0
  return fragment;
2505
0
}
2506
2507
Json::Value Target::DumpDependencies()
2508
0
{
2509
0
  Json::Value dependencies = Json::arrayValue;
2510
0
  cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
2511
0
  for (cmTargetDepend const& td : gg->GetTargetDirectDepends(this->GT)) {
2512
0
    dependencies.append(this->DumpDependency(td));
2513
0
  }
2514
0
  return dependencies;
2515
0
}
2516
2517
Json::Value Target::DumpDependency(cmTargetDepend const& td)
2518
0
{
2519
0
  Json::Value dependency = Json::objectValue;
2520
0
  dependency["id"] = TargetId(td, this->TopBuild);
2521
0
  this->AddBacktrace(dependency, td.GetBacktrace());
2522
0
  return dependency;
2523
0
}
2524
2525
Json::Value Target::DumpLinkItem(cmLinkItem const& linkItem)
2526
0
{
2527
0
  Json::Value itemJson = Json::objectValue;
2528
0
  if (linkItem.Target) {
2529
0
    itemJson["id"] = TargetId(linkItem.Target, this->TopBuild);
2530
0
  } else {
2531
0
    itemJson["fragment"] = linkItem.AsStr();
2532
0
  }
2533
0
  if (linkItem.InterfaceDirectFrom) {
2534
0
    Json::Value jsonDirectFrom = Json::objectValue;
2535
0
    jsonDirectFrom["id"] =
2536
0
      TargetId(linkItem.InterfaceDirectFrom, this->TopBuild);
2537
0
    itemJson["fromDependency"] = jsonDirectFrom;
2538
0
  }
2539
0
  this->AddBacktrace(itemJson, linkItem.Backtrace);
2540
0
  return itemJson;
2541
0
}
2542
2543
Json::Value Target::DumpLinkImplementationLibraries(
2544
  cmGeneratorTarget::UseTo usage)
2545
0
{
2546
0
  Json::Value jsonLibs = Json::arrayValue;
2547
2548
0
  cmLinkImplementationLibraries const* implLibs =
2549
0
    this->GT->GetLinkImplementationLibraries(this->Config, usage);
2550
0
  if (implLibs) {
2551
0
    for (cmLinkItem const& linkItem : implLibs->Libraries) {
2552
      // Non-target compile items are never used, so we drop them here too
2553
0
      if (usage == cmGeneratorTarget::UseTo::Link || linkItem.Target) {
2554
0
        jsonLibs.append(this->DumpLinkItem(linkItem));
2555
0
      }
2556
0
    }
2557
0
  }
2558
0
  return jsonLibs;
2559
0
}
2560
2561
Json::Value Target::DumpLinkInterfaceLibraries(cmGeneratorTarget::UseTo usage)
2562
0
{
2563
0
  Json::Value jsonLibs = Json::arrayValue;
2564
2565
0
  cmLinkInterfaceLibraries const* ifaceLibs =
2566
0
    this->GT->GetLinkInterfaceLibraries(this->Config, this->GT, usage);
2567
0
  if (ifaceLibs) {
2568
0
    for (cmLinkItem const& linkItem : ifaceLibs->Libraries) {
2569
      // Non-target compile items are never used, so we drop them here too
2570
0
      if (usage == cmGeneratorTarget::UseTo::Link || linkItem.Target) {
2571
0
        jsonLibs.append(this->DumpLinkItem(linkItem));
2572
0
      }
2573
0
    }
2574
0
  }
2575
0
  return jsonLibs;
2576
0
}
2577
2578
Json::Value Target::DumpObjectDependencies()
2579
0
{
2580
  // Object dependencies are a special case. They cannot be config-specific
2581
  // because they are obtained by matching the pattern $<TARGET_OBJECTS:xxx>
2582
  // against the SOURCES property, and the matcher rejects any cases where
2583
  // "xxx" contains a generator expression. We can't use
2584
  // GetSourceObjectLibraries() either because that also returns object
2585
  // libraries added via LINK_LIBRARIES rather than $<TARGET_OBJECTS:xxx>,
2586
  // and the whole point of orderDependencies is to capture those that are
2587
  // not listed in LINK_LIBRARIES.
2588
0
  std::vector<BT<cmGeneratorTarget*>> objectLibraries;
2589
0
  this->GT->GetObjectLibrariesInSources(objectLibraries);
2590
2591
  // We don't want to repeat the same target in the list. We will only
2592
  // retain one backtrace for cases where the same target is added multiple
2593
  // times from different commands. We also need a deterministic ordering,
2594
  // so we can't use cmGeneratorTarget* pointers in a std::set here.
2595
0
  using TargetIdMap = std::map<std::string, BT<cmGeneratorTarget*>>;
2596
0
  TargetIdMap uniqueObjectLibraries;
2597
0
  for (BT<cmGeneratorTarget*> const& target : objectLibraries) {
2598
0
    uniqueObjectLibraries[TargetId(target.Value, this->TopBuild)] = target;
2599
0
  }
2600
2601
0
  Json::Value jsonDependencies = Json::arrayValue;
2602
0
  for (TargetIdMap::value_type const& idTargetPair : uniqueObjectLibraries) {
2603
0
    Json::Value jsonDependency = Json::objectValue;
2604
0
    jsonDependency["id"] = idTargetPair.first;
2605
0
    this->AddBacktrace(jsonDependency, idTargetPair.second.Backtrace);
2606
0
    jsonDependencies.append(jsonDependency);
2607
0
  }
2608
0
  return jsonDependencies;
2609
0
}
2610
2611
Json::Value Target::DumpOrderDependencies()
2612
0
{
2613
  // The generated build systems don't account for per-config dependencies.
2614
  // This is due to limitations of Xcode and/or Visual Studio, which have
2615
  // (or at least once had) no way to express a per-config inter-target
2616
  // dependency.
2617
0
  Json::Value jsonDependencies = Json::arrayValue;
2618
0
  for (cmLinkItem const& linkItem : this->GT->GetUtilityItems()) {
2619
    // We don't want to dump dependencies on reserved targets like ZERO_CHECK.
2620
    // We shouldn't see link items that are not targets, but for backward
2621
    // compatibility reasons, they are currently allowed but silently ignored.
2622
0
    if (!linkItem.Target ||
2623
0
        cmGlobalGenerator::IsReservedTarget(linkItem.Target->GetName())) {
2624
0
      continue;
2625
0
    }
2626
0
    Json::Value jsonDependency = Json::objectValue;
2627
0
    jsonDependency["id"] = TargetId(linkItem.Target, this->TopBuild);
2628
0
    this->AddBacktrace(jsonDependency, linkItem.Backtrace);
2629
0
    jsonDependencies.append(jsonDependency);
2630
0
  }
2631
0
  return jsonDependencies;
2632
0
}
2633
2634
Json::Value Target::DumpFolder()
2635
0
{
2636
0
  Json::Value folder;
2637
0
  if (cmValue f = this->GT->GetProperty("FOLDER")) {
2638
0
    folder = Json::objectValue;
2639
0
    folder["name"] = *f;
2640
0
  }
2641
0
  return folder;
2642
0
}
2643
2644
Json::Value Target::DumpLauncher(char const* name, char const* type)
2645
0
{
2646
0
  cmValue property = this->GT->GetProperty(name);
2647
0
  Json::Value launcher;
2648
0
  if (property) {
2649
0
    cmLocalGenerator* lg = this->GT->GetLocalGenerator();
2650
0
    cmGeneratorExpression ge(*lg->GetCMakeInstance());
2651
0
    cmList commandWithArgs{ ge.Parse(*property)->Evaluate(lg, this->Config) };
2652
0
    if (!commandWithArgs.empty() && !commandWithArgs[0].empty()) {
2653
0
      std::string command(commandWithArgs[0]);
2654
0
      cmSystemTools::ConvertToUnixSlashes(command);
2655
0
      launcher = Json::objectValue;
2656
0
      launcher["command"] = RelativeIfUnder(this->TopSource, command);
2657
0
      launcher["type"] = type;
2658
0
      Json::Value args;
2659
0
      for (std::string const& arg : cmMakeRange(commandWithArgs).advance(1)) {
2660
0
        args.append(arg);
2661
0
      }
2662
0
      if (!args.empty()) {
2663
0
        launcher["arguments"] = std::move(args);
2664
0
      }
2665
0
    }
2666
0
  }
2667
0
  return launcher;
2668
0
}
2669
2670
Json::Value Target::DumpLaunchers()
2671
0
{
2672
0
  Json::Value launchers;
2673
0
  {
2674
0
    Json::Value launcher = DumpLauncher("TEST_LAUNCHER", "test");
2675
0
    if (!launcher.empty()) {
2676
0
      launchers.append(std::move(launcher));
2677
0
    }
2678
0
  }
2679
0
  if (this->GT->Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
2680
0
    Json::Value emulator = DumpLauncher("CROSSCOMPILING_EMULATOR", "emulator");
2681
0
    if (!emulator.empty()) {
2682
0
      launchers.append(std::move(emulator));
2683
0
    }
2684
0
  }
2685
0
  return launchers;
2686
0
}
2687
}
2688
2689
Json::Value Target::DumpDebugger()
2690
0
{
2691
0
  Json::Value debuggerInformation;
2692
0
  if (cmValue debuggerWorkingDirectory =
2693
0
        this->GT->GetGlobalGenerator()->GetDebuggerWorkingDirectory(
2694
0
          this->GT)) {
2695
0
    debuggerInformation = Json::objectValue;
2696
0
    debuggerInformation["workingDirectory"] = *debuggerWorkingDirectory;
2697
0
  }
2698
2699
0
  return debuggerInformation;
2700
0
}
2701
2702
Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
2703
                                   unsigned int versionMajor,
2704
                                   unsigned int versionMinor)
2705
0
{
2706
0
  Codemodel codemodel(fileAPI, versionMajor, versionMinor);
2707
0
  return codemodel.Dump();
2708
0
}