| /* 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; |
| } |