diff --git a/cmake/QtPublicSbomHelpers.cmake b/cmake/QtPublicSbomHelpers.cmake index 71dbf7a4f47..f46fbebe18d 100644 --- a/cmake/QtPublicSbomHelpers.cmake +++ b/cmake/QtPublicSbomHelpers.cmake @@ -478,14 +478,14 @@ function(_qt_internal_sbom_setup_fake_deterministic_build) set(QT_SBOM_FAKE_CHECKSUM "${value}" CACHE BOOL "SBOM fake checksums") endfunction() -# Helper to get purl parsing options. +# Helper to get purl entry-specific options. macro(_qt_internal_get_sbom_purl_parsing_options opt_args single_args multi_args) set(${opt_args} - NO_PURL NO_DEFAULT_QT_PURL PURL_USE_PACKAGE_VERSION ) set(${single_args} + PURL_ID PURL_TYPE PURL_NAMESPACE PURL_NAME @@ -498,7 +498,7 @@ macro(_qt_internal_get_sbom_purl_parsing_options opt_args single_args multi_args ) endmacro() -# Helper to get the purl variant option names that should be recongized by sbom functions like +# Helper to get the purl options 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} @@ -506,25 +506,19 @@ macro(_qt_internal_get_sbom_purl_add_target_options opt_args single_args multi_a ) set(${single_args} "") set(${multi_args} - PURL_QT_ARGS - PURL_3RDPARTY_UPSTREAM_ARGS - PURL_MIRROR_ARGS - PURL_QT_VALUES - PURL_3RDPARTY_UPSTREAM_VALUES - PURL_MIRROR_VALUES + PURLS + PURL_VALUES ) endmacro() # Helper to get purl options that should be forwarded from _qt_internal_sbom_add_target to # _qt_internal_sbom_handle_purl_values. macro(_qt_internal_get_sbom_purl_handling_options opt_args single_args multi_args) - set(${opt_args} - IS_QT_ENTITY_TYPE - ) + set(${opt_args} "") set(${single_args} SUPPLIER TYPE - VERSION + PACKAGE_VERSION ) set(${multi_args} "") @@ -947,11 +941,7 @@ function(_qt_internal_sbom_add_target target) endif() if(package_version) - list(APPEND purl_args VERSION "${package_version}") - endif() - - if(is_qt_entity_type) - list(APPEND purl_args IS_QT_ENTITY_TYPE) + list(APPEND purl_args PACKAGE_VERSION "${package_version}") endif() if(arg_USE_ATTRIBUTION_FILES AND qa_purls) @@ -965,7 +955,7 @@ function(_qt_internal_sbom_add_target target) OUT_VAR qa_purls_replaced ) - list(APPEND purl_args PURL_3RDPARTY_UPSTREAM_VALUES "${qa_purls_replaced}") + list(APPEND purl_args PURL_VALUES ${qa_purls_replaced}) endif() list(APPEND purl_args OUT_VAR purl_package_options) diff --git a/cmake/QtPublicSbomPurlHelpers.cmake b/cmake/QtPublicSbomPurlHelpers.cmake index a0e3101c236..6f91ea36fed 100644 --- a/cmake/QtPublicSbomPurlHelpers.cmake +++ b/cmake/QtPublicSbomPurlHelpers.cmake @@ -1,14 +1,15 @@ # Copyright (C) 2024 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -# Parse purl arguments for a specific purl variant, e.g. for parsing all values of arg_PURL_QT_ARGS. +# Parse purl arguments for a specific purl entry. # arguments_var_name is the variable name that contains the args. -macro(_qt_internal_sbom_parse_purl_variant_options prefix arguments_var_name) +# prefix is the prefix passed to cmake_parse_arguments. +macro(_qt_internal_sbom_parse_purl_entry_options prefix arguments_var_name) _qt_internal_get_sbom_purl_parsing_options(purl_opt_args purl_single_args purl_multi_args) - cmake_parse_arguments(arg "${purl_opt_args}" "${purl_single_args}" "${purl_multi_args}" + cmake_parse_arguments(${prefix} "${purl_opt_args}" "${purl_single_args}" "${purl_multi_args}" ${${arguments_var_name}}) - _qt_internal_validate_all_args_are_parsed(arg) + _qt_internal_validate_all_args_are_parsed(${prefix}) endmacro() # Helper macro to prepare forwarding all set purl options to some other function. @@ -40,25 +41,51 @@ macro(_qt_internal_sbom_forward_purl_handling_options args_var_name) endmacro() # Handles purl arguments specified to functions like qt_internal_add_sbom. -# Currently accepts arguments for 3 variants of purls, each of which will generate a separate purl. -# If no arguments are specified, for qt entity types, default values will be chosen. # -# Purl variants: -# - PURL_QT_ARGS -# args to override Qt's generic purl for Qt modules or patched 3rd party libs -# defaults to something like pkg:generic/TheQtCompany/${repo_name}-${target}@SHA1 -# - PURL_MIRROR_ARGS -# args to override Qt's mirror purl, which is hosted on github -# defaults to something like pkg:github/qt/${repo_name}@SHA1 -# - PURL_3RDPARTY_UPSTREAM_ARGS -# args to specify a purl pointing to an upstream repo, usually to github or another forge -# no defaults, but could look like: pkg:github/harfbuzz/harfbuzz@v8.5.0 -# Example values for harfbuzz: -# PURL_3RDPARTY_UPSTREAM_ARGS -# PURL_TYPE "github" -# PURL_NAMESPACE "harfbuzz" -# PURL_NAME "harfbuzz" -# PURL_VERSION "v8.5.0" # tag +# Synopsis +# +# qt_internal_add_sbom( +# PURLS +# [[PURL_ENTRY +# PURL_ID +# PURL_TYPE +# PURL_NAMESPACE +# PURL_NAME +# PURL_VERSION ]...] +# PURL_VALUES +# [purl-string...] +# ) +# +# Example +# +# qt_internal_add_sbom( +# PURLS +# PURL_ENTRY +# PURL_ID "UPSTREAM" +# PURL_TYPE "github" +# PURL_NAMESPACE "harfbuzz" +# PURL_NAME "harfbuzz" +# PURL_VERSION "v8.5.0" +# PURL_ENTRY +# PURL_ID "MIRROR" +# PURL_TYPE "git" +# PURL_NAMESPACE "harfbuzz" +# PURL_NAME "harfbuzz" +# PURL_QUALIFIERS "vcs_url=https://code.qt.io/qt/qtbase" +# .... +# PURL_VALUES +# pkg:git/harfbuzz/harfbuzz@v8.5.0 +# pkg:github/harfbuzz/harfbuzz@v8.5.0 +# .... +# +# +# PURLS accepts multiple purl entries, each starting with the PURL_ENTRY keyword. +# PURL_VALUES takes a list of pre-built purl strings. +# +# If no arguments are specified, for qt entity types (e.g. libraries built as part of Qt repos), +# default purls will be generated. +# +# There is no limit to the number of purls that can be added to a target. function(_qt_internal_sbom_handle_purl_values target) _qt_internal_get_sbom_purl_handling_options(opt_args single_args multi_args) list(APPEND single_args OUT_VAR) @@ -70,129 +97,113 @@ function(_qt_internal_sbom_handle_purl_values target) message(FATAL_ERROR "OUT_VAR must be set") endif() - # List of purl variants to process. - set(purl_variants "") - - _qt_internal_sbom_get_git_version_vars() - - 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 - ) - 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 "") - foreach(purl_variant IN LISTS purl_variants) + # Collect each PURL_ENTRY args into a separate variable. + set(purl_idx -1) + set(purl_entry_indices "") + foreach(purl_arg IN LISTS arg_PURLS) + if(purl_arg STREQUAL "PURL_ENTRY") + math(EXPR purl_idx "${purl_idx}+1") + list(APPEND purl_entry_indices "${purl_idx}") + elseif(purl_idx GREATER_EQUAL 0) + list(APPEND purl_${purl_idx}_args "${purl_arg}") + else() + message(FATAL_ERROR "Missing PURL_ENTRY keyword.") + endif() + endforeach() + + # Validate the args for each collected entry. + foreach(purl_idx IN LISTS purl_entry_indices) + list(LENGTH purl_${purl_idx}_args num_args) + if(num_args LESS 1) + message(FATAL_ERROR "Empty PURL_ENTRY encountered.") + endif() + _qt_internal_sbom_parse_purl_entry_options(arg purl_${purl_idx}_args) + endforeach() + + # Append qt specific placeholder entries when handling Qt entities. + 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_entries(${purl_handling_args} + OUT_VAR_IDS qt_purl_ids + ) + if(qt_purl_ids) + # Create purl placeholder indices for each qt purl id. + foreach(qt_purl_id IN LISTS qt_purl_ids) + math(EXPR purl_idx "${purl_idx}+1") + list(APPEND purl_entry_indices "${purl_idx}") + list(APPEND purl_${purl_idx}_args PURL_ID "${qt_purl_id}") + endforeach() + endif() + endif() + + foreach(purl_idx IN LISTS purl_entry_indices) # Clear previous values. foreach(option_name IN LISTS purl_opt_args purl_single_args purl_multi_args) unset(arg_${option_name}) endforeach() - _qt_internal_sbom_parse_purl_variant_options(arg arg_PURL_${purl_variant}_ARGS) + _qt_internal_sbom_parse_purl_entry_options(arg purl_${purl_idx}_args) - # Check if custom purl args were specified. - set(purl_args_available FALSE) - if(arg_PURL_${purl_variant}_ARGS) - set(purl_args_available TRUE) + set(purl_args "") + + # Override the purl version with the package version. + if(arg_PURL_USE_PACKAGE_VERSION AND arg_PACKAGE_VERSION) + set(arg_PURL_VERSION "${arg_PACKAGE_VERSION}") endif() - # 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(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL AND is_qt_purl_entity_type) - set(purl_args_available TRUE) + # Append a vcs_url to the qualifiers if specified. + if(arg_PURL_VCS_URL) + list(APPEND arg_PURL_QUALIFIERS "vcs_url=${arg_PURL_VCS_URL}") endif() - if(purl_args_available AND NOT arg_NO_PURL) - set(consider_purl_processing TRUE) - endif() + _qt_internal_forward_function_args( + FORWARD_APPEND + FORWARD_PREFIX arg + FORWARD_OUT_VAR purl_args + FORWARD_OPTIONS + ${purl_opt_args} + FORWARD_SINGLE + ${purl_single_args} + FORWARD_MULTI + ${purl_multi_args} + ) - if(consider_purl_processing) - set(purl_args "") + # Qt entity types get special treatment to gather the required args. + if(arg___QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PURL + AND arg_PURL_ID + AND arg_PURL_ID IN_LIST qt_purl_ids) - # Override the purl version with the package version. - if(arg_PURL_USE_PACKAGE_VERSION AND arg_VERSION) - set(arg_PURL_VERSION "${arg_VERSION}") - endif() - - # Append a vcs_url to the qualifiers if specified. - if(arg_PURL_VCS_URL) - list(APPEND arg_PURL_QUALIFIERS "vcs_url=${arg_PURL_VCS_URL}") - endif() - - _qt_internal_forward_function_args( - FORWARD_APPEND - FORWARD_PREFIX arg - FORWARD_OUT_VAR purl_args - FORWARD_OPTIONS - ${purl_opt_args} - FORWARD_SINGLE - ${purl_single_args} - FORWARD_MULTI - ${purl_multi_args} + _qt_internal_sbom_handle_qt_entity_purl("${target}" + ${purl_handling_args} + PURL_ID "${arg_PURL_ID}" + OUT_PURL_ARGS qt_purl_args ) - - # Qt entity types get special treatment purl. - 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() - _qt_internal_sbom_handle_qt_entity_purl("${target}" ${purl_handling_args} - PURL_VARIANT "${purl_variant}" - OUT_PURL_ARGS qt_purl_args - ) - if(qt_purl_args) - list(APPEND purl_args "${qt_purl_args}") - endif() + if(qt_purl_args) + list(APPEND purl_args "${qt_purl_args}") endif() - - _qt_internal_sbom_assemble_purl(${target} - ${purl_args} - OUT_VAR package_manager_external_ref - ) - list(APPEND project_package_options ${package_manager_external_ref}) endif() + + _qt_internal_sbom_assemble_purl(${target} + ${purl_args} + OUT_VAR package_manager_external_ref + ) + list(APPEND project_package_options ${package_manager_external_ref}) endforeach() - set(direct_values - PURL_QT_VALUES - PURL_MIRROR_VALUES - PURL_3RDPARTY_UPSTREAM_VALUES - ) + foreach(purl_value IN LISTS arg_PURL_VALUES) + _qt_internal_sbom_get_purl_value_extref( + VALUE "${purl_value}" OUT_VAR package_manager_external_ref) - foreach(direct_value IN LISTS direct_values) - if(arg_${direct_value}) - set(direct_values_per_type "") - foreach(direct_value IN LISTS arg_${direct_value}) - _qt_internal_sbom_get_purl_value_extref( - VALUE "${direct_value}" OUT_VAR package_manager_external_ref) - - list(APPEND direct_values_per_type ${package_manager_external_ref}) - endforeach() - # 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 directly specified ones (probably via a qt_attribution.json - # file) are the more important ones. So we prepend them. - list(PREPEND project_package_options ${direct_values_per_type}) - endif() + # 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 directly specified ones (probably via a qt_attribution.json + # file) are the more important ones. So we prepend them. + list(PREPEND project_package_options ${package_manager_external_ref}) endforeach() set(${arg_OUT_VAR} "${project_package_options}" PARENT_SCOPE) diff --git a/cmake/QtPublicSbomQtEntityHelpers.cmake b/cmake/QtPublicSbomQtEntityHelpers.cmake index 3b658a32523..b469bc8a542 100644 --- a/cmake/QtPublicSbomQtEntityHelpers.cmake +++ b/cmake/QtPublicSbomQtEntityHelpers.cmake @@ -203,7 +203,7 @@ function(_qt_internal_sbom_handle_qt_entity_cpe target) endif() endfunction() -# Returns a vcs url where for purls where qt entities of the current repo are hosted. +# Returns a vcs url for purls where qt entities of the current repo are hosted. function(_qt_internal_sbom_get_qt_entity_vcs_url target) set(opt_args "") set(single_args @@ -267,7 +267,6 @@ function(_qt_internal_sbom_get_qt_entity_purl_args target) REPO_NAME SUPPLIER VERSION - PURL_VARIANT OUT_VAR ) set(multi_args "") @@ -280,21 +279,18 @@ function(_qt_internal_sbom_get_qt_entity_purl_args target) cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) - set(supported_purl_variants QT MIRROR) - if(NOT arg_PURL_VARIANT IN_LIST supported_purl_variants) - message(FATAL_ERROR "PURL_VARIANT unknown: ${arg_PURL_VARIANT}") + if(arg_VERSION) + set(purl_version "${arg_VERSION}") endif() - if(arg_PURL_VARIANT STREQUAL "QT") + if(arg_PURL_ID STREQUAL "GENERIC") set(purl_type "generic") set(purl_namespace "${arg_SUPPLIER}") set(purl_name "${arg_NAME}") - set(purl_version "${arg_VERSION}") - elseif(arg_PURL_VARIANT STREQUAL "MIRROR") + elseif(arg_PURL_ID STREQUAL "GITHUB") set(purl_type "github") set(purl_namespace "qt") set(purl_name "${arg_REPO_NAME}") - set(purl_version "${arg_VERSION}") endif() if(arg_PURL_TYPE) @@ -336,12 +332,27 @@ function(_qt_internal_sbom_get_qt_entity_purl_args target) set(${arg_OUT_VAR} "${purl_args}" PARENT_SCOPE) endfunction() -# Helper function to decide which purl variants to add for a qt entity. -function(_qt_internal_sbom_handle_qt_entity_purl_variants) +# Helper to get the list of default purl ids for a qt entity. +# +# Qt entities have two purls by default: +# - a GITHUB one pointing to the qt github mirror +# - a GENERIC one pointing to code.qt.io via vcs_url +# +# Third party libraries vendored in Qt also have the same purls, like regular Qt +# libraries, but might also have an upstream one which is specified explicitly. +function(_qt_internal_sbom_get_qt_entity_default_purl_ids out_var) + set(supported_purl_ids GITHUB GENERIC) + set(${out_var} "${supported_purl_ids}" PARENT_SCOPE) +endfunction() + +# Helper function to decide which purl ids to add for a qt entity. +# Returns either a list of qt purl ids, or an empty list if it's not a qt entity type or qt 3rd +# party type. +function(_qt_internal_sbom_handle_qt_entity_purl_entries) _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 + OUT_VAR_IDS ) cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) @@ -351,100 +362,85 @@ function(_qt_internal_sbom_handle_qt_entity_purl_variants) QT_THIRD_PARTY_SOURCES ) - set(purl_variants "") + set(purl_ids "") - 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. + _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) - # 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) + if(is_qt_entity_type OR is_qt_3rd_party_entity_type) + _qt_internal_sbom_get_qt_entity_default_purl_ids(purl_ids) 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) + if(purl_ids) + set(${arg_OUT_VAR_IDS} "${purl_ids}" PARENT_SCOPE) endif() endfunction() -# Helper function to add purl values for a specific purl variant of a qt entity type. +# Helper function to add purl values for a specific purl entry 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 + PURL_ID ) 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) + _qt_internal_sbom_get_git_version_vars() - # 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() + # Return early if not handling one of the default qt purl ids, or if requested not to add a + # default purl. + _qt_internal_sbom_get_qt_entity_default_purl_ids(default_purl_ids) - _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() + if(arg_NO_DEFAULT_QT_PURL OR (NOT arg_PURL_ID IN_LIST default_purl_ids)) + set(${arg_OUT_PURL_ARGS} "${purl_args}" PARENT_SCOPE) + return() + 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}") + _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) + # Add a vcs_url to the GENERIC purl entry. + if(arg_PURL_ID STREQUAL "GENERIC") + set(entity_vcs_url_version_option "") # Can be empty. if(QT_SBOM_GIT_HASH_SHORT) - list(APPEND purl_args VERSION "${QT_SBOM_GIT_HASH_SHORT}") + set(entity_vcs_url_version_option 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}" + _qt_internal_sbom_get_qt_entity_vcs_url(${target} REPO_NAME "${repo_project_name_lowercase}" - SUPPLIER "${arg_SUPPLIER}" - PURL_VARIANT "${arg_PURL_VARIANT}" - ${purl_args} - OUT_VAR purl_args - ) + ${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_ID "${arg_PURL_ID}" + ${purl_args} + OUT_VAR purl_args + ) + if(purl_args) set(${arg_OUT_PURL_ARGS} "${purl_args}" PARENT_SCOPE) endif()