blob: 60672e6a0a4d84ae46e9549ac8d5e057671eedfe [file] [edit]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "cmExportFileGenerator.h"
#include "cmFindPackageStack.h"
#include "cmGeneratorExpression.h"
#include "cmSbomArguments.h"
class cmExportSet;
class cmGeneratorTarget;
class cmLocalGenerator;
struct cmSbomDocument;
struct cmSpdxDocument;
struct cmSpdxPackage;
struct cmSpdxCreationInfo;
/** \class cmSbomBuilder
* \brief Abstract base for SBOM document generators.
*
* Concrete leaves (cmBuildSbomBuilder, cmInstallSbomBuilder) supply two
* pure virtuals:
*
* - Generate(): selects the generator-expression preprocess context
* (BuildInterface vs InstallInterface) and delegates to the shared
* GenerateForTargets() body.
* - FindExportInfoFor(): consults the mode's export map (build-tree vs
* install-tree) to resolve cross-export references.
*
* All shared SPDX assembly, link-graph walking, and serialization lives
* here so that the leaves stay trivial.
*/
class cmSbomBuilder
{
public:
virtual ~cmSbomBuilder() = default;
/** Compute phase: wire the local generator, run Compute() on the owned
* export sets, and populate the SbomTargets cache so peer SBOMs can
* query CoversTarget() before any Generate() runs. */
void Compute(cmLocalGenerator* lg);
/** Produce the SBOM document on `os`. Implementations pick the
* generator-expression preprocess context (BuildInterface vs
* InstallInterface) and delegate to GenerateForTargets. */
virtual bool Generate(std::ostream& os) = 0;
/** Identifier this SBOM publishes itself as (the SPDX document name and
* the namespace under which other SBOMs refer to its contents). */
std::string const& GetPackageName() const { return this->PackageName; }
/** True if `target` is one of the targets this SBOM directly describes. */
bool CoversTarget(cmGeneratorTarget const* target) const;
/** True if `set` is one of the export sets this SBOM was built from. */
bool CoversExportSet(cmExportSet const* set) const;
/** Names of peer SBOMs (same build/install mode) that cover a target.
* Used by NoteLinkedTarget to attribute a cross-reference when no
* install(export) namespace is available. Sorted alphabetically. */
struct SbomInfo
{
std::vector<std::string> Packages;
};
protected:
cmSbomBuilder(cmSbomArguments args, std::vector<cmExportSet*> exportSets,
cmLocalGenerator* lg);
/** Mode-specific: where does `target` appear in the project's exports?
* Build leaves consult cmGlobalGenerator::FindBuildExportInfo;
* install leaves consult cmGlobalGenerator::FindInstallExportInfo. */
virtual cmExportFileGenerator::ExportInfo FindExportInfoFor(
cmGeneratorTarget const* target) const = 0;
/** Mode-specific: which peer SBOMs cover `target`?
* Build leaves consult cmGlobalGenerator::FindBuildSbomInfo;
* install leaves consult cmGlobalGenerator::FindInstallSbomInfo. */
virtual SbomInfo FindSbomInfoFor(cmGeneratorTarget const* target) const = 0;
/** The set of targets the SBOM directly describes — derived from the
* associated export sets. */
std::set<cmGeneratorTarget const*> CollectTargets() const;
/** Generate an sbom for the targets in this->SbomTargets. Each leaf class
* calls this internally */
bool GenerateForTargets(
std::ostream& os,
cmGeneratorExpression::PreprocessContext preprocessContext);
using ImportPropertyMap = std::map<std::string, std::string>;
struct TargetProperties
{
cmSpdxPackage const* Package;
cmGeneratorTarget const* Target;
ImportPropertyMap Properties;
};
void WriteSbom(cmSbomDocument& doc, std::ostream& os) const;
cmSpdxCreationInfo GenerateCreationInfo() const;
cmSpdxDocument GenerateSbom(cmSpdxCreationInfo const* ci) const;
cmSpdxPackage GenerateImportTarget(cmSpdxCreationInfo const* ci,
cmGeneratorTarget const* target) const;
bool AddPackageInformation(cmSpdxPackage& artifact, std::string const& name,
cmPackageInformation const& package) const;
bool GenerateProperties(
cmSbomDocument& doc, cmSpdxDocument* project, cmSpdxCreationInfo const* ci,
TargetProperties const& current,
std::vector<TargetProperties> const& allTargets) const;
void GenerateLinkProperties(
cmSbomDocument& doc, cmSpdxDocument* project, cmSpdxCreationInfo const* ci,
std::string const& libraries, TargetProperties const& current,
std::vector<TargetProperties> const& allTargets) const;
bool NoteLinkedTarget(cmGeneratorTarget const* target,
std::string const& linkedName,
cmGeneratorTarget const* linkedTarget);
bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target,
cmLocalGenerator const* lg);
void ResolveTargetsInGeneratorExpression(std::string& input,
cmGeneratorTarget const* target,
cmLocalGenerator const* lg);
void ResolveTargetsInGeneratorExpressions(std::string& input,
cmGeneratorTarget const* target);
bool PopulateInterfaceLinkLibrariesProperty(
cmGeneratorTarget const* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties);
bool PopulateLinkLibrariesProperty(cmGeneratorTarget const* target,
cmGeneratorExpression::PreprocessContext,
ImportPropertyMap& properties);
// Set at construction or via setters
cmLocalGenerator* LocalGenerator = nullptr;
// Inputs
std::vector<cmExportSet*> ExportSets;
private:
struct LinkInfo
{
std::string Package;
std::string Component;
};
// Metadata
std::string const PackageName;
std::string const Namespace;
std::string const PackageVersion;
std::string const PackageDescription;
std::string const PackageWebsite;
std::string const PackageUrl;
std::string const PackageLicense;
cmSbomArguments::SbomFormat const PackageFormat;
// Derived from inputs at generate time
std::set<cmGeneratorTarget const*> SbomTargets;
// Accumulated during generation
std::map<std::string, LinkInfo> LinkTargets;
std::map<std::string, cmPackageInformation> Requirements;
};