Coverage Report

Created: 2026-02-09 06:05

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