CMake: Add SBOM support for translations, custom files and friends
This change introduces a new SBOM API to add info about various kinds of files to a target SBOM package. The new function name is called qt_internal_sbom_add_files(). The motivating case is including SBOM information for qt translation files, resources (e.g. webengine data files) and any other kind of custom files. A sample call might look like: qt_internal_sbom_add_files(Translations FILES "${qm_files}" SOURCE_FILES_ONE_PER_INPUT_FILE "${ts_files}" FILE_TYPE "QT_TRANSLATION" INSTALL_PATH "${INSTALL_TRANSLATIONSDIR}" ) While the motivating case is Qt-specific, the function implementation is being somewhat future proofed for the not-yet created public SBOM API. The new API supports adding files to any target that is backed by an SBOM package, so all targets created by qt_internal_add_module() and friends, as well as ones created by qt_internal_add_sbom(). It can be called multiple times for the same target, with a different set of files, to e.g. assign a different license, or file type per file set. Note that the file set doesn't have anything to do with CMake's concept of file sets. The function is also multi-config aware, and allows specifying different install paths per config, as well as generator expressions in file names. But the multi-config support is a bit wonky, and might need some rethinking in the future. Note that the custom files must be installed and available in the specified qt install path, because the file contents will be checksummed at install time and embedded into the sbom document. Calling the new API does not do installation itself. Implementation wise, the function call flow is - project calls qt_internal_sbom_add_files() one or more times - at finalization time, the _qt_internal_sbom_add_target finalizer is called for a target, which then calls _qt_internal_sbom_handle_target_custom_files() - the latter calls _qt_internal_sbom_handle_target_custom_file_set() for each file set that was added to the target - the latter calls _qt_internal_sbom_handle_multi_config_custom_file() for each input file in the file set, which ultimately calls _qt_internal_sbom_add_custom_file() Pick-to: 6.8 6.9 Task-number: QTBUG-122899 Task-number: QTBUG-128320 Change-Id: Iafde26ebd68f4168b49e55fbc8ad1c251e98d4b0 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
parent
42a58d6619
commit
b085fe6ad9
@ -1012,6 +1012,15 @@ function(_qt_internal_sbom_add_target target)
|
|||||||
${copyrights_option}
|
${copyrights_option}
|
||||||
${license_option}
|
${license_option}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_qt_internal_sbom_handle_target_custom_files("${target}"
|
||||||
|
${no_install_option}
|
||||||
|
${install_prefix_option}
|
||||||
|
PACKAGE_TYPE "${arg_TYPE}"
|
||||||
|
PACKAGE_SPDX_ID "${package_spdx_id}"
|
||||||
|
${copyrights_option}
|
||||||
|
${license_option}
|
||||||
|
)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Walks a target's direct dependencies and assembles a list of relationships between the packages
|
# Walks a target's direct dependencies and assembles a list of relationships between the packages
|
||||||
@ -1389,27 +1398,43 @@ function(_qt_internal_sbom_handle_target_binary_files target)
|
|||||||
QT_THIRD_PARTY_MODULE
|
QT_THIRD_PARTY_MODULE
|
||||||
QT_THIRD_PARTY_SOURCES
|
QT_THIRD_PARTY_SOURCES
|
||||||
SYSTEM_LIBRARY
|
SYSTEM_LIBRARY
|
||||||
|
QT_TRANSLATIONS
|
||||||
|
QT_RESOURCES
|
||||||
|
QT_CUSTOM
|
||||||
|
QT_CUSTOM_NO_INFIX
|
||||||
|
|
||||||
# This will be meant for user projects, and are not currently used by Qt's sbom.
|
# This will be meant for user projects, and are not currently used by Qt's sbom.
|
||||||
THIRD_PARTY_LIBRARY
|
THIRD_PARTY_LIBRARY
|
||||||
THIRD_PARTY_LIBRARY_WITH_FILES
|
THIRD_PARTY_LIBRARY_WITH_FILES
|
||||||
EXECUTABLE
|
EXECUTABLE
|
||||||
LIBRARY
|
LIBRARY
|
||||||
|
TRANSLATIONS
|
||||||
|
RESOURCES
|
||||||
|
CUSTOM
|
||||||
|
CUSTOM_NO_INFIX
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT arg_TYPE IN_LIST supported_types)
|
if(NOT arg_TYPE IN_LIST supported_types)
|
||||||
message(FATAL_ERROR "Unsupported target TYPE for SBOM creation: ${arg_TYPE}")
|
message(FATAL_ERROR "Unsupported target TYPE for SBOM creation: ${arg_TYPE}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(types_without_files
|
set(types_without_binary_files
|
||||||
SYSTEM_LIBRARY
|
|
||||||
QT_THIRD_PARTY_SOURCES
|
QT_THIRD_PARTY_SOURCES
|
||||||
|
QT_TRANSLATIONS
|
||||||
|
QT_RESOURCES
|
||||||
|
QT_CUSTOM
|
||||||
|
QT_CUSTOM_NO_INFIX
|
||||||
|
SYSTEM_LIBRARY
|
||||||
THIRD_PARTY_LIBRARY
|
THIRD_PARTY_LIBRARY
|
||||||
|
TRANSLATIONS
|
||||||
|
RESOURCES
|
||||||
|
CUSTOM
|
||||||
|
CUSTOM_NO_INFIX
|
||||||
)
|
)
|
||||||
|
|
||||||
get_target_property(target_type ${target} TYPE)
|
get_target_property(target_type ${target} TYPE)
|
||||||
|
|
||||||
if(arg_TYPE IN_LIST types_without_files)
|
if(arg_TYPE IN_LIST types_without_binary_files)
|
||||||
message(DEBUG "Target ${target} has no binary files to reference in the SBOM "
|
message(DEBUG "Target ${target} has no binary files to reference in the SBOM "
|
||||||
"because it has the ${arg_TYPE} type.")
|
"because it has the ${arg_TYPE} type.")
|
||||||
return()
|
return()
|
||||||
@ -1532,6 +1557,7 @@ endfunction()
|
|||||||
# Add a binary file of a target to the sbom (e.g a shared library or an executable).
|
# Add a binary file of a target to the sbom (e.g a shared library or an executable).
|
||||||
# Adds relationships to the SBOM that the binary file was generated from its source files,
|
# Adds relationships to the SBOM that the binary file was generated from its source files,
|
||||||
# as well as relationship to the owning package.
|
# as well as relationship to the owning package.
|
||||||
|
# TODO: Consider merging the common parts with _qt_internal_sbom_add_custom_file somehow.
|
||||||
function(_qt_internal_sbom_add_binary_file target file_path)
|
function(_qt_internal_sbom_add_binary_file target file_path)
|
||||||
set(opt_args
|
set(opt_args
|
||||||
OPTIONAL
|
OPTIONAL
|
||||||
@ -1600,7 +1626,7 @@ function(_qt_internal_sbom_add_binary_file target file_path)
|
|||||||
set(relationships "${arg_PACKAGE_SPDX_ID} CONTAINS ${spdx_id}")
|
set(relationships "${arg_PACKAGE_SPDX_ID} CONTAINS ${spdx_id}")
|
||||||
|
|
||||||
# Add source file relationships from which the binary file was generated.
|
# Add source file relationships from which the binary file was generated.
|
||||||
_qt_internal_sbom_add_source_files("${target}" "${spdx_id}" source_relationships)
|
_qt_internal_sbom_add_target_source_files("${target}" "${spdx_id}" source_relationships)
|
||||||
if(source_relationships)
|
if(source_relationships)
|
||||||
list(APPEND relationships "${source_relationships}")
|
list(APPEND relationships "${source_relationships}")
|
||||||
endif()
|
endif()
|
||||||
@ -1626,6 +1652,425 @@ function(_qt_internal_sbom_add_binary_file target file_path)
|
|||||||
)
|
)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# Add a list of to-be-installed files that should appear in the files section of the target's
|
||||||
|
# SBOM document.
|
||||||
|
# Supports multiple calls with the same target name.
|
||||||
|
# Each call is handled as a separate set of files.
|
||||||
|
# For options that can be passed, see the doc-comment of
|
||||||
|
# _qt_internal_sbom_handle_target_custom_file_set.
|
||||||
|
function(_qt_internal_sbom_add_files target)
|
||||||
|
if(NOT QT_GENERATE_SBOM)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET "${target}")
|
||||||
|
message(FATAL_ERROR "The target ${target} does not exist.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(file_sets_count "${target}" _qt_sbom_custom_file_sets_count)
|
||||||
|
if(NOT file_sets_count)
|
||||||
|
set(file_sets_count 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_property(TARGET "${target}"
|
||||||
|
APPEND PROPERTY _qt_sbom_custom_file_set_${file_sets_count} "${ARGN}")
|
||||||
|
|
||||||
|
math(EXPR file_sets_count "${file_sets_count}+1")
|
||||||
|
set_property(TARGET "${target}" PROPERTY _qt_sbom_custom_file_sets_count "${file_sets_count}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Handles addition of custom file SPDX entries for a given target, by processing all the collected
|
||||||
|
# file sets so far.
|
||||||
|
# Applies the passed license and copyright info to all collected files.
|
||||||
|
#
|
||||||
|
# Options that can be passed.
|
||||||
|
#
|
||||||
|
# NO_INSTALL - if set, custom file processing is skipped, because the files will not be installed.
|
||||||
|
#
|
||||||
|
# PACKAGE_TYPE - the type of the package that the files belong to, is used to compute an infix
|
||||||
|
# for the file spdx id.
|
||||||
|
#
|
||||||
|
# PACKAGE_SPDX_ID - the package spdx id is used to add a relationship between the package and file.
|
||||||
|
#
|
||||||
|
# LICENSE_EXPRESSION - a license expression to apply to the files.
|
||||||
|
#
|
||||||
|
# INSTALL_PREFIX - the install prefix for the files, this is usually the install prefix of qt.
|
||||||
|
#
|
||||||
|
# COPYRIGHTS - a list of copyright strings to apply to the files.
|
||||||
|
function(_qt_internal_sbom_handle_target_custom_files target)
|
||||||
|
set(opt_args
|
||||||
|
NO_INSTALL
|
||||||
|
)
|
||||||
|
set(single_args
|
||||||
|
PACKAGE_TYPE
|
||||||
|
PACKAGE_SPDX_ID
|
||||||
|
LICENSE_EXPRESSION
|
||||||
|
INSTALL_PREFIX
|
||||||
|
)
|
||||||
|
set(multi_args
|
||||||
|
COPYRIGHTS
|
||||||
|
)
|
||||||
|
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
|
||||||
|
_qt_internal_validate_all_args_are_parsed(arg)
|
||||||
|
|
||||||
|
# Nothing to process if no file sets were defined.
|
||||||
|
get_target_property(file_sets_count "${target}" _qt_sbom_custom_file_sets_count)
|
||||||
|
if(NOT file_sets_count)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(arg_NO_INSTALL)
|
||||||
|
message(DEBUG "Skipping sbom custom file processing for ${target} because NO_INSTALL is "
|
||||||
|
"set")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT arg_PACKAGE_SPDX_ID)
|
||||||
|
message(FATAL_ERROR "PACKAGE_SPDX_ID must be set")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qt_internal_forward_function_args(
|
||||||
|
FORWARD_PREFIX arg
|
||||||
|
FORWARD_OUT_VAR file_common_options
|
||||||
|
FORWARD_SINGLE
|
||||||
|
PACKAGE_TYPE
|
||||||
|
PACKAGE_SPDX_ID
|
||||||
|
LICENSE_EXPRESSION
|
||||||
|
INSTALL_PREFIX
|
||||||
|
FORWARD_MULTI
|
||||||
|
COPYRIGHTS
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subtract -1, because foreach(RANGE is inclusive).
|
||||||
|
math(EXPR file_sets_count "${file_sets_count}-1")
|
||||||
|
foreach(file_set_index RANGE ${file_sets_count})
|
||||||
|
get_target_property(file_set_args "${target}" _qt_sbom_custom_file_set_${file_set_index})
|
||||||
|
|
||||||
|
if(NOT file_set_args)
|
||||||
|
message(FATAL_ERROR "No arguments were specified for SBOM custom file set for "
|
||||||
|
"${target}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qt_internal_sbom_handle_target_custom_file_set("${target}"
|
||||||
|
${file_common_options} ${file_set_args})
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Processes a file set of custom files for which to include SBOM info.
|
||||||
|
# The
|
||||||
|
# NO_INSTALL
|
||||||
|
# PACKAGE_TYPE
|
||||||
|
# PACKAGE_SPDX_ID
|
||||||
|
# LICENSE_EXPRESSION
|
||||||
|
# INSTALL_PREFIX
|
||||||
|
# COPYRIGHTS
|
||||||
|
# options are the same as in _qt_internal_sbom_handle_target_custom_files, and are actually
|
||||||
|
# forwarded from that function, because they might be set at the target level.
|
||||||
|
#
|
||||||
|
# In addition, more options can be passed when called via qt_internal_sbom_add_custom_files:
|
||||||
|
#
|
||||||
|
# They are:
|
||||||
|
#
|
||||||
|
# FILE_TYPE - the type of each provided file. Supported types can be found in the implementation of
|
||||||
|
# _qt_internal_sbom_get_spdx_v2_3_file_type_for_file().
|
||||||
|
# Some examples are QT_TRANSLATION, QT_TRANSLATIONS_CATALOG, QT_RESOURCE.
|
||||||
|
#
|
||||||
|
# FILES - a list of file paths to include in the SBOM. Only the file name is currently used.
|
||||||
|
#
|
||||||
|
# SOURCE_FILES - which source files were used to generate the custom files. All source files apply
|
||||||
|
# to each input file.
|
||||||
|
#
|
||||||
|
# SOURCE_FILES_PER_INPUT_FILE - for each index i in FILES, the corresponding source files are
|
||||||
|
# in SOURCE_FILES[i], so that each input gets exactly one source file.
|
||||||
|
# This is provided as an option, to prevent performance overhead from having to add a
|
||||||
|
# custom file set for each new source file, when dealing with translations that have a
|
||||||
|
# 1-to-1 ts->qm relationship.
|
||||||
|
#
|
||||||
|
# There is also a set of multi config aware options that can be set, like
|
||||||
|
# INSTALL_PATH
|
||||||
|
# INSTALL_PATH_<CONFIG>
|
||||||
|
# which should be the relative install dir path where the
|
||||||
|
# files will be installed, relative to $ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}.
|
||||||
|
function(_qt_internal_sbom_handle_target_custom_file_set target)
|
||||||
|
set(opt_args
|
||||||
|
""
|
||||||
|
)
|
||||||
|
set(single_args
|
||||||
|
FILE_TYPE
|
||||||
|
PACKAGE_SPDX_ID
|
||||||
|
PACKAGE_TYPE
|
||||||
|
LICENSE_EXPRESSION
|
||||||
|
INSTALL_PREFIX
|
||||||
|
)
|
||||||
|
set(multi_args
|
||||||
|
COPYRIGHTS
|
||||||
|
FILES
|
||||||
|
SOURCE_FILES
|
||||||
|
SOURCE_FILES_PER_INPUT_FILE
|
||||||
|
)
|
||||||
|
|
||||||
|
# Don't explicitly forward the multi config single args, but still parse them.
|
||||||
|
# They will be accessed from the current scope directly.
|
||||||
|
set(single_args_without_multi_config_args "${single_args}")
|
||||||
|
_qt_internal_sbom_get_multi_config_single_args(multi_config_single_args)
|
||||||
|
list(APPEND single_args ${multi_config_single_args})
|
||||||
|
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
|
||||||
|
_qt_internal_validate_all_args_are_parsed(arg)
|
||||||
|
|
||||||
|
# No custom files to process.
|
||||||
|
if(NOT arg_FILES)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Don't forward the FILES option.
|
||||||
|
set(multi_args_without_files "${multi_args}")
|
||||||
|
list(REMOVE_ITEM multi_args_without_files FILES)
|
||||||
|
|
||||||
|
# Handle the case where we have one source file per input file.
|
||||||
|
if(arg_SOURCE_FILES_PER_INPUT_FILE)
|
||||||
|
list(LENGTH arg_FILES files_count)
|
||||||
|
list(LENGTH arg_SOURCE_FILES_PER_INPUT_FILE source_files_count)
|
||||||
|
if(NOT files_count EQUAL source_files_count)
|
||||||
|
message(FATAL_ERROR "The number of files passed to SOURCE_FILES must match the number"
|
||||||
|
"of files passed to SOURCE_FILES_PER_INPUT_FILE.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Don't forward all of the source files, but rather one per input file.
|
||||||
|
list(REMOVE_ITEM multi_args_without_files SOURCE_FILES_PER_INPUT_FILE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qt_internal_forward_function_args(
|
||||||
|
FORWARD_PREFIX arg
|
||||||
|
FORWARD_OUT_VAR forward_args
|
||||||
|
FORWARD_SINGLE
|
||||||
|
${single_args_without_multi_config_args}
|
||||||
|
FORWARD_MULTI
|
||||||
|
${multi_args_without_files}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(file_index 0)
|
||||||
|
foreach(file_path IN LISTS arg_FILES)
|
||||||
|
set(per_file_forward_args "")
|
||||||
|
|
||||||
|
# We don't currently use the file path for anything other than getting the file name, to
|
||||||
|
# embed it into the spdx document entry.
|
||||||
|
# What matters in the end is the location where the file is installed, which is handled
|
||||||
|
# by the PATH_KIND option.
|
||||||
|
get_filename_component(file_name "${file_path}" NAME)
|
||||||
|
|
||||||
|
if(arg_SOURCE_FILES_PER_INPUT_FILE)
|
||||||
|
list(GET arg_SOURCE_FILES_PER_INPUT_FILE "${file_index}" source_file)
|
||||||
|
list(APPEND per_file_forward_args SOURCE_FILES "${source_file}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# The multi_config_single_args are deliberately not forwarded, but are available in this
|
||||||
|
# function scope, for direct access in the called function scope, because
|
||||||
|
# cmake_parse_arguments can't handle:
|
||||||
|
# PATH_KIND "INSTALL_PATH"
|
||||||
|
# INSTALL_PATH "/some_path"
|
||||||
|
# the parsing gets confused by what's the option and what's the value.
|
||||||
|
_qt_internal_sbom_handle_multi_config_custom_file(${target}
|
||||||
|
PATH_KIND "INSTALL_PATH"
|
||||||
|
PATH_SUFFIX "${file_name}"
|
||||||
|
OPTIONS
|
||||||
|
${forward_args}
|
||||||
|
${per_file_forward_args}
|
||||||
|
)
|
||||||
|
math(EXPR file_index "${file_index}+1")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Helper function to add a custom file to the sbom, while handling multi-config and different
|
||||||
|
# kind of paths.
|
||||||
|
# In multi-config builds, we assume that the non-default config file will be optional, because it
|
||||||
|
# might not be installed.
|
||||||
|
#
|
||||||
|
# Expects the parent scope to contain the ${PATH_KIND} and ${PATH_KIND}_<CONFIG> variables.
|
||||||
|
# Examples are INSTALL_PATH or INSTALL_PATH_DEBUG.
|
||||||
|
# They can't be forwarded as options because of cmake_parse_arguments parsing issues when a value
|
||||||
|
# can be the same as a key. See comment in implementation of
|
||||||
|
#_qt_internal_sbom_handle_target_custom_file_set.
|
||||||
|
function(_qt_internal_sbom_handle_multi_config_custom_file target)
|
||||||
|
set(opt_args "")
|
||||||
|
set(single_args
|
||||||
|
PATH_KIND
|
||||||
|
PATH_SUFFIX
|
||||||
|
)
|
||||||
|
set(multi_args
|
||||||
|
OPTIONS
|
||||||
|
)
|
||||||
|
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
|
||||||
|
_qt_internal_validate_all_args_are_parsed(arg)
|
||||||
|
|
||||||
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
if(is_multi_config)
|
||||||
|
set(configs ${CMAKE_CONFIGURATION_TYPES})
|
||||||
|
else()
|
||||||
|
set(configs "${CMAKE_BUILD_TYPE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(config IN LISTS configs)
|
||||||
|
_qt_internal_sbom_get_and_check_multi_config_aware_single_arg_option(
|
||||||
|
arg "${arg_PATH_KIND}" "${config}" resolved_path)
|
||||||
|
_qt_internal_sbom_get_target_file_is_optional_in_multi_config("${config}" is_optional)
|
||||||
|
_qt_internal_path_join(file_path "${resolved_path}" "${arg_PATH_SUFFIX}")
|
||||||
|
_qt_internal_sbom_add_custom_file(
|
||||||
|
"${target}"
|
||||||
|
"${file_path}"
|
||||||
|
${arg_OPTIONS}
|
||||||
|
${is_optional}
|
||||||
|
CONFIG ${config}
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Adds one custom file with the given relative install path into the SBOM document.
|
||||||
|
# Will embed GENERATED_FROM source file relationships if a list of source files is specified.
|
||||||
|
function(_qt_internal_sbom_add_custom_file target installed_file_relative_path)
|
||||||
|
set(opt_args
|
||||||
|
OPTIONAL
|
||||||
|
)
|
||||||
|
set(single_args
|
||||||
|
PACKAGE_SPDX_ID
|
||||||
|
PACKAGE_TYPE
|
||||||
|
LICENSE_EXPRESSION
|
||||||
|
INSTALL_PREFIX
|
||||||
|
FILE_TYPE
|
||||||
|
CONFIG
|
||||||
|
)
|
||||||
|
set(multi_args
|
||||||
|
COPYRIGHTS
|
||||||
|
SOURCE_FILES
|
||||||
|
)
|
||||||
|
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 2 arg "${opt_args}" "${single_args}" "${multi_args}")
|
||||||
|
_qt_internal_validate_all_args_are_parsed(arg)
|
||||||
|
|
||||||
|
if(NOT arg_PACKAGE_SPDX_ID)
|
||||||
|
message(FATAL_ERROR "PACKAGE_SPDX_ID must be set")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(file_common_options "")
|
||||||
|
|
||||||
|
if(arg_COPYRIGHTS)
|
||||||
|
list(JOIN arg_COPYRIGHTS "\n" copyrights)
|
||||||
|
list(APPEND file_common_options COPYRIGHT "<text>${copyrights}</text>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(arg_LICENSE_EXPRESSION)
|
||||||
|
list(APPEND file_common_options LICENSE "${arg_LICENSE_EXPRESSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(arg_INSTALL_PREFIX)
|
||||||
|
list(APPEND file_common_options INSTALL_PREFIX "${arg_INSTALL_PREFIX}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
if(is_multi_config)
|
||||||
|
set(spdx_id_suffix "${arg_CONFIG}")
|
||||||
|
set(config_to_install_option CONFIG ${arg_CONFIG})
|
||||||
|
else()
|
||||||
|
set(spdx_id_suffix "")
|
||||||
|
set(config_to_install_option "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(arg_FILE_TYPE)
|
||||||
|
_qt_internal_sbom_get_spdx_v2_3_file_type_for_file(file_type "${arg_FILE_TYPE}")
|
||||||
|
else()
|
||||||
|
set(file_type "OTHER")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_filename_component(file_name "${installed_file_relative_path}" NAME)
|
||||||
|
|
||||||
|
_qt_internal_sbom_get_package_infix("${arg_PACKAGE_TYPE}" package_infix)
|
||||||
|
|
||||||
|
_qt_internal_sbom_get_file_spdx_id(
|
||||||
|
"${package_infix}-${target}-${file_name}-${spdx_id_suffix}" spdx_id)
|
||||||
|
|
||||||
|
# Add relationship from owning package.
|
||||||
|
set(relationships "${arg_PACKAGE_SPDX_ID} CONTAINS ${spdx_id}")
|
||||||
|
|
||||||
|
# Add source file relationships from which the custom file was generated.
|
||||||
|
set(sources_option "")
|
||||||
|
|
||||||
|
if(arg_SOURCE_FILES)
|
||||||
|
set(sources_option SOURCES ${arg_SOURCE_FILES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qt_internal_sbom_add_source_files(
|
||||||
|
${sources_option}
|
||||||
|
SPDX_ID "${spdx_id}"
|
||||||
|
OUT_RELATIONSHIPS_VAR source_relationships
|
||||||
|
)
|
||||||
|
|
||||||
|
if(source_relationships)
|
||||||
|
list(APPEND relationships "${source_relationships}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(glue "\nRelationship: ")
|
||||||
|
# Replace semicolon with $<SEMICOLON> to avoid errors when passing into sbom_add.
|
||||||
|
string(REPLACE ";" "$<SEMICOLON>" relationships "${relationships}")
|
||||||
|
|
||||||
|
# Glue the relationships at generation time, because there some source file relationships
|
||||||
|
# will be conditional on genexes, and evaluate to an empty value, and we want to discard
|
||||||
|
# such relationships.
|
||||||
|
set(relationships "$<JOIN:${relationships},${glue}>")
|
||||||
|
set(relationship_option RELATIONSHIP "${relationships}")
|
||||||
|
|
||||||
|
_qt_internal_sbom_generate_add_file(
|
||||||
|
FILENAME "${installed_file_relative_path}"
|
||||||
|
FILETYPE "${file_type}" ${optional}
|
||||||
|
SPDXID "${spdx_id}"
|
||||||
|
${file_common_options}
|
||||||
|
${config_to_install_option}
|
||||||
|
${relationship_option}
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Maps an arbitrary file type to a spdx v2.3 file type.
|
||||||
|
# There is a list of known SPDX types, and custom Qt ones.
|
||||||
|
# Any other type is mapped to OTHER.
|
||||||
|
# The mapping might change when we start generating spdx v3.0 documents.
|
||||||
|
function(_qt_internal_sbom_get_spdx_v2_3_file_type_for_file out_var file_type_in)
|
||||||
|
set(spdx_v2_3_file_types
|
||||||
|
SOURCE
|
||||||
|
BINARY
|
||||||
|
ARCHIVE
|
||||||
|
APPLICATION
|
||||||
|
AUDIO
|
||||||
|
IMAGE
|
||||||
|
TEXT
|
||||||
|
VIDEO
|
||||||
|
DOCUMENTATION
|
||||||
|
SPDX
|
||||||
|
OTHER
|
||||||
|
)
|
||||||
|
|
||||||
|
# No semantic meaning at the moment, but we might want to map the values to something else
|
||||||
|
# when we port to SPDX v3.0+.
|
||||||
|
set(qt_file_types
|
||||||
|
QT_TRANSLATION
|
||||||
|
QT_TRANSLATIONS_CATALOG
|
||||||
|
QT_RESOURCE
|
||||||
|
TRANSLATION
|
||||||
|
RESOURCE
|
||||||
|
CUSTOM
|
||||||
|
)
|
||||||
|
|
||||||
|
if(file_type_in IN_LIST spdx_v2_3_file_types)
|
||||||
|
set(file_type "${file_type_in}")
|
||||||
|
elseif(file_type_in IN_LIST qt_file_types)
|
||||||
|
set(file_type OTHER)
|
||||||
|
else()
|
||||||
|
set(file_type OTHER)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${out_var} "${file_type}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# Takes a relative or absolute path and maps it to a reproducible path that is relative to
|
# Takes a relative or absolute path and maps it to a reproducible path that is relative to
|
||||||
# the project source or build dir.
|
# the project source or build dir.
|
||||||
function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var)
|
function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var)
|
||||||
@ -1706,11 +2151,55 @@ function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Adds source file "generated from" relationship comments to the sbom for a given target.
|
# Collect source file "generated from" relationship comments for a given target file.
|
||||||
function(_qt_internal_sbom_add_source_files target spdx_id out_relationships)
|
function(_qt_internal_sbom_add_target_source_files target spdx_id out_relationships)
|
||||||
get_target_property(sources ${target} SOURCES)
|
get_target_property(sources ${target} SOURCES)
|
||||||
|
if(NOT sources)
|
||||||
|
set(sources "")
|
||||||
|
endif()
|
||||||
list(REMOVE_DUPLICATES sources)
|
list(REMOVE_DUPLICATES sources)
|
||||||
|
|
||||||
|
set(sources_option "")
|
||||||
|
if(sources)
|
||||||
|
set(sources_option SOURCES ${sources})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qt_internal_sbom_add_source_files(
|
||||||
|
${sources_option}
|
||||||
|
SPDX_ID "${spdx_id}"
|
||||||
|
OUT_RELATIONSHIPS_VAR relationships
|
||||||
|
)
|
||||||
|
|
||||||
|
set(${out_relationships} "${relationships}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Collect source file "generated from" relationship comments for the given sources.
|
||||||
|
function(_qt_internal_sbom_add_source_files)
|
||||||
|
set(opt_args "")
|
||||||
|
set(single_args
|
||||||
|
SPDX_ID
|
||||||
|
OUT_RELATIONSHIPS_VAR
|
||||||
|
)
|
||||||
|
set(multi_args
|
||||||
|
SOURCES
|
||||||
|
)
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}")
|
||||||
|
_qt_internal_validate_all_args_are_parsed(arg)
|
||||||
|
|
||||||
|
if(NOT arg_SPDX_ID)
|
||||||
|
message(FATAL_ERROR "SPDX_ID must be set")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT arg_OUT_RELATIONSHIPS_VAR)
|
||||||
|
message(FATAL_ERROR "OUT_RELATIONSHIPS_VAR must be set")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT arg_SOURCES)
|
||||||
|
set(sources "")
|
||||||
|
else()
|
||||||
|
set(sources "${arg_SOURCES}")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(relationships "")
|
set(relationships "")
|
||||||
|
|
||||||
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
|
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
|
||||||
@ -1750,7 +2239,7 @@ function(_qt_internal_sbom_add_source_files target spdx_id out_relationships)
|
|||||||
list(APPEND relationships "${relationship}")
|
list(APPEND relationships "${relationship}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set(${out_relationships} "${relationships}" PARENT_SCOPE)
|
set(${arg_OUT_RELATIONSHIPS_VAR} "${relationships}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Adds a license id and its text to the sbom.
|
# Adds a license id and its text to the sbom.
|
||||||
@ -2865,6 +3354,10 @@ function(_qt_internal_sbom_is_qt_entity_type sbom_type out_var)
|
|||||||
QT_PLUGIN
|
QT_PLUGIN
|
||||||
QT_APP
|
QT_APP
|
||||||
QT_TOOL
|
QT_TOOL
|
||||||
|
QT_TRANSLATIONS
|
||||||
|
QT_RESOURCES
|
||||||
|
QT_CUSTOM
|
||||||
|
QT_CUSTOM_NO_INFIX
|
||||||
)
|
)
|
||||||
|
|
||||||
set(is_qt_entity_type FALSE)
|
set(is_qt_entity_type FALSE)
|
||||||
@ -2949,6 +3442,14 @@ function(_qt_internal_sbom_get_package_infix type out_infix)
|
|||||||
set(package_infix "qt-bundled-3rdparty-module")
|
set(package_infix "qt-bundled-3rdparty-module")
|
||||||
elseif(type STREQUAL "QT_THIRD_PARTY_SOURCES")
|
elseif(type STREQUAL "QT_THIRD_PARTY_SOURCES")
|
||||||
set(package_infix "qt-3rdparty-sources")
|
set(package_infix "qt-3rdparty-sources")
|
||||||
|
elseif(type STREQUAL "QT_TRANSLATIONS")
|
||||||
|
set(package_infix "qt-translation")
|
||||||
|
elseif(type STREQUAL "QT_RESOURCES")
|
||||||
|
set(package_infix "qt-resource")
|
||||||
|
elseif(type STREQUAL "QT_CUSTOM")
|
||||||
|
set(package_infix "qt-custom")
|
||||||
|
elseif(type STREQUAL "QT_CUSTOM_NO_INFIX")
|
||||||
|
set(package_infix "qt")
|
||||||
elseif(type STREQUAL "SYSTEM_LIBRARY")
|
elseif(type STREQUAL "SYSTEM_LIBRARY")
|
||||||
set(package_infix "system-3rdparty")
|
set(package_infix "system-3rdparty")
|
||||||
elseif(type STREQUAL "EXECUTABLE")
|
elseif(type STREQUAL "EXECUTABLE")
|
||||||
@ -2959,6 +3460,14 @@ function(_qt_internal_sbom_get_package_infix type out_infix)
|
|||||||
set(package_infix "3rdparty-library")
|
set(package_infix "3rdparty-library")
|
||||||
elseif(type STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES")
|
elseif(type STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES")
|
||||||
set(package_infix "3rdparty-library-with-files")
|
set(package_infix "3rdparty-library-with-files")
|
||||||
|
elseif(type STREQUAL "TRANSLATIONS")
|
||||||
|
set(package_infix "translations")
|
||||||
|
elseif(type STREQUAL "RESOURCES")
|
||||||
|
set(package_infix "resource")
|
||||||
|
elseif(type STREQUAL "CUSTOM")
|
||||||
|
set(package_infix "custom")
|
||||||
|
elseif(type STREQUAL "CUSTOM_NO_INFIX")
|
||||||
|
set(package_infix "")
|
||||||
else()
|
else()
|
||||||
message(DEBUG "No package infix due to unknown type: ${type}")
|
message(DEBUG "No package infix due to unknown type: ${type}")
|
||||||
set(package_infix "")
|
set(package_infix "")
|
||||||
@ -2982,6 +3491,14 @@ function(_qt_internal_sbom_get_package_purpose type out_purpose)
|
|||||||
set(package_purpose "LIBRARY")
|
set(package_purpose "LIBRARY")
|
||||||
elseif(type STREQUAL "QT_THIRD_PARTY_SOURCES")
|
elseif(type STREQUAL "QT_THIRD_PARTY_SOURCES")
|
||||||
set(package_purpose "LIBRARY")
|
set(package_purpose "LIBRARY")
|
||||||
|
elseif(type STREQUAL "QT_TRANSLATIONS")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
|
elseif(type STREQUAL "QT_RESOURCES")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
|
elseif(type STREQUAL "QT_CUSTOM")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
|
elseif(type STREQUAL "QT_CUSTOM_NO_INFIX")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
elseif(type STREQUAL "SYSTEM_LIBRARY")
|
elseif(type STREQUAL "SYSTEM_LIBRARY")
|
||||||
set(package_purpose "LIBRARY")
|
set(package_purpose "LIBRARY")
|
||||||
elseif(type STREQUAL "EXECUTABLE")
|
elseif(type STREQUAL "EXECUTABLE")
|
||||||
@ -2992,6 +3509,14 @@ function(_qt_internal_sbom_get_package_purpose type out_purpose)
|
|||||||
set(package_purpose "LIBRARY")
|
set(package_purpose "LIBRARY")
|
||||||
elseif(type STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES")
|
elseif(type STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES")
|
||||||
set(package_purpose "LIBRARY")
|
set(package_purpose "LIBRARY")
|
||||||
|
elseif(type STREQUAL "TRANSLATIONS")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
|
elseif(type STREQUAL "RESOURCES")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
|
elseif(type STREQUAL "CUSTOM")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
|
elseif(type STREQUAL "CUSTOM_NO_INFIX")
|
||||||
|
set(package_purpose "OTHER")
|
||||||
else()
|
else()
|
||||||
set(package_purpose "OTHER")
|
set(package_purpose "OTHER")
|
||||||
endif()
|
endif()
|
||||||
@ -3669,8 +4194,8 @@ function(_qt_internal_sbom_handle_multi_config_target_binary_file target)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Helper to retrieve a list of multi-config aware option names that can be parsed by the binary
|
# Helper to retrieve a list of multi-config aware option names that can be parsed by the
|
||||||
# file handling function.
|
# file handling functions.
|
||||||
# For example in single config we need to parse RUNTIME_PATH, in multi-config we need to parse
|
# For example in single config we need to parse RUNTIME_PATH, in multi-config we need to parse
|
||||||
# RUNTIME_PATH_DEBUG and RUNTIME_PATH_RELEASE.
|
# RUNTIME_PATH_DEBUG and RUNTIME_PATH_RELEASE.
|
||||||
#
|
#
|
||||||
@ -3694,19 +4219,26 @@ function(_qt_internal_sbom_get_multi_config_single_args out_var)
|
|||||||
FRAMEWORK_PATH
|
FRAMEWORK_PATH
|
||||||
)
|
)
|
||||||
|
|
||||||
|
list(APPEND single_args "${single_args_to_process}")
|
||||||
|
|
||||||
|
# We need to process multi config args even in a single config build, because there might be API
|
||||||
|
# calls that specify them directly. Use a default set of multi config configs.
|
||||||
|
set(configs Release RelWithDebInfo MinSizeRel Debug)
|
||||||
|
|
||||||
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||||
if(is_multi_config)
|
if(is_multi_config AND CMAKE_CONFIGURATION_TYPES)
|
||||||
set(configs ${CMAKE_CONFIGURATION_TYPES})
|
list(APPEND configs ${CMAKE_CONFIGURATION_TYPES})
|
||||||
foreach(config IN LISTS configs)
|
|
||||||
string(TOUPPER ${config} config_upper)
|
|
||||||
foreach(single_arg IN LISTS single_args_to_process)
|
|
||||||
list(APPEND single_args "${single_arg}_${config_upper}")
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
else()
|
|
||||||
list(APPEND single_args "${single_args_to_process}")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
list(REMOVE_DUPLICATES configs)
|
||||||
|
|
||||||
|
foreach(config IN LISTS configs)
|
||||||
|
string(TOUPPER ${config} config_upper)
|
||||||
|
foreach(single_arg IN LISTS single_args_to_process)
|
||||||
|
list(APPEND single_args "${single_arg}_${config_upper}")
|
||||||
|
endforeach()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY
|
set_property(GLOBAL PROPERTY
|
||||||
_qt_internal_sbom_multi_config_single_args "${single_args}")
|
_qt_internal_sbom_multi_config_single_args "${single_args}")
|
||||||
set(${out_var} ${single_args} PARENT_SCOPE)
|
set(${out_var} ${single_args} PARENT_SCOPE)
|
||||||
@ -3736,11 +4268,14 @@ function(_qt_internal_sbom_get_and_check_multi_config_aware_single_arg_option
|
|||||||
arg_prefix arg_name config out_var)
|
arg_prefix arg_name config out_var)
|
||||||
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
|
||||||
|
# Prefer the multi config option if it is set.
|
||||||
if(is_multi_config)
|
if(is_multi_config)
|
||||||
string(TOUPPER ${config} config_upper)
|
string(TOUPPER ${config} config_upper)
|
||||||
set(outer_scope_var_name "${arg_prefix}_${arg_name}_${config_upper}")
|
set(outer_scope_var_name "${arg_prefix}_${arg_name}_${config_upper}")
|
||||||
set(option_name "${arg_name}_${config_upper}")
|
set(option_name "${arg_name}_${config_upper}")
|
||||||
else()
|
endif()
|
||||||
|
|
||||||
|
if(NOT is_multi_config OR NOT DEFINED ${outer_scope_var_name})
|
||||||
set(outer_scope_var_name "${arg_prefix}_${arg_name}")
|
set(outer_scope_var_name "${arg_prefix}_${arg_name}")
|
||||||
set(option_name "${arg_name}")
|
set(option_name "${arg_name}")
|
||||||
endif()
|
endif()
|
||||||
|
@ -31,3 +31,7 @@ function(qt_internal_sbom_end_qt_repo_project)
|
|||||||
_qt_internal_sbom_end_qt_repo_project(${ARGN})
|
_qt_internal_sbom_end_qt_repo_project(${ARGN})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
function(qt_internal_sbom_add_files)
|
||||||
|
_qt_internal_sbom_add_files(${ARGN})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user