diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 01450ce9a7..c4a9d77cd8 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -84,7 +84,6 @@ static void AddExportGenerator( if (exportSet) { globalGenerator->AddBuildExportExportSet(exportGenerator.get()); } - makefile.AddExportBuildFileGenerator(std::move(exportGenerator)); } @@ -426,6 +425,7 @@ static bool HandleSbomMode(std::vector const& args, using arg_t = cmSbomArguments; using gen_t = cmExportBuildSbomGenerator; + status.GetMakefile().SetExplicitlyGeneratesSbom(true); return HandleSpecialExportMode(args, status); } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index b20f079f4b..8f837b134b 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -25,6 +25,7 @@ #include "cm_codecvt_Encoding.hxx" #include "cmAlgorithms.h" +#include "cmArgumentParserTypes.h" #include "cmBuildArgs.h" #include "cmCMakePath.h" #include "cmCPackPropertiesGenerator.h" @@ -42,6 +43,7 @@ #include "cmGeneratorTarget.h" #include "cmInstallGenerator.h" #include "cmInstallRuntimeDependencySet.h" +#include "cmInstallSbomExportGenerator.h" #include "cmLinkLineComputer.h" #include "cmList.h" #include "cmListFileCache.h" @@ -52,6 +54,7 @@ #include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmRange.h" +#include "cmSbomArguments.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -1569,6 +1572,37 @@ bool cmGlobalGenerator::Compute() return false; } +#ifndef CMAKE_BOOTSTRAP + bool isTryCompile = this->GetGlobalSetting("IN_TRY_COMPILE").IsOn(); + bool sbomEnabled = cmExperimental::HasSupportEnabled( + *this->Makefiles[0], cmExperimental::Feature::GenerateSbom); + + // Automatically generate SBOM files if enabled. + cmValue sbomFormat = this->GetGlobalSetting("CMAKE_INSTALL_SBOM_FORMATS"); + if (sbomFormat.IsSet() && !this->Makefiles[0]->ExplicitlyGeneratesSbom() && + sbomEnabled && !isTryCompile) { + std::string location = + this->Makefiles[0]->GetSafeDefinition("CMAKE_INSTALL_LIBDIR"); + if (location.empty()) { + location = "lib"; + } + + std::string projectName = this->LocalGenerators[0]->GetProjectName(); + cmSbomArguments sbomDefaultArgs; + sbomDefaultArgs.ProjectName = projectName; + for (auto& exportSet : this->ExportSets) { + sbomDefaultArgs.PackageName = exportSet.first; + std::string dest = cmStrCat(location, "/sbom/", projectName); + this->Makefiles[0]->AddInstallGenerator( + cm::make_unique( + &exportSet.second, dest, "", std::vector(), "", + cmInstallGenerator::SelectMessageLevel(this->Makefiles[0].get()), + false, std::move(sbomDefaultArgs), "", + this->Makefiles[0]->GetBacktrace())); + } + } +#endif + for (auto const& localGen : this->LocalGenerators) { cmMakefile* mf = localGen->GetMakefile(); for (auto const& g : mf->GetInstallGenerators()) { diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 3cb667c46c..716a6c5680 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -2584,6 +2584,7 @@ bool HandleSbomMode(std::vector const& args, // specified helper.Makefile->GetGlobalGenerator()->AddInstallComponent( ica.GetComponent()); + helper.Makefile->SetExplicitlyGeneratesSbom(true); // Create the export install generator. helper.Makefile->AddInstallGenerator( diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 54e6d6c90d..374dadd710 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1430,6 +1430,16 @@ void cmMakefile::AddTestGenerator(std::unique_ptr g) } } +bool cmMakefile::ExplicitlyGeneratesSbom() const +{ + return this->ExplicitSbomGenerator; +} + +void cmMakefile::SetExplicitlyGeneratesSbom(bool status) +{ + this->ExplicitSbomGenerator = status; +} + void cmMakefile::PushFunctionScope(std::string const& fileName, cmPolicies::PolicyMap const& pm) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index eeda5a248b..56deefad03 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -854,6 +854,9 @@ public: //! Initialize a makefile from its parent void InitializeFromParent(cmMakefile* parent); + bool ExplicitlyGeneratesSbom() const; + void SetExplicitlyGeneratesSbom(bool status = true); + void AddInstallGenerator(std::unique_ptr g); std::vector>& GetInstallGenerators() @@ -1239,6 +1242,7 @@ private: cmFindPackageStack FindPackageStack; unsigned int FindPackageStackNextIndex = 0; + bool ExplicitSbomGenerator = false; bool DebugFindPkg = false; bool CheckSystemVars; diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 9c24f28b7f..eaffdf7e0d 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -1412,6 +1412,7 @@ add_RunCMake_test(AutoExportDll add_RunCMake_test(AndroidMK) add_RunCMake_test(ExportPackageInfo) add_RunCMake_test(ExportSbom) +add_RunCMake_test(EnvSbom) add_RunCMake_test(InstallPackageInfo) add_RunCMake_test(InstallExportsAsPackageInfo) add_RunCMake_test(InstallSbom) diff --git a/Tests/RunCMake/EnvSbom/ApplicationTarget-install-check.cmake b/Tests/RunCMake/EnvSbom/ApplicationTarget-install-check.cmake new file mode 100644 index 0000000000..b8c70704da --- /dev/null +++ b/Tests/RunCMake/EnvSbom/ApplicationTarget-install-check.cmake @@ -0,0 +1,2 @@ +file(READ "${RunCMake_TEST_INSTALL_DIR}/lib/sbom/test_project/application_targets.spdx.json" content) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/ApplicationTarget-install-check.cmake) diff --git a/Tests/RunCMake/EnvSbom/ApplicationTarget.cmake b/Tests/RunCMake/EnvSbom/ApplicationTarget.cmake new file mode 100644 index 0000000000..8aca301755 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/ApplicationTarget.cmake @@ -0,0 +1,2 @@ +project(test_project) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/ApplicationTarget.cmake) diff --git a/Tests/RunCMake/EnvSbom/CMakeLists.txt b/Tests/RunCMake/EnvSbom/CMakeLists.txt new file mode 100644 index 0000000000..abd58e2f9a --- /dev/null +++ b/Tests/RunCMake/EnvSbom/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 4.2) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/EnvSbom/InterfaceTarget-install-check.cmake b/Tests/RunCMake/EnvSbom/InterfaceTarget-install-check.cmake new file mode 100644 index 0000000000..0fba94cc56 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/InterfaceTarget-install-check.cmake @@ -0,0 +1,2 @@ +file(READ "${RunCMake_TEST_INSTALL_DIR}/lib/sbom/test_project/interface_targets.spdx.json" content) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/InterfaceTarget-install-check.cmake) diff --git a/Tests/RunCMake/EnvSbom/InterfaceTarget.cmake b/Tests/RunCMake/EnvSbom/InterfaceTarget.cmake new file mode 100644 index 0000000000..4fcb0a32b2 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/InterfaceTarget.cmake @@ -0,0 +1,2 @@ +project(test_project) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/InterfaceTarget.cmake) diff --git a/Tests/RunCMake/EnvSbom/MissingPackageNamespace-install-check.cmake b/Tests/RunCMake/EnvSbom/MissingPackageNamespace-install-check.cmake new file mode 100644 index 0000000000..f162630094 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/MissingPackageNamespace-install-check.cmake @@ -0,0 +1,2 @@ +file(READ "${RunCMake_TEST_INSTALL_DIR}/lib/sbom/test_project/test_targets.spdx.json" content) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/MissingPackageNamespace-install-check.cmake) diff --git a/Tests/RunCMake/EnvSbom/MissingPackageNamespace.cmake b/Tests/RunCMake/EnvSbom/MissingPackageNamespace.cmake new file mode 100644 index 0000000000..c9659ca89a --- /dev/null +++ b/Tests/RunCMake/EnvSbom/MissingPackageNamespace.cmake @@ -0,0 +1,2 @@ +project(test_project VERSION 1.0.2) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/MissingPackageNamespace.cmake) diff --git a/Tests/RunCMake/EnvSbom/ProjectMetadata-install-check.cmake b/Tests/RunCMake/EnvSbom/ProjectMetadata-install-check.cmake new file mode 100644 index 0000000000..0198df15a7 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/ProjectMetadata-install-check.cmake @@ -0,0 +1,2 @@ +file(READ "${RunCMake_TEST_INSTALL_DIR}/lib/sbom/test_project/test_targets.spdx.json" content) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/ProjectMetadata-install-check.cmake) diff --git a/Tests/RunCMake/EnvSbom/ProjectMetadata.cmake b/Tests/RunCMake/EnvSbom/ProjectMetadata.cmake new file mode 100644 index 0000000000..0b07078f9c --- /dev/null +++ b/Tests/RunCMake/EnvSbom/ProjectMetadata.cmake @@ -0,0 +1,6 @@ +project(test_project LANGUAGES NONE + VERSION 1.3 + DESCRIPTION "An eloquent description" + HOMEPAGE_URL "www.example.com" + SPDX_LICENSE "BSD-3") +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/ProjectMetadata.cmake) diff --git a/Tests/RunCMake/EnvSbom/ReferencesNonExportedTarget-install-check.cmake b/Tests/RunCMake/EnvSbom/ReferencesNonExportedTarget-install-check.cmake new file mode 100644 index 0000000000..d00e3c0c52 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/ReferencesNonExportedTarget-install-check.cmake @@ -0,0 +1,2 @@ +file(READ "${RunCMake_TEST_INSTALL_DIR}/lib/sbom/test_project/dog.spdx.json" content) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/ReferencesNonExportedTarget-install-check.cmake) diff --git a/Tests/RunCMake/EnvSbom/ReferencesNonExportedTarget.cmake b/Tests/RunCMake/EnvSbom/ReferencesNonExportedTarget.cmake new file mode 100644 index 0000000000..7c30010f4a --- /dev/null +++ b/Tests/RunCMake/EnvSbom/ReferencesNonExportedTarget.cmake @@ -0,0 +1,2 @@ +project(test_project) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/ReferencesNonExportedTarget.cmake) diff --git a/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake b/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake new file mode 100644 index 0000000000..f3506612ee --- /dev/null +++ b/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake @@ -0,0 +1,34 @@ +include(RunCMake) + +set(common_test_options + -Wno-dev + "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=ca494ed3-b261-4205-a01f-603c95e4cae0" + "-DCMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES:STRING=e82e467b-f997-4464-8ace-b00808fff261" + "-DCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO:STRING=7fa7d13b-8308-4dc7-af39-9e450456d68f" + "-DCMAKE_INSTALL_SBOM_FORMATS:STRING=JSON" + "-DCMAKE_INSTALL_LIBDIR=lib" +) + +function(run_cmake_install test) + set(extra_options ${ARGN}) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + set(RunCMake_TEST_INSTALL_DIR ${RunCMake_BINARY_DIR}/${test}-install) + set(RunCMake_TEST_OPTIONS ${common_test_options} ${extra_options}) + list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_INSTALL_DIR}) + if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=DEBUG) + endif() + + run_cmake(${test}) + set(RunCMake_TEST_NO_CLEAN TRUE) + run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${test}-install ${CMAKE_COMMAND} --install . --config Debug) +endfunction() + +run_cmake_install(ApplicationTarget) +run_cmake_install(InterfaceTarget) +run_cmake_install(SharedTarget) + +run_cmake_install(MissingPackageNamespace) +run_cmake_install(ReferencesNonExportedTarget) +run_cmake_install(ProjectMetadata) diff --git a/Tests/RunCMake/EnvSbom/SharedTarget-install-check.cmake b/Tests/RunCMake/EnvSbom/SharedTarget-install-check.cmake new file mode 100644 index 0000000000..7bcf11662e --- /dev/null +++ b/Tests/RunCMake/EnvSbom/SharedTarget-install-check.cmake @@ -0,0 +1,2 @@ +file(READ "${RunCMake_TEST_INSTALL_DIR}/lib/sbom/test_project/shared_targets.spdx.json" content) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/SharedTarget-install-check.cmake) diff --git a/Tests/RunCMake/EnvSbom/SharedTarget.cmake b/Tests/RunCMake/EnvSbom/SharedTarget.cmake new file mode 100644 index 0000000000..6d3419ace4 --- /dev/null +++ b/Tests/RunCMake/EnvSbom/SharedTarget.cmake @@ -0,0 +1,2 @@ +project(test_project) +include(${CMAKE_CURRENT_LIST_DIR}/../Sbom/SharedTarget.cmake) diff --git a/Tests/RunCMake/Sbom/ApplicationTarget.cmake b/Tests/RunCMake/Sbom/ApplicationTarget.cmake index 54a89bd441..9d9961b5de 100644 --- a/Tests/RunCMake/Sbom/ApplicationTarget.cmake +++ b/Tests/RunCMake/Sbom/ApplicationTarget.cmake @@ -16,4 +16,5 @@ target_link_libraries(application PUBLIC bar::bar) install( TARGETS application EXPORT application_targets + DESTINATION . ) diff --git a/Tests/RunCMake/Sbom/InterfaceTarget.cmake b/Tests/RunCMake/Sbom/InterfaceTarget.cmake index 1df1b79938..8c0f91b7d6 100644 --- a/Tests/RunCMake/Sbom/InterfaceTarget.cmake +++ b/Tests/RunCMake/Sbom/InterfaceTarget.cmake @@ -16,4 +16,5 @@ target_link_libraries(interface INTERFACE bar::bar) install( TARGETS interface EXPORT interface_targets + DESTINATION . ) diff --git a/Tests/RunCMake/Sbom/MissingPackageNamespace.cmake b/Tests/RunCMake/Sbom/MissingPackageNamespace.cmake index 516a049086..38341bd721 100644 --- a/Tests/RunCMake/Sbom/MissingPackageNamespace.cmake +++ b/Tests/RunCMake/Sbom/MissingPackageNamespace.cmake @@ -18,4 +18,5 @@ target_link_libraries(test PUBLIC baz) install( TARGETS test EXPORT test_targets + DESTINATION . ) diff --git a/Tests/RunCMake/Sbom/ProjectMetadata.cmake b/Tests/RunCMake/Sbom/ProjectMetadata.cmake index be8566bf29..ff53931e61 100644 --- a/Tests/RunCMake/Sbom/ProjectMetadata.cmake +++ b/Tests/RunCMake/Sbom/ProjectMetadata.cmake @@ -8,4 +8,5 @@ add_library(test INTERFACE) install( TARGETS test EXPORT test_targets + DESTINATION . ) diff --git a/Tests/RunCMake/Sbom/ReferencesNonExportedTarget.cmake b/Tests/RunCMake/Sbom/ReferencesNonExportedTarget.cmake index 555c08fc2f..4c1cbf216f 100644 --- a/Tests/RunCMake/Sbom/ReferencesNonExportedTarget.cmake +++ b/Tests/RunCMake/Sbom/ReferencesNonExportedTarget.cmake @@ -8,4 +8,3 @@ add_library(canine INTERFACE) target_link_libraries(canine INTERFACE mammal) install(TARGETS canine EXPORT dog DESTINATION .) -install(SBOM dog EXPORT dog DESTINATION .) diff --git a/Tests/RunCMake/Sbom/SharedTarget.cmake b/Tests/RunCMake/Sbom/SharedTarget.cmake index 24ad7d95f4..67d7027d87 100644 --- a/Tests/RunCMake/Sbom/SharedTarget.cmake +++ b/Tests/RunCMake/Sbom/SharedTarget.cmake @@ -11,4 +11,5 @@ target_link_libraries(shared PUBLIC foo::foo) install( TARGETS shared EXPORT shared_targets + DESTINATION . )