From ce0d893025ead7131be2f3b7f8115039ddb02fa6 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 13 Jan 2025 15:30:15 +0100 Subject: [PATCH] CMake: Decouple Qt specific handling from SBOM implementation The SBOM functions so far had a lot of Qt-specific logic inside them. Decouple this logic into separate Qt-specific functions or explicitly guard the code with Qt-specific handling options, to prepare for a cleaner SBOM public API. The generic functions then call the Qt-specific ones if various internal options are set. This approach is used, rather than directly passing values to the generic functions because: - we have cases where we need to recursively pass the values all the way down to all recursively created attribution targets - some of the logic needs to know about values before and after qt processing, and this could be achieved with something like lambdas but it's not worth the complexity Task-number: QTBUG-122899 Change-Id: I4399c41f4d976f20b16a0bb0c674d4f07ee1ccd4 Reviewed-by: Joerg Bornemann (cherry picked from commit f1ac316191c010b1389f6f3549c9f0b4424b9936) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 59a571c75dbbe3cd425629ad309bdf143f0616de) --- cmake/Qt3rdPartyLibraryHelpers.cmake | 2 +- cmake/QtAppHelpers.cmake | 2 +- cmake/QtBuildHelpers.cmake | 1 + cmake/QtModuleHelpers.cmake | 2 +- cmake/QtPluginHelpers.cmake | 2 +- cmake/QtPublicSbomAttributionHelpers.cmake | 18 + cmake/QtPublicSbomHelpers.cmake | 308 ++++++++--------- cmake/QtPublicSbomPurlHelpers.cmake | 107 ++---- cmake/QtPublicSbomQtEntityHelpers.cmake | 375 +++++++++++++++++++++ cmake/QtSbomHelpers.cmake | 41 ++- cmake/QtToolHelpers.cmake | 2 +- 11 files changed, 611 insertions(+), 249 deletions(-) create mode 100644 cmake/QtPublicSbomQtEntityHelpers.cmake diff --git a/cmake/Qt3rdPartyLibraryHelpers.cmake b/cmake/Qt3rdPartyLibraryHelpers.cmake index a727cdad06e..04a2d047842 100644 --- a/cmake/Qt3rdPartyLibraryHelpers.cmake +++ b/cmake/Qt3rdPartyLibraryHelpers.cmake @@ -379,7 +379,7 @@ function(qt_internal_add_3rdparty_library target) ${__qt_internal_sbom_multi_args} ) - _qt_internal_extend_sbom(${target} ${sbom_args}) + qt_internal_extend_qt_entity_sbom(${target} ${sbom_args}) endif() qt_add_list_file_finalizer(qt_internal_finalize_3rdparty_library ${target}) diff --git a/cmake/QtAppHelpers.cmake b/cmake/QtAppHelpers.cmake index d0ecf4e8e6d..00613275416 100644 --- a/cmake/QtAppHelpers.cmake +++ b/cmake/QtAppHelpers.cmake @@ -154,7 +154,7 @@ function(qt_internal_add_app target) ${__qt_internal_sbom_multi_args} ) - _qt_internal_extend_sbom(${target} ${sbom_args}) + qt_internal_extend_qt_entity_sbom(${target} ${sbom_args}) endif() qt_add_list_file_finalizer(qt_internal_finalize_app ${target}) diff --git a/cmake/QtBuildHelpers.cmake b/cmake/QtBuildHelpers.cmake index 5022f6911f2..c33f63a4f05 100644 --- a/cmake/QtBuildHelpers.cmake +++ b/cmake/QtBuildHelpers.cmake @@ -298,6 +298,7 @@ function(qt_internal_get_qt_build_public_helpers out_var) QtPublicSbomOpsHelpers QtPublicSbomPurlHelpers QtPublicSbomPythonHelpers + QtPublicSbomQtEntityHelpers QtPublicSbomSystemDepHelpers QtPublicTargetHelpers QtPublicTestHelpers diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake index 198a8a5ed9f..5dbda3a1fb3 100644 --- a/cmake/QtModuleHelpers.cmake +++ b/cmake/QtModuleHelpers.cmake @@ -976,7 +976,7 @@ set(QT_ALLOW_MISSING_TOOLS_PACKAGES TRUE)") ${__qt_internal_sbom_multi_args} ) - _qt_internal_extend_sbom(${target} ${sbom_args}) + qt_internal_extend_qt_entity_sbom(${target} ${sbom_args}) endif() qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${arg_NO_PRIVATE_MODULE}) diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake index fc036cf6a54..90da6fe5b13 100644 --- a/cmake/QtPluginHelpers.cmake +++ b/cmake/QtPluginHelpers.cmake @@ -443,7 +443,7 @@ function(qt_internal_add_plugin target) ${__qt_internal_sbom_multi_args} ) - _qt_internal_extend_sbom(${target} ${sbom_args}) + qt_internal_extend_qt_entity_sbom(${target} ${sbom_args}) endif() qt_add_list_file_finalizer(qt_finalize_plugin ${target} ${finalizer_extra_args}) diff --git a/cmake/QtPublicSbomAttributionHelpers.cmake b/cmake/QtPublicSbomAttributionHelpers.cmake index 142be7dce27..ab210869f1a 100644 --- a/cmake/QtPublicSbomAttributionHelpers.cmake +++ b/cmake/QtPublicSbomAttributionHelpers.cmake @@ -166,6 +166,24 @@ function(_qt_internal_sbom_handle_qt_attribution_files out_prefix_outer) set(sbom_args "") + # Always propagate the package supplier, because we assume the supplier for 3rd + # party libs is the same as the current project supplier. + # Also propagate the internal qt entity type values like CPE, supplier, PURL + # handling options, attribution file values, if set. + _qt_internal_forward_function_args( + FORWARD_APPEND + FORWARD_PREFIX arg + FORWARD_OUT_VAR sbom_args + FORWARD_OPTIONS + USE_ATTRIBUTION_FILES + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_CPE + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_SUPPLIER + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL + __QT_INTERNAL_HANDLE_QT_ENTITY_ATTRIBUTION_FILES + FORWARD_SINGLE + SUPPLIER + ) + if(propagate_sbom_options_to_new_attribution_targets) # Filter out the attributtion options, they will be passed mnaually # depending on which file and index is currently being processed. diff --git a/cmake/QtPublicSbomHelpers.cmake b/cmake/QtPublicSbomHelpers.cmake index 50574334b0e..ebfcd79f763 100644 --- a/cmake/QtPublicSbomHelpers.cmake +++ b/cmake/QtPublicSbomHelpers.cmake @@ -28,7 +28,8 @@ function(_qt_internal_sbom_begin_project) _qt_internal_sbom_setup_fake_deterministic_build() set(opt_args - QT_CPE + USE_GIT_VERSION + __QT_INTERNAL_HANDLE_QT_REPO ) set(single_args INSTALL_PREFIX @@ -82,9 +83,10 @@ function(_qt_internal_sbom_begin_project) _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) + set(repo_supplier_url "") if(arg_SUPPLIER_URL) set(repo_supplier_url "${arg_SUPPLIER_URL}") - else() + elseif(arg___QT_INTERNAL_HANDLE_QT_REPO) _qt_internal_sbom_get_default_supplier_url(repo_supplier_url) endif() @@ -95,7 +97,7 @@ function(_qt_internal_sbom_begin_project) set(QT_SBOM_GIT_HASH "") # empty on purpose, no source of info set(QT_SBOM_GIT_HASH_SHORT "") # empty on purpose, no source of info set(non_git_version "${arg_VERSION}") - else() + elseif(arg_USE_GIT_VERSION) # Query git version info. _qt_internal_find_git_package() _qt_internal_query_git_version( @@ -177,19 +179,19 @@ function(_qt_internal_sbom_begin_project) if(arg_COPYRIGHTS) list(JOIN arg_COPYRIGHTS "\n" arg_COPYRIGHTS) set(repo_copyright "${arg_COPYRIGHTS}") - else() + elseif(arg___QT_INTERNAL_HANDLE_QT_REPO) _qt_internal_sbom_get_default_qt_copyright_header(repo_copyright) endif() if(arg_SUPPLIER) set(repo_supplier "${arg_SUPPLIER}") - else() + elseif(arg___QT_INTERNAL_HANDLE_QT_REPO) _qt_internal_sbom_get_default_supplier(repo_supplier) endif() if(arg_CPE) set(qt_cpe "${arg_CPE}") - elseif(arg_QT_CPE) + elseif(arg___QT_INTERNAL_HANDLE_QT_REPO) _qt_internal_sbom_get_cpe_qt_repo(qt_cpe) else() set(qt_cpe "") @@ -197,17 +199,19 @@ function(_qt_internal_sbom_begin_project) if(arg_DOWNLOAD_LOCATION) set(download_location "${arg_DOWNLOAD_LOCATION}") - else() + elseif(arg___QT_INTERNAL_HANDLE_QT_REPO) _qt_internal_sbom_get_qt_repo_source_download_location(download_location) endif() set(project_comment "") - _qt_internal_get_configure_line(configure_line) - if(configure_line) - set(configure_line_comment - "\n${repo_project_name_lowercase} was configured with:\n ${configure_line}\n") - string(APPEND project_comment "${configure_line_comment}") + if(arg___QT_INTERNAL_HANDLE_QT_REPO) + _qt_internal_get_configure_line(configure_line) + if(configure_line) + set(configure_line_comment + "\n${repo_project_name_lowercase} was configured with:\n ${configure_line}\n") + string(APPEND project_comment "${configure_line_comment}") + endif() endif() _qt_internal_sbom_begin_project_generate( @@ -246,7 +250,7 @@ function(_qt_internal_sbom_begin_project) # Collect project licenses. set(license_dirs "") - if(EXISTS "${PROJECT_SOURCE_DIR}/LICENSES") + if(arg___QT_INTERNAL_HANDLE_QT_REPO AND EXISTS "${PROJECT_SOURCE_DIR}/LICENSES") list(APPEND license_dirs "${PROJECT_SOURCE_DIR}/LICENSES") endif() @@ -433,7 +437,8 @@ function(_qt_internal_sbom_begin_qt_repo_project) _qt_internal_sbom_begin_project( INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}" - QT_CPE + USE_GIT_VERSION + __QT_INTERNAL_HANDLE_QT_REPO ${sbom_project_args} ) endfunction() @@ -496,7 +501,9 @@ endmacro() # Helper to get the purl variant option names that should be recongized by sbom functions like # _qt_internal_sbom_add_target. macro(_qt_internal_get_sbom_purl_add_target_options opt_args single_args multi_args) - set(${opt_args} "") + set(${opt_args} + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL + ) set(${single_args} "") set(${multi_args} PURL_QT_ARGS @@ -543,6 +550,14 @@ macro(_qt_internal_get_sbom_add_target_common_options opt_args single_args multi NO_DEFAULT_QT_SUPPLIER SBOM_INCOMPLETE_3RD_PARTY_DEPENDENCIES IS_QT_3RD_PARTY_HEADER_MODULE + USE_ATTRIBUTION_FILES + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PACKAGE_VERSION + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_SUPPLIER + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_DOWNLOAD_LOCATION + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_LICENSE + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_COPYRIGHTS + __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_CPE + __QT_INTERNAL_HANDLE_QT_ENTITY_ATTRIBUTION_FILES ) set(${single_args} PACKAGE_VERSION @@ -682,38 +697,40 @@ function(_qt_internal_sbom_add_target target) OUT_VAR package_spdx_id ) - set(attribution_args - PARENT_TARGET "${target}" - ) - - if(is_qt_entity_type) - list(APPEND attribution_args CREATE_SBOM_FOR_EACH_ATTRIBUTION) - endif() - - # Forward the sbom specific options when handling attribution files because those might - # create other sbom targets that need to inherit the parent ones. - _qt_internal_get_sbom_specific_options(sbom_opt_args sbom_single_args sbom_multi_args) - - _qt_internal_forward_function_args( - FORWARD_APPEND - FORWARD_PREFIX arg - FORWARD_OUT_VAR attribution_args - FORWARD_OPTIONS - ${sbom_opt_args} - FORWARD_SINGLE - ${sbom_single_args} - FORWARD_MULTI - ${sbom_multi_args} - ) - - if(NOT arg_NO_CURRENT_DIR_ATTRIBUTION - AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/qt_attribution.json") - list(APPEND attribution_args - ATTRIBUTION_FILE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/qt_attribution.json" + if(arg_USE_ATTRIBUTION_FILES) + set(attribution_args + PARENT_TARGET "${target}" ) - endif() - _qt_internal_sbom_handle_qt_attribution_files(qa ${attribution_args}) + if(is_qt_entity_type AND arg___QT_INTERNAL_HANDLE_QT_ENTITY_ATTRIBUTION_FILES) + list(APPEND attribution_args CREATE_SBOM_FOR_EACH_ATTRIBUTION) + endif() + + # Forward the sbom specific options when handling attribution files because those might + # create other sbom targets that need to inherit the parent ones. + _qt_internal_get_sbom_specific_options(sbom_opt_args sbom_single_args sbom_multi_args) + + _qt_internal_forward_function_args( + FORWARD_APPEND + FORWARD_PREFIX arg + FORWARD_OUT_VAR attribution_args + FORWARD_OPTIONS + ${sbom_opt_args} + FORWARD_SINGLE + ${sbom_single_args} + FORWARD_MULTI + ${sbom_multi_args} + ) + + if(NOT arg_NO_CURRENT_DIR_ATTRIBUTION + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/qt_attribution.json") + list(APPEND attribution_args + ATTRIBUTION_FILE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/qt_attribution.json" + ) + endif() + + _qt_internal_sbom_handle_qt_attribution_files(qa ${attribution_args}) + endif() # Collect license expressions, but in most cases, each expression needs to be abided, so we # AND the accumulated license expressions. @@ -723,59 +740,21 @@ function(_qt_internal_sbom_add_target target) set(license_expression "${arg_LICENSE_EXPRESSION}") endif() - # For Qt entities, we have some special handling. - if(is_qt_entity_type AND NOT arg_NO_DEFAULT_QT_LICENSE AND NOT arg_QT_LICENSE_ID) - if(arg_TYPE STREQUAL "QT_TOOL" OR arg_TYPE STREQUAL "QT_APP") - if(QT_SBOM_DEFAULT_QT_LICENSE_ID_EXECUTABLES - AND NOT arg_NO_DEFAULT_QT_LICENSE_ID_EXECUTABLES) - # A repo might contain only the "gpl3" license variant as the default for all - # executables, so allow setting it at the repo level to avoid having to repeat it - # for each target. - _qt_internal_sbom_get_spdx_license_expression( - "${QT_SBOM_DEFAULT_QT_LICENSE_ID_EXECUTABLES}" qt_license_expression) - else() - # For tools and apps, we use the gpl exception variant by default. - _qt_internal_sbom_get_spdx_license_expression("QT_COMMERCIAL_OR_GPL3_WITH_EXCEPTION" - qt_license_expression) - endif() - - elseif(QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES - AND NOT arg_NO_DEFAULT_QT_LICENSE_ID_LIBRARIES) - # A repo might contain only the "gpl3" license variant as the default for all modules - # and plugins, so allow setting it at the repo level to avoid having to repeat it - # for each target. - _qt_internal_sbom_get_spdx_license_expression( - "${QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES}" qt_license_expression) - - else() - # Otherwise, for modules and plugins we use the default qt license. - _qt_internal_sbom_get_spdx_license_expression("QT_DEFAULT" qt_license_expression) + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_LICENSE) + _qt_internal_sbom_forward_sbom_add_target_options(sbom_add_target_args) + _qt_internal_sbom_handle_qt_entity_license_expression(${target} ${sbom_add_target_args} + OUT_VAR qt_entity_license_expression) + if(qt_entity_license_expression) + _qt_internal_sbom_join_two_license_ids_with_op( + "${license_expression}" "AND" "${qt_entity_license_expression}" + license_expression) endif() - - _qt_internal_sbom_join_two_license_ids_with_op( - "${license_expression}" "AND" "${qt_license_expression}" - license_expression) - endif() - - # Some Qt entities might request a specific license from the subset that we usually use. - if(arg_QT_LICENSE_ID) - _qt_internal_sbom_get_spdx_license_expression("${arg_QT_LICENSE_ID}" - requested_license_expression) - _qt_internal_sbom_join_two_license_ids_with_op( - "${license_expression}" "AND" "${requested_license_expression}" - license_expression) - endif() - - # Allow setting a license expression string per directory scope via a variable. - if(is_qt_entity_type AND QT_SBOM_LICENSE_EXPRESSION AND NOT arg_NO_DEFAULT_DIRECTORY_QT_LICENSE) - set(qt_license_expression "${QT_SBOM_LICENSE_EXPRESSION}") - _qt_internal_sbom_join_two_license_ids_with_op( - "${license_expression}" "AND" "${qt_license_expression}" - license_expression) endif() # Read a license expression from the attribution json file. - if(qa_license_id AND NOT arg_NO_ATTRIBUTION_LICENSE_ID) + if(arg_USE_ATTRIBUTION_FILES + AND qa_license_id + AND NOT arg_NO_ATTRIBUTION_LICENSE_ID) if(NOT qa_license_id MATCHES "urn:dje:license") _qt_internal_sbom_join_two_license_ids_with_op( "${license_expression}" "AND" "${qa_license_id}" @@ -794,7 +773,7 @@ function(_qt_internal_sbom_add_target target) list(APPEND project_package_options LICENSE_CONCLUDED "${license_expression}") # For qt entities we know the license we provide, so we mark it as declared as well. - if(is_qt_entity_type) + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_LICENSE AND is_qt_entity_type) list(APPEND project_package_options LICENSE_DECLARED "${license_expression}") endif() endif() @@ -804,13 +783,17 @@ function(_qt_internal_sbom_add_target target) if(arg_COPYRIGHTS) list(APPEND copyrights "${arg_COPYRIGHTS}") endif() - if(is_qt_entity_type AND NOT arg_NO_DEFAULT_QT_COPYRIGHTS) - _qt_internal_sbom_get_default_qt_copyright_header(qt_default_copyright) - if(qt_default_copyright) - list(APPEND copyrights "${qt_default_copyright}") + + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_COPYRIGHTS) + _qt_internal_sbom_forward_sbom_add_target_options(sbom_add_target_args) + _qt_internal_sbom_handle_qt_entity_copyrights(${target} ${sbom_add_target_args} + OUT_VAR qt_copyrights) + if(qt_copyrights) + list(APPEND copyrights ${qt_copyrights}) endif() endif() - if(qa_copyrights) + + if(arg_USE_ATTRIBUTION_FILES AND qa_copyrights) list(APPEND copyrights "${qa_copyrights}") endif() if(copyrights) @@ -821,11 +804,19 @@ function(_qt_internal_sbom_add_target target) set(package_version "") if(arg_PACKAGE_VERSION) set(package_version "${arg_PACKAGE_VERSION}") - elseif(is_qt_entity_type AND NOT arg_NO_DEFAULT_QT_PACKAGE_VERSION) - _qt_internal_sbom_get_default_qt_package_version(package_version) - elseif(qa_version) + elseif(arg_USE_ATTRIBUTION_FILES AND qa_version) set(package_version "${qa_version}") endif() + + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PACKAGE_VERSION) + _qt_internal_sbom_forward_sbom_add_target_options(sbom_add_target_args) + _qt_internal_sbom_handle_qt_entity_package_version(${target} ${sbom_add_target_args} + OUT_VAR qt_entity_package_version) + if(qt_entity_package_version) + set(package_version "${qt_entity_package_version}") + endif() + endif() + if(package_version) list(APPEND project_package_options VERSION "${package_version}") endif() @@ -833,10 +824,17 @@ function(_qt_internal_sbom_add_target target) set(supplier "") if(arg_SUPPLIER) set(supplier "${arg_SUPPLIER}") - elseif((is_qt_entity_type OR is_qt_3rd_party_entity_type) - AND NOT arg_NO_DEFAULT_QT_SUPPLIER) - _qt_internal_sbom_get_default_supplier(supplier) endif() + + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_SUPPLIER) + _qt_internal_sbom_forward_sbom_add_target_options(sbom_add_target_args) + _qt_internal_sbom_handle_qt_entity_supplier(${target} ${sbom_add_target_args} + OUT_VAR qt_entity_supplier) + if(qt_entity_supplier) + set(supplier "${qt_entity_supplier}") + endif() + endif() + if(supplier) list(APPEND project_package_options SUPPLIER "Organization: ${supplier}") endif() @@ -844,15 +842,28 @@ function(_qt_internal_sbom_add_target target) set(download_location "") if(arg_DOWNLOAD_LOCATION) set(download_location "${arg_DOWNLOAD_LOCATION}") - elseif(is_qt_entity_type) - _qt_internal_sbom_get_qt_repo_source_download_location(download_location) - elseif(arg_TYPE STREQUAL "QT_THIRD_PARTY_MODULE" OR arg_TYPE STREQUAL "QT_THIRD_PARTY_SOURCES") + endif() + + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_DOWNLOAD_LOCATION) + _qt_internal_sbom_forward_sbom_add_target_options(sbom_add_target_args) + _qt_internal_sbom_handle_qt_entity_download_location(${target} ${sbom_add_target_args} + OUT_VAR qt_entity_download_location) + if(qt_entity_download_location) + set(download_location "${qt_entity_download_location}") + endif() + endif() + + if(arg_USE_ATTRIBUTION_FILES + AND (arg_TYPE STREQUAL "QT_THIRD_PARTY_MODULE" + OR arg_TYPE STREQUAL "QT_THIRD_PARTY_SOURCES")) if(qa_download_location) set(download_location "${qa_download_location}") elseif(qa_homepage) set(download_location "${qa_homepage}") endif() - elseif(arg_TYPE STREQUAL "SYSTEM_LIBRARY") + endif() + + if(arg_TYPE STREQUAL "SYSTEM_LIBRARY") # Try to get package url that was set using CMake's set_package_properties function. # Relies on querying the internal global property name that CMake sets in its # implementation. @@ -860,7 +871,9 @@ function(_qt_internal_sbom_add_target target) if(target_url) set(download_location "${target_url}") endif() - if(NOT download_location AND qa_download_location) + if(NOT download_location + AND arg_USE_ATTRIBUTION_FILES + AND qa_download_location) set(download_location "${qa_download_location}") endif() endif() @@ -872,10 +885,10 @@ function(_qt_internal_sbom_add_target target) _qt_internal_sbom_get_package_purpose("${arg_TYPE}" package_purpose) list(APPEND project_package_options PURPOSE "${package_purpose}") - set(cpe_args "") + set(cpe_values "") if(arg_CPE) - list(APPEND cpe_args CPE "${arg_CPE}") + list(APPEND cpe_values "${arg_CPE}") endif() if(arg_CPE_VENDOR AND arg_CPE_PRODUCT) @@ -883,27 +896,30 @@ function(_qt_internal_sbom_add_target target) VENDOR "${arg_CPE_VENDOR}" PRODUCT "${arg_CPE_PRODUCT}" VERSION "${package_version}") - list(APPEND cpe_args CPE "${custom_cpe}") + list(APPEND cpe_values "${custom_cpe}") endif() - if(qa_cpes) + if(arg_USE_ATTRIBUTION_FILES AND qa_cpes) _qt_internal_sbom_replace_qa_placeholders( VALUES ${qa_cpes} VERSION "${package_version}" OUT_VAR qa_cpes_replaced ) - list(APPEND cpe_args CPE "${qa_cpes_replaced}") + list(APPEND cpe_values "${qa_cpes_replaced}") endif() - # Add the qt-specific CPE if the target is a Qt entity type, or if it's a 3rd party entity type - # without any CPE specified. - if(is_qt_entity_type OR (is_qt_3rd_party_entity_type AND NOT cpe_args)) - _qt_internal_sbom_compute_security_cpe_for_qt(cpe_list) - list(APPEND cpe_args CPE "${cpe_list}") + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_CPE) + _qt_internal_sbom_forward_sbom_add_target_options(sbom_add_target_args) + _qt_internal_sbom_handle_qt_entity_cpe(${target} ${sbom_add_target_args} + CPE "${cpe_values}" + OUT_VAR qt_cpe_list) + if(qt_cpe_list) + list(APPEND cpe_values ${qt_cpe_list}) + endif() endif() - if(cpe_args) - list(APPEND project_package_options ${cpe_args}) + if(cpe_values) + list(APPEND project_package_options CPE ${cpe_values}) endif() # Assemble arguments to forward to the function that handles purl options. @@ -934,7 +950,7 @@ function(_qt_internal_sbom_add_target target) list(APPEND purl_args IS_QT_ENTITY_TYPE) endif() - if(qa_purls) + if(arg_USE_ATTRIBUTION_FILES AND qa_purls) _qt_internal_sbom_replace_qa_placeholders( VALUES ${qa_purls} VERSION "${package_version}" @@ -951,10 +967,11 @@ function(_qt_internal_sbom_add_target target) list(APPEND project_package_options ${purl_package_options}) endif() - if(is_qt_3rd_party_entity_type - OR arg_TYPE STREQUAL "SYSTEM_LIBRARY" - OR arg_TYPE STREQUAL "THIRD_PARTY_LIBRARY" - OR arg_TYPE STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES" + if(arg_USE_ATTRIBUTION_FILES + AND (is_qt_3rd_party_entity_type + OR arg_TYPE STREQUAL "SYSTEM_LIBRARY" + OR arg_TYPE STREQUAL "THIRD_PARTY_LIBRARY" + OR arg_TYPE STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES") ) if(qa_attribution_name) string(APPEND package_comment " Name: ${qa_attribution_name}\n") @@ -1664,41 +1681,6 @@ function(_qt_internal_sbom_get_package_purpose type out_purpose) set(${out_purpose} "${package_purpose}" PARENT_SCOPE) endfunction() -# Get the default qt copyright. -function(_qt_internal_sbom_get_default_qt_copyright_header out_var) - set(${out_var} - "Copyright (C) The Qt Company Ltd. and other contributors." - PARENT_SCOPE) -endfunction() - -# Get the default qt package version. -function(_qt_internal_sbom_get_default_qt_package_version out_var) - set(${out_var} "${QT_REPO_MODULE_VERSION}" PARENT_SCOPE) -endfunction() - -# Get the default qt supplier. -function(_qt_internal_sbom_get_default_supplier out_var) - set(${out_var} "TheQtCompany" PARENT_SCOPE) -endfunction() - -# Get the default qt supplier url. -function(_qt_internal_sbom_get_default_supplier_url out_var) - set(${out_var} "https://qt.io" PARENT_SCOPE) -endfunction() - -# Get the default qt download location. -# If git info is available, includes the hash. -function(_qt_internal_sbom_get_qt_repo_source_download_location out_var) - _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) - set(download_location "git://code.qt.io/qt/${repo_project_name_lowercase}.git") - - _qt_internal_sbom_get_git_version_vars() - if(QT_SBOM_GIT_HASH) - string(APPEND download_location "@${QT_SBOM_GIT_HASH}") - endif() - set(${out_var} "${download_location}" PARENT_SCOPE) -endfunction() - # Queries the current project git version variables and sets them in the parent scope. function(_qt_internal_sbom_get_git_version_vars) get_cmake_property(QT_SBOM_GIT_VERSION QT_SBOM_GIT_VERSION) diff --git a/cmake/QtPublicSbomPurlHelpers.cmake b/cmake/QtPublicSbomPurlHelpers.cmake index dc5efc5361f..4da0a9fa8cd 100644 --- a/cmake/QtPublicSbomPurlHelpers.cmake +++ b/cmake/QtPublicSbomPurlHelpers.cmake @@ -100,46 +100,24 @@ function(_qt_internal_sbom_handle_purl_values target) _qt_internal_sbom_get_git_version_vars() - set(third_party_types - QT_THIRD_PARTY_MODULE - QT_THIRD_PARTY_SOURCES - ) - - if(arg_IS_QT_ENTITY_TYPE) - # Qt entities have two purls by default, a QT generic one and a MIRROR hosted on github. - list(APPEND purl_variants MIRROR QT) - elseif(arg_TYPE IN_LIST third_party_types) - # Third party libraries vendored in Qt also have at least two purls, like regular Qt - # libraries, but might also have an upstream one. - - # The order in which the purls are generated matters for tools that consume the SBOM. Some - # tools can only handle one PURL per package, so the first one should be the important one. - # For now, I deem that the upstream one if present. Otherwise the github mirror. - if(arg_PURL_3RDPARTY_UPSTREAM_ARGS) - list(APPEND purl_variants 3RDPARTY_UPSTREAM) - endif() - - list(APPEND purl_variants MIRROR QT) - else() - # If handling another entity type, handle based on whether any of the purl arguments are - # set. - set(known_purl_variants QT MIRROR 3RDPARTY_UPSTREAM) - foreach(known_purl_variant IN LISTS known_purl_variants) - if(arg_PURL_${known_purl_variant}_ARGS) - list(APPEND purl_variants ${known_purl_variant}) - endif() - endforeach() - endif() - - if(arg_IS_QT_ENTITY_TYPE - OR arg_TYPE STREQUAL "QT_THIRD_PARTY_MODULE" - OR arg_TYPE STREQUAL "QT_THIRD_PARTY_SOURCES" + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL) + _qt_internal_sbom_forward_purl_handling_options(purl_handling_args) + _qt_internal_sbom_handle_qt_entity_purl_variants(${purl_handling_args} + OUT_VAR_VARIANTS qt_purl_variants + OUT_VAR_IS_QT_PURL_ENTITY_TYPE is_qt_purl_entity_type ) - set(is_qt_purl_entity_type TRUE) - else() - set(is_qt_purl_entity_type FALSE) + if(qt_purl_variants) + list(APPEND purl_variants "${qt_purl_variants}") + endif() endif() + set(known_purl_variants QT MIRROR 3RDPARTY_UPSTREAM) + foreach(known_purl_variant IN LISTS known_purl_variants) + if(arg_PURL_${known_purl_variant}_ARGS AND NOT known_purl_variant IN_LIST purl_variants) + list(APPEND purl_variants ${known_purl_variant}) + endif() + endforeach() + _qt_internal_get_sbom_purl_parsing_options(purl_opt_args purl_single_args purl_multi_args) set(project_package_options "") @@ -161,7 +139,12 @@ function(_qt_internal_sbom_handle_purl_values target) # We want to create a purl either if it's one of Qt's entities and one of it's default # purl types, or if custom args were specified. set(consider_purl_processing FALSE) - if((purl_args_available OR is_qt_purl_entity_type) AND NOT arg_NO_PURL) + + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL AND is_qt_purl_entity_type) + set(purl_args_available TRUE) + endif() + + if(purl_args_available AND NOT arg_NO_PURL) set(consider_purl_processing TRUE) endif() @@ -191,48 +174,18 @@ function(_qt_internal_sbom_handle_purl_values target) ) # Qt entity types get special treatment purl. - if(is_qt_purl_entity_type AND NOT arg_NO_DEFAULT_QT_PURL AND - (purl_variant STREQUAL "QT" OR purl_variant STREQUAL "MIRROR")) - _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) - - # Add a vcs_url to the generic QT variant. - if(purl_variant STREQUAL "QT") - set(entity_vcs_url_version_option "") - # Can be empty. - if(QT_SBOM_GIT_HASH_SHORT) - set(entity_vcs_url_version_option VERSION "${QT_SBOM_GIT_HASH_SHORT}") - endif() - - _qt_internal_sbom_get_qt_entity_vcs_url(${target} - REPO_NAME "${repo_project_name_lowercase}" - ${entity_vcs_url_version_option} - OUT_VAR vcs_url) - list(APPEND purl_args PURL_QUALIFIERS "vcs_url=${vcs_url}") + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL) + _qt_internal_sbom_forward_purl_handling_options(purl_handling_args) + if(is_qt_purl_entity_type) + list(APPEND purl_handling_args IS_QT_PURL_ENTITY_TYPE) endif() - - # Add the subdirectory path where the target was created as a custom qualifier. - _qt_internal_sbom_get_qt_entity_repo_source_dir(${target} OUT_VAR sub_path) - if(sub_path) - list(APPEND purl_args PURL_SUBPATH "${sub_path}") - endif() - - # Add the target name as a custom qualifer. - list(APPEND purl_args PURL_QUALIFIERS "library_name=${target}") - - # Can be empty. - if(QT_SBOM_GIT_HASH_SHORT) - list(APPEND purl_args VERSION "${QT_SBOM_GIT_HASH_SHORT}") - endif() - - # Get purl args the Qt entity type, taking into account defaults. - _qt_internal_sbom_get_qt_entity_purl_args(${target} - NAME "${repo_project_name_lowercase}-${target}" - REPO_NAME "${repo_project_name_lowercase}" - SUPPLIER "${arg_SUPPLIER}" + _qt_internal_sbom_handle_qt_entity_purl("${target}" ${purl_handling_args} PURL_VARIANT "${purl_variant}" - ${purl_args} - OUT_VAR purl_args + OUT_PURL_ARGS qt_purl_args ) + if(qt_purl_args) + list(APPEND purl_args "${qt_purl_args}") + endif() endif() _qt_internal_sbom_assemble_purl(${target} diff --git a/cmake/QtPublicSbomQtEntityHelpers.cmake b/cmake/QtPublicSbomQtEntityHelpers.cmake new file mode 100644 index 00000000000..51a7bc1cc15 --- /dev/null +++ b/cmake/QtPublicSbomQtEntityHelpers.cmake @@ -0,0 +1,375 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Helper macro to prepare forwarding all set sbom options to some other function. +# Expects the options names to be set in the parent scope by calling +# _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) +macro(_qt_internal_sbom_forward_sbom_add_target_options args_var_name) + if(NOT opt_args) + message(FATAL_ERROR + "Expected opt_args to be set by _qt_internal_get_sbom_add_target_options") + endif() + if(NOT single_args) + message(FATAL_ERROR + "Expected single_args to be set by _qt_internal_get_sbom_add_target_options") + endif() + if(NOT multi_args) + message(FATAL_ERROR + "Expected multi_args to be set by _qt_internal_get_sbom_add_target_options") + endif() + _qt_internal_forward_function_args( + FORWARD_PREFIX arg + FORWARD_OUT_VAR ${args_var_name} + FORWARD_OPTIONS + ${opt_args} + FORWARD_SINGLE + ${single_args} + FORWARD_MULTI + ${multi_args} + ) +endmacro() + +# Helper function to add a default supplier for a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_supplier target) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND single_args OUT_VAR) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_is_qt_entity_type("${arg_TYPE}" is_qt_entity_type) + _qt_internal_sbom_is_qt_3rd_party_entity_type("${arg_TYPE}" is_qt_3rd_party_entity_type) + + set(supplier "") + if(NOT arg_SUPPLIER + AND (is_qt_entity_type OR is_qt_3rd_party_entity_type) + AND NOT arg_NO_DEFAULT_QT_SUPPLIER) + _qt_internal_sbom_get_default_supplier(supplier) + endif() + + if(supplier) + set(${arg_OUT_VAR} "${supplier}" PARENT_SCOPE) + endif() +endfunction() + +# Helper function to add a default package for a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_package_version target) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND single_args OUT_VAR) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_is_qt_entity_type("${arg_TYPE}" is_qt_entity_type) + + set(package_version "") + if(NOT arg_PACKAGE_VERSION + AND is_qt_entity_type + AND NOT arg_NO_DEFAULT_QT_PACKAGE_VERSION) + _qt_internal_sbom_get_default_qt_package_version(package_version) + endif() + + if(package_version) + set(${arg_OUT_VAR} "${package_version}" PARENT_SCOPE) + endif() +endfunction() + +# Helper function to add a default repo download location for a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_download_location target) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND single_args OUT_VAR) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_is_qt_entity_type("${arg_TYPE}" is_qt_entity_type) + + set(download_location "") + if(NOT arg_DOWNLOAD_LOCATION AND is_qt_entity_type) + _qt_internal_sbom_get_qt_repo_source_download_location(download_location) + endif() + + if(download_location) + set(${arg_OUT_VAR} "${download_location}" PARENT_SCOPE) + endif() +endfunction() + +# Helper function to add a default license expression for a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_license_expression target) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND single_args OUT_VAR) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_is_qt_entity_type("${arg_TYPE}" is_qt_entity_type) + + set(license_expression "") + + # For Qt entities, we have some special handling. + if(is_qt_entity_type AND NOT arg_NO_DEFAULT_QT_LICENSE AND NOT arg_QT_LICENSE_ID) + if(arg_TYPE STREQUAL "QT_TOOL" OR arg_TYPE STREQUAL "QT_APP") + if(QT_SBOM_DEFAULT_QT_LICENSE_ID_EXECUTABLES + AND NOT arg_NO_DEFAULT_QT_LICENSE_ID_EXECUTABLES) + # A repo might contain only the "gpl3" license variant as the default for all + # executables, so allow setting it at the repo level to avoid having to repeat it + # for each target. + _qt_internal_sbom_get_spdx_license_expression( + "${QT_SBOM_DEFAULT_QT_LICENSE_ID_EXECUTABLES}" license_expression) + else() + # For tools and apps, we use the gpl exception variant by default. + _qt_internal_sbom_get_spdx_license_expression("QT_COMMERCIAL_OR_GPL3_WITH_EXCEPTION" + license_expression) + endif() + + elseif(QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES + AND NOT arg_NO_DEFAULT_QT_LICENSE_ID_LIBRARIES) + # A repo might contain only the "gpl3" license variant as the default for all modules + # and plugins, so allow setting it at the repo level to avoid having to repeat it + # for each target. + _qt_internal_sbom_get_spdx_license_expression( + "${QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES}" license_expression) + + else() + # Otherwise, for modules and plugins we use the default qt license. + _qt_internal_sbom_get_spdx_license_expression("QT_DEFAULT" license_expression) + endif() + endif() + + # Some Qt entities might request a specific license from the subset that we usually use. + if(arg_QT_LICENSE_ID) + _qt_internal_sbom_get_spdx_license_expression("${arg_QT_LICENSE_ID}" + requested_license_expression) + _qt_internal_sbom_join_two_license_ids_with_op( + "${license_expression}" "AND" "${requested_license_expression}" + license_expression) + endif() + + # Allow setting a license expression string per directory scope via a variable. + if(is_qt_entity_type AND QT_SBOM_LICENSE_EXPRESSION AND NOT arg_NO_DEFAULT_DIRECTORY_QT_LICENSE) + set(qt_license_expression "${QT_SBOM_LICENSE_EXPRESSION}") + _qt_internal_sbom_join_two_license_ids_with_op( + "${license_expression}" "AND" "${qt_license_expression}" + license_expression) + endif() + + if(license_expression) + set(${arg_OUT_VAR} "${license_expression}" PARENT_SCOPE) + endif() +endfunction() + +# Get the default qt copyright. +function(_qt_internal_sbom_get_default_qt_copyright_header out_var) + set(${out_var} + "Copyright (C) The Qt Company Ltd. and other contributors." + PARENT_SCOPE) +endfunction() + +# Helper function to add default copyrights for a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_copyrights target) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND single_args OUT_VAR) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_is_qt_entity_type("${arg_TYPE}" is_qt_entity_type) + + set(qt_default_copyright "") + if(is_qt_entity_type AND NOT arg_NO_DEFAULT_QT_COPYRIGHTS) + _qt_internal_sbom_get_default_qt_copyright_header(qt_default_copyright) + endif() + + if(qt_default_copyright) + set(${arg_OUT_VAR} "${qt_default_copyright}" PARENT_SCOPE) + endif() +endfunction() + +# Helper function to add default CPEs for a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_cpe target) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND single_args OUT_VAR) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_is_qt_entity_type("${arg_TYPE}" is_qt_entity_type) + _qt_internal_sbom_is_qt_3rd_party_entity_type("${arg_TYPE}" is_qt_3rd_party_entity_type) + + set(cpe_list "") + + # Add the qt-specific CPE if the target is a Qt entity type, or if it's a 3rd party entity type + # without any CPE specified. + if(is_qt_entity_type OR (is_qt_3rd_party_entity_type AND NOT arg_CPE)) + _qt_internal_sbom_compute_security_cpe_for_qt(cpe_list) + endif() + + if(cpe_list) + set(${arg_OUT_VAR} "${cpe_list}" PARENT_SCOPE) + endif() +endfunction() + +# Helper macro to prepare forwarding all set purl options to some other function. +# Expects the options names to be set in the parent scope by calling +# _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) +macro(_qt_internal_sbom_forward_purl_handling_options args_var_name) + if(NOT opt_args) + message(FATAL_ERROR + "Expected opt_args to be set by _qt_internal_get_sbom_purl_handling_options") + endif() + if(NOT single_args) + message(FATAL_ERROR + "Expected single_args to be set by _qt_internal_get_sbom_purl_handling_options") + endif() + if(NOT multi_args) + message(FATAL_ERROR + "Expected multi_args to be set by _qt_internal_get_sbom_purl_handling_options") + endif() + _qt_internal_forward_function_args( + FORWARD_PREFIX arg + FORWARD_OUT_VAR ${args_var_name} + FORWARD_OPTIONS + ${opt_args} + FORWARD_SINGLE + ${single_args} + FORWARD_MULTI + ${multi_args} + ) +endmacro() + +# Helper function to decide which purl variants to add for a qt entity. +function(_qt_internal_sbom_handle_qt_entity_purl_variants) + _qt_internal_get_sbom_purl_handling_options(opt_args single_args multi_args) + list(APPEND single_args + OUT_VAR # This is unused, but added by the calling function. + OUT_VAR_VARIANTS OUT_VAR_IS_QT_PURL_ENTITY_TYPE + ) + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set(third_party_types + QT_THIRD_PARTY_MODULE + QT_THIRD_PARTY_SOURCES + ) + + set(purl_variants "") + + if(arg_IS_QT_ENTITY_TYPE) + # Qt entities have two purls by default, a QT generic one and a MIRROR hosted on github. + list(APPEND purl_variants MIRROR QT) + elseif(arg_TYPE IN_LIST third_party_types) + # Third party libraries vendored in Qt also have at least two purls, like regular Qt + # libraries, but might also have an upstream one. + + # The order in which the purls are generated matters for tools that consume the SBOM. Some + # tools can only handle one PURL per package, so the first one should be the important one. + # For now, I deem that the upstream one if present. Otherwise the github mirror. + if(arg_PURL_3RDPARTY_UPSTREAM_ARGS) + list(APPEND purl_variants 3RDPARTY_UPSTREAM) + endif() + + list(APPEND purl_variants MIRROR QT) + endif() + + if(arg_IS_QT_ENTITY_TYPE + OR arg_TYPE STREQUAL "QT_THIRD_PARTY_MODULE" + OR arg_TYPE STREQUAL "QT_THIRD_PARTY_SOURCES") + set(is_qt_purl_entity_type TRUE) + else() + set(is_qt_purl_entity_type FALSE) + endif() + + if(purl_variants) + set(${arg_OUT_VAR_VARIANTS} "${purl_variants}" PARENT_SCOPE) + endif() + if(is_qt_purl_entity_type) + set(${arg_OUT_VAR_IS_QT_PURL_ENTITY_TYPE} "${is_qt_purl_entity_type}" PARENT_SCOPE) + endif() +endfunction() + +# Helper function to add purl values for a specific purl variant of a qt entity type. +function(_qt_internal_sbom_handle_qt_entity_purl target) + _qt_internal_get_sbom_purl_handling_options(opt_args single_args multi_args) + list(APPEND opt_args IS_QT_PURL_ENTITY_TYPE) + list(APPEND single_args + OUT_VAR # This is unused, but added by the calling function. + OUT_PURL_ARGS + PURL_VARIANT + ) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set(purl_args "") + + # Qt entity types get special treatment purl. + if(arg_IS_QT_PURL_ENTITY_TYPE AND NOT arg_NO_DEFAULT_QT_PURL AND + (arg_PURL_VARIANT STREQUAL "QT" OR arg_PURL_VARIANT STREQUAL "MIRROR")) + _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) + + # Add a vcs_url to the generic QT variant. + if(arg_PURL_VARIANT STREQUAL "QT") + set(entity_vcs_url_version_option "") + # Can be empty. + if(QT_SBOM_GIT_HASH_SHORT) + set(entity_vcs_url_version_option VERSION "${QT_SBOM_GIT_HASH_SHORT}") + endif() + + _qt_internal_sbom_get_qt_entity_vcs_url(${target} + REPO_NAME "${repo_project_name_lowercase}" + ${entity_vcs_url_version_option} + OUT_VAR vcs_url) + list(APPEND purl_args PURL_QUALIFIERS "vcs_url=${vcs_url}") + endif() + + # Add the subdirectory path where the target was created as a custom qualifier. + _qt_internal_sbom_get_qt_entity_repo_source_dir(${target} OUT_VAR sub_path) + if(sub_path) + list(APPEND purl_args PURL_SUBPATH "${sub_path}") + endif() + + # Add the target name as a custom qualifer. + list(APPEND purl_args PURL_QUALIFIERS "library_name=${target}") + + # Can be empty. + if(QT_SBOM_GIT_HASH_SHORT) + list(APPEND purl_args VERSION "${QT_SBOM_GIT_HASH_SHORT}") + endif() + + # Get purl args the Qt entity type, taking into account defaults. + _qt_internal_sbom_get_qt_entity_purl_args(${target} + NAME "${repo_project_name_lowercase}-${target}" + REPO_NAME "${repo_project_name_lowercase}" + SUPPLIER "${arg_SUPPLIER}" + PURL_VARIANT "${arg_PURL_VARIANT}" + ${purl_args} + OUT_VAR purl_args + ) + endif() + + if(purl_args) + set(${arg_OUT_PURL_ARGS} "${purl_args}" PARENT_SCOPE) + endif() +endfunction() + + +# Get the default qt package version. +function(_qt_internal_sbom_get_default_qt_package_version out_var) + set(${out_var} "${QT_REPO_MODULE_VERSION}" PARENT_SCOPE) +endfunction() + +# Get the default qt supplier. +function(_qt_internal_sbom_get_default_supplier out_var) + set(${out_var} "TheQtCompany" PARENT_SCOPE) +endfunction() + +# Get the default qt supplier url. +function(_qt_internal_sbom_get_default_supplier_url out_var) + set(${out_var} "https://qt.io" PARENT_SCOPE) +endfunction() + +# Get the default qt download location. +# If git info is available, includes the hash. +function(_qt_internal_sbom_get_qt_repo_source_download_location out_var) + _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) + set(download_location "git://code.qt.io/qt/${repo_project_name_lowercase}.git") + + _qt_internal_sbom_get_git_version_vars() + if(QT_SBOM_GIT_HASH) + string(APPEND download_location "@${QT_SBOM_GIT_HASH}") + endif() + set(${out_var} "${download_location}" PARENT_SCOPE) +endfunction() diff --git a/cmake/QtSbomHelpers.cmake b/cmake/QtSbomHelpers.cmake index f6d947cf01b..9edf356afd2 100644 --- a/cmake/QtSbomHelpers.cmake +++ b/cmake/QtSbomHelpers.cmake @@ -1,10 +1,15 @@ # Copyright (C) 2024 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -# For now these are simple internal forwarding wrappers for the public counterparts, which are -# meant to be used in qt repo CMakeLists.txt files. -function(qt_internal_add_sbom) - _qt_internal_add_sbom(${ARGN}) +# These internal sbom functions are meant to be used in qt repo CMakeLists.txt files. + +function(qt_internal_add_sbom target) + if(NOT QT_GENERATE_SBOM) + return() + endif() + + qt_internal_sbom_get_default_sbom_args("${target}" sbom_extra_args ${ARGN}) + _qt_internal_add_sbom(${target} ${ARGN} ${sbom_extra_args}) endfunction() function(qt_internal_extend_sbom) @@ -135,3 +140,31 @@ function(qt_internal_sbom_get_sanitized_spdx_id out_var hint) _qt_internal_sbom_get_sanitized_spdx_id(result "${hint}") set(${out_var} "${result}" PARENT_SCOPE) endfunction() + +# Gets a list of default sbom args to use when processing qt entity types. +function(qt_internal_sbom_get_default_sbom_args target out_var) + _qt_internal_get_sbom_add_target_options(opt_args single_args multi_args) + list(APPEND opt_args IMMEDIATE_FINALIZATION) + cmake_parse_arguments(PARSE_ARGV 2 arg "${opt_args}" "${single_args}" "${multi_args}") + + _qt_internal_validate_all_args_are_parsed(arg) + + set(sbom_args "") + + list(APPEND sbom_args USE_ATTRIBUTION_FILES) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PACKAGE_VERSION) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_SUPPLIER) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_DOWNLOAD_LOCATION) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_LICENSE) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_COPYRIGHTS) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_CPE) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL) + list(APPEND sbom_args __QT_INTERNAL_HANDLE_QT_ENTITY_ATTRIBUTION_FILES) + + set(${out_var} "${sbom_args}" PARENT_SCOPE) +endfunction() + +function(qt_internal_extend_qt_entity_sbom target) + qt_internal_sbom_get_default_sbom_args("${target}" sbom_extra_args ${ARGN}) + _qt_internal_extend_sbom(${target} ${ARGN} ${sbom_extra_args}) +endfunction() diff --git a/cmake/QtToolHelpers.cmake b/cmake/QtToolHelpers.cmake index 0b85ec58af1..22e083b1208 100644 --- a/cmake/QtToolHelpers.cmake +++ b/cmake/QtToolHelpers.cmake @@ -306,7 +306,7 @@ function(qt_internal_add_tool target_name) ${__qt_internal_sbom_multi_args} ) - _qt_internal_extend_sbom(${target_name} ${sbom_args}) + qt_internal_extend_qt_entity_sbom(${target_name} ${sbom_args}) endif() qt_add_list_file_finalizer(qt_internal_finalize_tool ${target_name})