Coverage Report

Created: 2026-09-14 06:43

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