Coverage Report

Created: 2026-02-09 06:05

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