Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmExportInstallSbomGenerator.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 "cmExportInstallSbomGenerator.h"
4
5
#include <functional>
6
#include <map>
7
#include <memory>
8
#include <set>
9
#include <sstream>
10
#include <utility>
11
#include <vector>
12
13
#include <cmext/string_view>
14
15
#include "cmExportSet.h"
16
#include "cmFileSetMetadata.h"
17
#include "cmGeneratorExpression.h"
18
#include "cmGeneratorFileSet.h"
19
#include "cmGeneratorTarget.h"
20
#include "cmInstallExportGenerator.h"
21
#include "cmInstallFileSetGenerator.h"
22
#include "cmLocalGenerator.h"
23
#include "cmMakefile.h"
24
#include "cmMessageType.h"
25
#include "cmOutputConverter.h"
26
#include "cmSbomArguments.h"
27
#include "cmSbomObject.h"
28
#include "cmSpdx.h"
29
#include "cmStateTypes.h"
30
#include "cmStringAlgorithms.h"
31
#include "cmSystemTools.h"
32
#include "cmTarget.h"
33
#include "cmTargetExport.h"
34
35
cmExportInstallSbomGenerator::cmExportInstallSbomGenerator(
36
  cmInstallExportGenerator* iegen, cmSbomArguments args)
37
0
  : cmExportSbomGenerator(std::move(args))
38
0
  , cmExportInstallFileGenerator(iegen)
39
0
{
40
0
  this->SetNamespace(cmStrCat(this->GetPackageName(), "::"_s));
41
0
}
Unexecuted instantiation: cmExportInstallSbomGenerator::cmExportInstallSbomGenerator(cmInstallExportGenerator*, cmSbomArguments)
Unexecuted instantiation: cmExportInstallSbomGenerator::cmExportInstallSbomGenerator(cmInstallExportGenerator*, cmSbomArguments)
42
43
std::string cmExportInstallSbomGenerator::GetConfigImportFileGlob() const
44
0
{
45
0
  std::string glob = cmStrCat(this->FileBase, "@*", this->FileExt);
46
0
  return glob;
47
0
}
48
49
std::string const& cmExportInstallSbomGenerator::GetExportName() const
50
0
{
51
0
  return this->GetPackageName();
52
0
}
53
54
cm::string_view cmExportInstallSbomGenerator::GetImportPrefixWithSlash() const
55
0
{
56
0
  return "@prefix@/"_s;
57
0
}
58
59
bool cmExportInstallSbomGenerator::GenerateMainFile(std::ostream& os)
60
0
{
61
0
  std::vector<cmTargetExport const*> allTargets;
62
0
  {
63
0
    auto visitor = [&](cmTargetExport const* te) { allTargets.push_back(te); };
64
65
0
    if (!this->CollectExports(visitor)) {
66
0
      return false;
67
0
    }
68
0
  }
69
0
  cmSbomDocument doc;
70
0
  doc.Graph.reserve(256);
71
72
0
  cmSpdxCreationInfo const* ci =
73
0
    insert_back(doc.Graph, this->GenerateCreationInfo());
74
0
  cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
75
0
  std::vector<TargetProperties> targets;
76
0
  targets.reserve(allTargets.size());
77
78
0
  for (cmTargetExport const* te : allTargets) {
79
0
    cmGeneratorTarget const* gt = te->Target;
80
0
    ImportPropertyMap properties;
81
0
    if (!this->PopulateInterfaceProperties(te, properties)) {
82
0
      return false;
83
0
    }
84
0
    this->PopulateLinkLibrariesProperty(
85
0
      gt, cmGeneratorExpression::InstallInterface, properties);
86
0
    this->PopulateInterfaceLinkLibrariesProperty(
87
0
      gt, cmGeneratorExpression::InstallInterface, properties);
88
89
0
    targets.push_back(TargetProperties{
90
0
      insert_back(project->RootElements,
91
0
                  this->GenerateImportTarget(ci, te->Target)),
92
0
      te->Target, std::move(properties) });
93
0
  }
94
95
0
  for (auto const& target : targets) {
96
0
    this->GenerateProperties(doc, project, ci, target, targets);
97
0
  }
98
99
0
  this->WriteSbom(doc, os);
100
0
  return true;
101
0
}
102
103
void cmExportInstallSbomGenerator::GenerateImportTargetsConfig(
104
  std::ostream& os, std::string const& config, std::string const& suffix)
105
0
{
106
0
  cmSbomDocument doc;
107
0
  doc.Graph.reserve(256);
108
109
0
  cmSpdxCreationInfo const* ci =
110
0
    insert_back(doc.Graph, this->GenerateCreationInfo());
111
0
  cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
112
113
0
  std::vector<TargetProperties> targets;
114
0
  std::string cfg = (config.empty() ? "noconfig" : config);
115
116
0
  for (auto const& te : this->GetExportSet()->GetTargetExports()) {
117
0
    ImportPropertyMap properties;
118
0
    std::set<std::string> importedLocations;
119
120
0
    if (this->GetExportTargetType(te.get()) !=
121
0
        cmStateEnums::INTERFACE_LIBRARY) {
122
0
      this->PopulateImportProperties(config, suffix, te.get(), properties,
123
0
                                     importedLocations);
124
0
    }
125
0
    this->PopulateInterfaceProperties(te.get(), properties);
126
0
    this->PopulateInterfaceLinkLibrariesProperty(
127
0
      te->Target, cmGeneratorExpression::InstallInterface, properties);
128
0
    this->PopulateLinkLibrariesProperty(
129
0
      te->Target, cmGeneratorExpression::InstallInterface, properties);
130
131
0
    targets.push_back(TargetProperties{
132
0
      insert_back(project->RootElements,
133
0
                  this->GenerateImportTarget(ci, te->Target)),
134
0
      te->Target, std::move(properties) });
135
0
  }
136
137
0
  for (auto const& target : targets) {
138
0
    this->GenerateProperties(doc, project, ci, target, targets);
139
0
  }
140
141
0
  this->WriteSbom(doc, os);
142
0
}
143
144
std::string cmExportInstallSbomGenerator::GenerateImportPrefix() const
145
0
{
146
0
  std::string expDest = this->IEGen->GetDestination();
147
0
  if (cmSystemTools::FileIsFullPath(expDest)) {
148
0
    std::string const& installPrefix =
149
0
      this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
150
0
        "CMAKE_INSTALL_PREFIX");
151
0
    if (cmHasPrefix(expDest, installPrefix)) {
152
0
      auto n = installPrefix.length();
153
0
      while (n < expDest.length() && expDest[n] == '/') {
154
0
        ++n;
155
0
      }
156
0
      expDest = expDest.substr(n);
157
0
    } else {
158
0
      this->ReportError(
159
0
        cmStrCat("install(SBOM \"", this->GetExportName(),
160
0
                 "\" ...) specifies DESTINATION \"", expDest,
161
0
                 "\" which is not a subdirectory of the install prefix."));
162
0
      return {};
163
0
    }
164
0
  }
165
166
0
  if (expDest.empty()) {
167
0
    return this->GetInstallPrefix();
168
0
  }
169
0
  return cmStrCat(this->GetImportPrefixWithSlash(), expDest);
170
0
}
171
172
void cmExportInstallSbomGenerator::HandleMissingTarget(
173
  std::string& /* link_libs */, cmGeneratorTarget const* /* depender */,
174
  cmGeneratorTarget* /* dependee */)
175
0
{
176
0
}
177
178
bool cmExportInstallSbomGenerator::CheckInterfaceDirs(
179
  std::string const& /* prepro */, cmGeneratorTarget const* /* target */,
180
  std::string const& /* prop */) const
181
0
{
182
0
  return true;
183
0
}
184
185
std::string cmExportInstallSbomGenerator::InstallNameDir(
186
  cmGeneratorTarget const* target, std::string const& config)
187
0
{
188
0
  std::string install_name_dir;
189
190
0
  cmMakefile* mf = target->Target->GetMakefile();
191
0
  if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
192
0
    install_name_dir =
193
0
      target->GetInstallNameDirForInstallTree(config, "@prefix@");
194
0
  }
195
196
0
  return install_name_dir;
197
0
}
198
199
std::string cmExportInstallSbomGenerator::GetCxxModulesDirectory() const
200
0
{
201
0
  return {};
202
0
}
203
204
void cmExportInstallSbomGenerator::GenerateCxxModuleConfigInformation(
205
  std::string const&, std::ostream&) const
206
0
{
207
0
}
208
209
std::string cmExportInstallSbomGenerator::GetCxxModuleFile(
210
  std::string const& /* name */) const
211
0
{
212
0
  return {};
213
0
}
214
215
cm::optional<std::string> cmExportInstallSbomGenerator::GetFileSetDirectory(
216
  cmGeneratorTarget* gte, cmTargetExport const* te,
217
  cmGeneratorFileSet const* fileSet, cm::optional<std::string> const& config)
218
0
{
219
0
  cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
220
0
  auto cge =
221
0
    ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination());
222
223
0
  std::string const unescapedDest =
224
0
    cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte);
225
0
  bool const isConfigDependent = cge->GetHadContextSensitiveCondition();
226
227
0
  if (config && !isConfigDependent) {
228
0
    return {};
229
0
  }
230
231
0
  std::string const& type = fileSet->GetType();
232
0
  if (config && (type == cm::FileSetMetadata::CXX_MODULES)) {
233
0
    cmMakefile* mf = gte->LocalGenerator->GetMakefile();
234
0
    std::ostringstream e;
235
0
    e << "The \"" << gte->GetName() << "\" target's interface file set \""
236
0
      << fileSet->GetName() << "\" of type \"" << type
237
0
      << "\" contains context-sensitive base file entries which is not "
238
0
         "supported.";
239
0
    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
240
0
    return {};
241
0
  }
242
243
0
  cm::optional<std::string> dest = cmOutputConverter::EscapeForCMake(
244
0
    unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
245
246
0
  if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
247
0
    dest = cmStrCat("@prefix@/"_s, *dest);
248
0
  }
249
250
0
  return dest;
251
0
}