Coverage Report

Created: 2026-06-15 07:03

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