blob: c5c9acb31b1429defecc31198eef8efd54cca9a0 [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmExportInstallSbomGenerator.h"
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <utility>
#include <vector>
#include <cmext/string_view>
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmInstallExportGenerator.h"
#include "cmInstallFileSetGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmSbomArguments.h"
#include "cmSbomObject.h"
#include "cmSpdx.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetExport.h"
cmExportInstallSbomGenerator::cmExportInstallSbomGenerator(
cmInstallExportGenerator* iegen, cmSbomArguments args)
: cmExportSbomGenerator(std::move(args))
, cmExportInstallFileGenerator(iegen)
{
this->SetNamespace(cmStrCat(this->GetPackageName(), "::"_s));
}
std::string cmExportInstallSbomGenerator::GetConfigImportFileGlob() const
{
std::string glob = cmStrCat(this->FileBase, "@*", this->FileExt);
return glob;
}
std::string const& cmExportInstallSbomGenerator::GetExportName() const
{
return this->GetPackageName();
}
cm::string_view cmExportInstallSbomGenerator::GetImportPrefixWithSlash() const
{
return "@prefix@/"_s;
}
bool cmExportInstallSbomGenerator::GenerateMainFile(std::ostream& os)
{
std::vector<cmTargetExport const*> allTargets;
{
auto visitor = [&](cmTargetExport const* te) { allTargets.push_back(te); };
if (!this->CollectExports(visitor)) {
return false;
}
}
cmSbomDocument doc;
doc.Graph.reserve(256);
cmSpdxCreationInfo const* ci =
insert_back(doc.Graph, this->GenerateCreationInfo());
cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
std::vector<TargetProperties> targets;
targets.reserve(allTargets.size());
for (cmTargetExport const* te : allTargets) {
cmGeneratorTarget const* gt = te->Target;
ImportPropertyMap properties;
if (!this->PopulateInterfaceProperties(te, properties)) {
return false;
}
this->PopulateLinkLibrariesProperty(
gt, cmGeneratorExpression::InstallInterface, properties);
this->PopulateInterfaceLinkLibrariesProperty(
gt, cmGeneratorExpression::InstallInterface, properties);
targets.push_back(TargetProperties{
insert_back(project->RootElements,
this->GenerateImportTarget(ci, te->Target)),
te->Target, std::move(properties) });
}
for (auto const& target : targets) {
this->GenerateProperties(doc, project, ci, target, targets);
}
this->WriteSbom(doc, os);
return true;
}
void cmExportInstallSbomGenerator::GenerateImportTargetsConfig(
std::ostream& os, std::string const& config, std::string const& suffix)
{
cmSbomDocument doc;
doc.Graph.reserve(256);
cmSpdxCreationInfo const* ci =
insert_back(doc.Graph, this->GenerateCreationInfo());
cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
std::vector<TargetProperties> targets;
std::string cfg = (config.empty() ? "noconfig" : config);
for (auto const& te : this->GetExportSet()->GetTargetExports()) {
ImportPropertyMap properties;
std::set<std::string> importedLocations;
if (this->GetExportTargetType(te.get()) !=
cmStateEnums::INTERFACE_LIBRARY) {
this->PopulateImportProperties(config, suffix, te.get(), properties,
importedLocations);
}
this->PopulateInterfaceProperties(te.get(), properties);
this->PopulateInterfaceLinkLibrariesProperty(
te->Target, cmGeneratorExpression::InstallInterface, properties);
this->PopulateLinkLibrariesProperty(
te->Target, cmGeneratorExpression::InstallInterface, properties);
targets.push_back(TargetProperties{
insert_back(project->RootElements,
this->GenerateImportTarget(ci, te->Target)),
te->Target, std::move(properties) });
}
for (auto const& target : targets) {
this->GenerateProperties(doc, project, ci, target, targets);
}
this->WriteSbom(doc, os);
}
std::string cmExportInstallSbomGenerator::GenerateImportPrefix() const
{
std::string expDest = this->IEGen->GetDestination();
if (cmSystemTools::FileIsFullPath(expDest)) {
std::string const& installPrefix =
this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
"CMAKE_INSTALL_PREFIX");
if (cmHasPrefix(expDest, installPrefix)) {
auto n = installPrefix.length();
while (n < expDest.length() && expDest[n] == '/') {
++n;
}
expDest = expDest.substr(n);
} else {
this->ReportError(
cmStrCat("install(SBOM \"", this->GetExportName(),
"\" ...) specifies DESTINATION \"", expDest,
"\" which is not a subdirectory of the install prefix."));
return {};
}
}
if (expDest.empty()) {
return this->GetInstallPrefix();
}
return cmStrCat(this->GetImportPrefixWithSlash(), expDest);
}
void cmExportInstallSbomGenerator::HandleMissingTarget(
std::string& /* link_libs */, cmGeneratorTarget const* /* depender */,
cmGeneratorTarget* /* dependee */)
{
}
bool cmExportInstallSbomGenerator::CheckInterfaceDirs(
std::string const& /* prepro */, cmGeneratorTarget const* /* target */,
std::string const& /* prop */) const
{
return true;
}
std::string cmExportInstallSbomGenerator::InstallNameDir(
cmGeneratorTarget const* target, std::string const& config)
{
std::string install_name_dir;
cmMakefile* mf = target->Target->GetMakefile();
if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
install_name_dir =
target->GetInstallNameDirForInstallTree(config, "@prefix@");
}
return install_name_dir;
}
std::string cmExportInstallSbomGenerator::GetCxxModulesDirectory() const
{
return {};
}
void cmExportInstallSbomGenerator::GenerateCxxModuleConfigInformation(
std::string const&, std::ostream&) const
{
}
std::string cmExportInstallSbomGenerator::GetCxxModuleFile(
std::string const& /* name */) const
{
return {};
}
cm::optional<std::string> cmExportInstallSbomGenerator::GetFileSetDirectory(
cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
cm::optional<std::string> const& config)
{
cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
auto cge =
ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination());
std::string const unescapedDest =
cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte);
bool const isConfigDependent = cge->GetHadContextSensitiveCondition();
if (config && !isConfigDependent) {
return {};
}
std::string const& type = fileSet->GetType();
if (config && (type == "CXX_MODULES"_s)) {
cmMakefile* mf = gte->LocalGenerator->GetMakefile();
std::ostringstream e;
e << "The \"" << gte->GetName() << "\" target's interface file set \""
<< fileSet->GetName() << "\" of type \"" << type
<< "\" contains context-sensitive base file entries which is not "
"supported.";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return {};
}
cm::optional<std::string> dest = cmOutputConverter::EscapeForCMake(
unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
dest = cmStrCat("@prefix@/"_s, *dest);
}
return dest;
}