Coverage Report

Created: 2026-03-12 06:35

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