diff --git a/cmake/QtBuildRepoHelpers.cmake b/cmake/QtBuildRepoHelpers.cmake index be487d7f410..00dfc2f1b44 100644 --- a/cmake/QtBuildRepoHelpers.cmake +++ b/cmake/QtBuildRepoHelpers.cmake @@ -351,10 +351,7 @@ macro(qt_build_repo_begin) set_property(GLOBAL PROPERTY _qt_synced_modules ${QT_INTERNAL_SYNCED_MODULES}) endif() - _qt_internal_sbom_begin_project( - INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}" - QT_CPE - ) + _qt_internal_sbom_auto_begin_qt_repo_project() endmacro() # Runs delayed actions on some of the Qt targets. @@ -418,7 +415,7 @@ macro(qt_build_repo_end) set(QT_INTERNAL_FRESH_REQUESTED "FALSE" CACHE INTERNAL "") endif() - _qt_internal_sbom_end_project() + _qt_internal_sbom_auto_end_qt_repo_project() if(NOT QT_SUPERBUILD) qt_internal_qt_configure_end() diff --git a/cmake/QtPublicSbomGenerationHelpers.cmake b/cmake/QtPublicSbomGenerationHelpers.cmake index de632cdc0fe..da59482a72f 100644 --- a/cmake/QtPublicSbomGenerationHelpers.cmake +++ b/cmake/QtPublicSbomGenerationHelpers.cmake @@ -18,9 +18,25 @@ function(qt_internal_sbom_set_default_option_value_and_error_if_empty option_nam endif() endfunction() +# Helper that returns the relative sbom build dir. +# To accommodate multiple projects within a qt repo (like qtwebengine), we need to choose separate +# build dirs for each project. +function(_qt_internal_get_current_project_sbom_relative_dir out_var) + _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) + _qt_internal_sbom_get_qt_repo_project_name_lower_case(real_qt_repo_project_name_lowercase) + + if(repo_project_name_lowercase STREQUAL real_qt_repo_project_name_lowercase) + set(sbom_dir "qt_sbom") + else() + set(sbom_dir "qt_sbom/${repo_project_name_lowercase}") + endif() + set(${out_var} "${sbom_dir}" PARENT_SCOPE) +endfunction() + # Helper that returns the directory where the intermediate sbom files will be generated. function(_qt_internal_get_current_project_sbom_dir out_var) - set(sbom_dir "${PROJECT_BINARY_DIR}/qt_sbom") + _qt_internal_get_current_project_sbom_relative_dir(relative_dir) + set(sbom_dir "${PROJECT_BINARY_DIR}/${relative_dir}") set(${out_var} "${sbom_dir}" PARENT_SCOPE) endfunction() @@ -414,6 +430,7 @@ function(_qt_internal_sbom_end_project_generate) endif() _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) + _qt_internal_sbom_get_qt_repo_project_name_lower_case(real_qt_repo_project_name_lowercase) # Create a build target to create a build-time sbom (no verification codes or sha1s). set(repo_sbom_target "sbom_${repo_project_name_lowercase}") @@ -427,7 +444,7 @@ function(_qt_internal_sbom_end_project_generate) USES_TERMINAL # To avoid running two configs of the command in parallel ) - get_cmake_property(qt_repo_deps _qt_repo_deps_${repo_project_name_lowercase}) + get_cmake_property(qt_repo_deps _qt_repo_deps_${real_qt_repo_project_name_lowercase}) if(qt_repo_deps) foreach(repo_dep IN LISTS qt_repo_deps) set(repo_dep_sbom "sbom_${repo_dep}") @@ -767,6 +784,7 @@ function(_qt_internal_sbom_generate_add_external_reference) set(content " set(relative_file_name \"${arg_FILENAME}\") set(document_dir_paths ${install_prefixes}) + list(JOIN document_dir_paths \"\\n\" document_dir_paths_per_line) foreach(document_dir_path IN LISTS document_dir_paths) set(document_file_path \"\${document_dir_path}/\${relative_file_name}\") if(EXISTS \"\${document_file_path}\") @@ -775,7 +793,7 @@ function(_qt_internal_sbom_generate_add_external_reference) endforeach() if(NOT EXISTS \"\${document_file_path}\") message(FATAL_ERROR \"Could not find external SBOM document \${relative_file_name}\" - \" in any of the document dir paths: \${document_dir_paths} \" + \" in any of the document dir paths: \${document_dir_paths_per_line} \" ) endif() file(SHA1 \"\${document_file_path}\" ext_sha1) diff --git a/cmake/QtPublicSbomHelpers.cmake b/cmake/QtPublicSbomHelpers.cmake index f1fce0fffa0..9e4a855c062 100644 --- a/cmake/QtPublicSbomHelpers.cmake +++ b/cmake/QtPublicSbomHelpers.cmake @@ -38,6 +38,7 @@ function(_qt_internal_sbom_begin_project) DOCUMENT_NAMESPACE VERSION SBOM_PROJECT_NAME + QT_REPO_PROJECT_NAME CPE ) set(multi_args @@ -69,6 +70,13 @@ function(_qt_internal_sbom_begin_project) else() _qt_internal_sbom_set_root_project_name("${PROJECT_NAME}") endif() + + if(arg_QT_REPO_PROJECT_NAME) + _qt_internal_sbom_set_qt_repo_project_name("${arg_QT_REPO_PROJECT_NAME}") + else() + _qt_internal_sbom_set_qt_repo_project_name("${PROJECT_NAME}") + endif() + _qt_internal_sbom_get_root_project_name_for_spdx_id(repo_project_name_for_spdx_id) _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) @@ -376,6 +384,75 @@ function(_qt_internal_sbom_end_project) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${attribution_files}") endfunction() +# Automatically begins sbom generation for a qt git repo unless QT_SKIP_SBOM_AUTO_PROJECT is TRUE. +function(_qt_internal_sbom_auto_begin_qt_repo_project) + # Allow skipping auto generation of sbom project, in case it needs to be manually adjusted with + # extra parameters. + if(QT_SKIP_SBOM_AUTO_PROJECT) + return() + endif() + + _qt_internal_sbom_begin_qt_repo_project() +endfunction() + +# Sets up sbom generation for a qt git repo or qt-git-repo-sub-project (e.g. qtpdf in qtwebengine). +# +# In the case of a qt-git-repo-sub-project, the function expects the following options: +# - SBOM_PROJECT_NAME (e.g. QtPdf) +# - QT_REPO_PROJECT_NAME (e.g. QtWebEngine) +# +# Expects the following variables to always be set before the function call: +# - QT_STAGING_PREFIX +# - INSTALL_SBOMDIR +function(_qt_internal_sbom_begin_qt_repo_project) + set(opt_args "") + set(single_args + SBOM_PROJECT_NAME + QT_REPO_PROJECT_NAME + ) + set(multi_args "") + + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set(sbom_project_args "") + + _qt_internal_forward_function_args( + FORWARD_APPEND + FORWARD_PREFIX arg + FORWARD_OUT_VAR sbom_project_args + FORWARD_OPTIONS + ${opt_args} + FORWARD_SINGLE + ${single_args} + FORWARD_MULTI + ${multi_args} + ) + + _qt_internal_sbom_begin_project( + INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}" + QT_CPE + ${sbom_project_args} + ) +endfunction() + +# Automatically ends sbom generation for a qt git repo unless QT_SKIP_SBOM_AUTO_PROJECT is TRUE. +function(_qt_internal_sbom_auto_end_qt_repo_project) + # Allow skipping auto generation of sbom project, in case it needs to be manually adjusted with + # extra parameters. + if(QT_SKIP_SBOM_AUTO_PROJECT) + return() + endif() + + _qt_internal_sbom_end_qt_repo_project() +endfunction() + +# Endssbom generation for a qt git repo or qt-git-repo-sub-project. + +function(_qt_internal_sbom_end_qt_repo_project) + _qt_internal_sbom_end_project() +endfunction() + # Helper to get purl parsing options. macro(_qt_internal_get_sbom_purl_parsing_options opt_args single_args multi_args) set(${opt_args} @@ -2608,11 +2685,17 @@ macro(_qt_internal_sbom_get_attribution_key json_key out_var out_prefix) endif() endmacro() -# Set sbom project name for the root project. +# Sets the sbom project name for the root project. function(_qt_internal_sbom_set_root_project_name project_name) set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_project_name "${project_name}") endfunction() +# Sets the real qt repo project name for a given project (e.g. set QtWebEngine for project QtPdf). +# This is needed to be able to extract the qt repo dependencies in a top-level build. +function(_qt_internal_sbom_set_qt_repo_project_name project_name) + set_property(GLOBAL PROPERTY _qt_internal_sbom_qt_repo_project_name "${project_name}") +endfunction() + # Get repo project_name spdx id reference, needs to start with Package- to be NTIA compliant. function(_qt_internal_sbom_get_root_project_name_for_spdx_id out_var) _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) @@ -2620,7 +2703,7 @@ function(_qt_internal_sbom_get_root_project_name_for_spdx_id out_var) set(${out_var} "${sbom_repo_project_name}" PARENT_SCOPE) endfunction() -# Just a lower case sbom project name. +# Returns the lower case sbom project name. function(_qt_internal_sbom_get_root_project_name_lower_case out_var) get_cmake_property(project_name _qt_internal_sbom_repo_project_name) @@ -2632,6 +2715,19 @@ function(_qt_internal_sbom_get_root_project_name_lower_case out_var) set(${out_var} "${repo_project_name_lowercase}" PARENT_SCOPE) endfunction() +# Returns the lower case real qt repo project name (e.g. returns 'qtwebengine' when building the +# project qtpdf). +function(_qt_internal_sbom_get_qt_repo_project_name_lower_case out_var) + get_cmake_property(project_name _qt_internal_sbom_qt_repo_project_name) + + if(NOT project_name) + message(FATAL_ERROR "No real Qt repo SBOM project name was set.") + endif() + + string(TOLOWER "${project_name}" repo_project_name_lowercase) + set(${out_var} "${repo_project_name_lowercase}" PARENT_SCOPE) +endfunction() + # Get a spdx id to reference an external document. function(_qt_internal_sbom_get_external_document_ref_spdx_id repo_name out_var) set(${out_var} "DocumentRef-${repo_name}" PARENT_SCOPE) diff --git a/cmake/QtSbomHelpers.cmake b/cmake/QtSbomHelpers.cmake index 340354a759b..c46740b5acc 100644 --- a/cmake/QtSbomHelpers.cmake +++ b/cmake/QtSbomHelpers.cmake @@ -22,3 +22,12 @@ endfunction() function(qt_find_package_extend_sbom) _qt_find_package_extend_sbom(${ARGN}) endfunction() + +function(qt_internal_sbom_begin_qt_repo_project) + _qt_internal_sbom_begin_qt_repo_project(${ARGN}) +endfunction() + +function(qt_internal_sbom_end_qt_repo_project) + _qt_internal_sbom_end_qt_repo_project(${ARGN}) +endfunction() +