It's possible for a project to install a custom file with the same name into different destination directories, and want to include them in the SBOM. Previously this failed at CMake generation time with an error like: CMake Error: Files to be generated by multiple different commands: qt_sbom/SPDXRef-PackagedFile-foo-bar.cmake This happened due to using a non-unique filename for the generated SBOM building file, as well as the spdx id the file name is based on. Include a short hash based on the installed relative path of the file to avoid spdx id clashes, and thus generated file name clashes. Pick-to: 6.8 Task-number: QTBUG-122899 Change-Id: I4c2ecd4652708504ef299af9b6f53d680d542382 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io> (cherry picked from commit 9245d0a0f0761364e7b5b3d1c5c96cba16522820) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
1150 lines
40 KiB
CMake
1150 lines
40 KiB
CMake
# Copyright (C) 2024 The Qt Company Ltd.
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
# Handles addition of binary files SPDX entries for a given target.
|
|
# Is multi-config aware.
|
|
function(_qt_internal_sbom_handle_target_binary_files target)
|
|
set(opt_args
|
|
NO_INSTALL
|
|
FRAMEWORK
|
|
)
|
|
set(single_args
|
|
TYPE
|
|
SPDX_ID
|
|
LICENSE_EXPRESSION
|
|
INSTALL_PREFIX
|
|
)
|
|
set(multi_args
|
|
COPYRIGHTS
|
|
)
|
|
|
|
_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)
|
|
|
|
if(arg_NO_INSTALL)
|
|
message(DEBUG "Skipping sbom target file processing ${target} because NO_INSTALL is set")
|
|
return()
|
|
endif()
|
|
|
|
if(QT_SBOM_SKIP_BINARY_FILES)
|
|
message(DEBUG "Skipping sbom target file processing ${target} because "
|
|
"QT_SBOM_SKIP_BINARY_FILES is set")
|
|
return()
|
|
endif()
|
|
|
|
set(supported_types
|
|
QT_MODULE
|
|
QT_PLUGIN
|
|
QT_APP
|
|
QT_TOOL
|
|
QT_THIRD_PARTY_MODULE
|
|
QT_THIRD_PARTY_SOURCES
|
|
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.
|
|
THIRD_PARTY_LIBRARY
|
|
THIRD_PARTY_LIBRARY_WITH_FILES
|
|
THIRD_PARTY_SOURCES
|
|
EXECUTABLE
|
|
LIBRARY
|
|
TRANSLATIONS
|
|
RESOURCES
|
|
CUSTOM
|
|
CUSTOM_NO_INFIX
|
|
)
|
|
|
|
if(NOT arg_TYPE IN_LIST supported_types)
|
|
message(FATAL_ERROR "Unsupported target TYPE for SBOM creation: ${arg_TYPE}")
|
|
endif()
|
|
|
|
set(types_without_binary_files
|
|
QT_THIRD_PARTY_SOURCES
|
|
QT_TRANSLATIONS
|
|
QT_RESOURCES
|
|
QT_CUSTOM
|
|
QT_CUSTOM_NO_INFIX
|
|
SYSTEM_LIBRARY
|
|
THIRD_PARTY_LIBRARY
|
|
THIRD_PARTY_SOURCES
|
|
TRANSLATIONS
|
|
RESOURCES
|
|
CUSTOM
|
|
CUSTOM_NO_INFIX
|
|
)
|
|
|
|
get_target_property(target_type ${target} TYPE)
|
|
|
|
if(arg_TYPE IN_LIST types_without_binary_files)
|
|
message(DEBUG "Target ${target} has no binary files to reference in the SBOM "
|
|
"because it has the ${arg_TYPE} type.")
|
|
return()
|
|
endif()
|
|
|
|
if(target_type STREQUAL "INTERFACE_LIBRARY")
|
|
message(DEBUG "Target ${target} has no binary files to reference in the SBOM "
|
|
"because it is an INTERFACE_LIBRARY.")
|
|
return()
|
|
endif()
|
|
|
|
get_target_property(excluded ${target} _qt_internal_excluded_from_default_target)
|
|
if(excluded)
|
|
message(DEBUG "Target ${target} has no binary files to reference in the SBOM "
|
|
"because it was excluded from the default 'all' target.")
|
|
return()
|
|
endif()
|
|
|
|
if(NOT arg_SPDX_ID)
|
|
message(FATAL_ERROR "SPDX_ID must be set")
|
|
endif()
|
|
set(package_spdx_id "${arg_SPDX_ID}")
|
|
|
|
set(file_common_options "")
|
|
|
|
list(APPEND file_common_options PACKAGE_SPDX_ID "${package_spdx_id}")
|
|
list(APPEND file_common_options PACKAGE_TYPE "${arg_TYPE}")
|
|
|
|
if(arg_COPYRIGHTS)
|
|
list(APPEND file_common_options COPYRIGHTS "${arg_COPYRIGHTS}")
|
|
endif()
|
|
|
|
if(arg_LICENSE_EXPRESSION)
|
|
list(APPEND file_common_options LICENSE_EXPRESSION "${arg_LICENSE_EXPRESSION}")
|
|
endif()
|
|
|
|
if(arg_INSTALL_PREFIX)
|
|
list(APPEND file_common_options INSTALL_PREFIX "${arg_INSTALL_PREFIX}")
|
|
endif()
|
|
|
|
set(path_suffix "$<TARGET_FILE_NAME:${target}>")
|
|
|
|
if(arg_FRAMEWORK)
|
|
set(library_path_kind FRAMEWORK_PATH)
|
|
else()
|
|
set(library_path_kind LIBRARY_PATH)
|
|
endif()
|
|
|
|
if(arg_TYPE STREQUAL "QT_TOOL"
|
|
OR arg_TYPE STREQUAL "QT_APP"
|
|
OR arg_TYPE STREQUAL "EXECUTABLE")
|
|
|
|
set(valid_executable_types
|
|
"EXECUTABLE"
|
|
)
|
|
if(ANDROID)
|
|
list(APPEND valid_executable_types "MODULE_LIBRARY")
|
|
endif()
|
|
if(NOT target_type IN_LIST valid_executable_types)
|
|
message(FATAL_ERROR "Unsupported target type: ${target_type}")
|
|
endif()
|
|
|
|
get_target_property(app_is_bundle ${target} MACOSX_BUNDLE)
|
|
if(app_is_bundle)
|
|
_qt_internal_get_executable_bundle_info(bundle "${target}")
|
|
_qt_internal_path_join(path_suffix "${bundle_contents_binary_dir}" "${path_suffix}")
|
|
endif()
|
|
|
|
_qt_internal_sbom_handle_multi_config_target_binary_file(${target}
|
|
PATH_KIND RUNTIME_PATH
|
|
PATH_SUFFIX "${path_suffix}"
|
|
OPTIONS ${file_common_options}
|
|
)
|
|
elseif(arg_TYPE STREQUAL "QT_PLUGIN")
|
|
if(NOT (target_type STREQUAL "SHARED_LIBRARY"
|
|
OR target_type STREQUAL "STATIC_LIBRARY"
|
|
OR target_type STREQUAL "MODULE_LIBRARY"))
|
|
message(FATAL_ERROR "Unsupported target type: ${target_type}")
|
|
endif()
|
|
|
|
_qt_internal_sbom_handle_multi_config_target_binary_file(${target}
|
|
PATH_KIND INSTALL_PATH
|
|
PATH_SUFFIX "${path_suffix}"
|
|
OPTIONS ${file_common_options}
|
|
)
|
|
elseif(arg_TYPE STREQUAL "QT_MODULE"
|
|
OR arg_TYPE STREQUAL "QT_THIRD_PARTY_MODULE"
|
|
OR arg_TYPE STREQUAL "LIBRARY"
|
|
OR arg_TYPE STREQUAL "THIRD_PARTY_LIBRARY_WITH_FILES"
|
|
)
|
|
if(WIN32 AND target_type STREQUAL "SHARED_LIBRARY")
|
|
_qt_internal_sbom_handle_multi_config_target_binary_file(${target}
|
|
PATH_KIND RUNTIME_PATH
|
|
PATH_SUFFIX "${path_suffix}"
|
|
OPTIONS ${file_common_options}
|
|
)
|
|
|
|
_qt_internal_sbom_handle_multi_config_target_binary_file(${target}
|
|
PATH_KIND ARCHIVE_PATH
|
|
PATH_SUFFIX "$<TARGET_LINKER_FILE_NAME:${target}>"
|
|
OPTIONS
|
|
${file_common_options}
|
|
IMPORT_LIBRARY
|
|
# OPTIONAL because on Windows the import library might not always be present,
|
|
# because no symbols are exported.
|
|
OPTIONAL
|
|
)
|
|
elseif(target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "STATIC_LIBRARY")
|
|
_qt_internal_sbom_handle_multi_config_target_binary_file(${target}
|
|
PATH_KIND "${library_path_kind}"
|
|
PATH_SUFFIX "${path_suffix}"
|
|
OPTIONS ${file_common_options}
|
|
)
|
|
else()
|
|
message(FATAL_ERROR "Unsupported target type: ${target_type}")
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
# 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,
|
|
# 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)
|
|
set(opt_args
|
|
OPTIONAL
|
|
IMPORT_LIBRARY
|
|
)
|
|
set(single_args
|
|
PACKAGE_SPDX_ID
|
|
PACKAGE_TYPE
|
|
LICENSE_EXPRESSION
|
|
CONFIG
|
|
INSTALL_PREFIX
|
|
)
|
|
set(multi_args
|
|
COPYRIGHTS
|
|
)
|
|
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()
|
|
|
|
set(file_infix "")
|
|
if(arg_IMPORT_LIBRARY)
|
|
set(file_infix "-ImportLibrary")
|
|
endif()
|
|
|
|
# We kind of have to add the package infix into the file spdx, otherwise we get file system
|
|
# collisions for cases like the qml tool and Qml library, and apparently cmake's file(GENERATE)
|
|
# is case insensitive for file names.
|
|
_qt_internal_sbom_get_package_infix("${arg_PACKAGE_TYPE}" package_infix)
|
|
|
|
_qt_internal_sbom_get_file_spdx_id(
|
|
"${package_infix}-${target}-${file_infix}-${spdx_id_suffix}" spdx_id)
|
|
|
|
set(optional "")
|
|
if(arg_OPTIONAL)
|
|
set(optional OPTIONAL)
|
|
endif()
|
|
|
|
# Add relationship from owning package.
|
|
set(relationships "${arg_PACKAGE_SPDX_ID} CONTAINS ${spdx_id}")
|
|
|
|
# Add source file relationships from which the binary file was generated.
|
|
if(NOT QT_SBOM_SKIP_SOURCE_FILES)
|
|
_qt_internal_sbom_add_target_source_files("${target}" "${spdx_id}" source_relationships)
|
|
if(source_relationships)
|
|
list(APPEND relationships "${source_relationships}")
|
|
endif()
|
|
else()
|
|
message(DEBUG "Skipping sbom source file processing for file '${file_path}' because "
|
|
"QT_SBOM_SKIP_SOURCE_FILES is set")
|
|
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}")
|
|
|
|
# Add the actual binary file to the latest package.
|
|
_qt_internal_sbom_generate_add_file(
|
|
FILENAME "${file_path}"
|
|
FILETYPE BINARY ${optional}
|
|
SPDXID "${spdx_id}"
|
|
${file_common_options}
|
|
${config_to_install_option}
|
|
${relationship_option}
|
|
)
|
|
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(QT_SBOM_SKIP_CUSTOM_FILES)
|
|
message(DEBUG "Skipping sbom custom file processing ${target} because "
|
|
"QT_SBOM_SKIP_BINARY_FILES 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_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.
|
|
#
|
|
# DIRECTORIES - a list of directories which will be file(GLOB_RECURSE)d to find files to include in
|
|
# the SBOM.
|
|
#
|
|
# 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
|
|
DIRECTORIES
|
|
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 AND NOT arg_DIRECTORIES)
|
|
return()
|
|
endif()
|
|
|
|
# Don't forward the FILES and DIRECTORIES options.
|
|
set(multi_args_without_files "${multi_args}")
|
|
list(REMOVE_ITEM multi_args_without_files FILES DIRECTORIES)
|
|
|
|
# Handle the case where we have one source file per input file.
|
|
if(arg_SOURCE_FILES_PER_INPUT_FILE)
|
|
if(NOT arg_FILES)
|
|
message(FATAL_ERROR "SOURCE_FILES_PER_INPUT_FILE can only be set if FILES is set.")
|
|
endif()
|
|
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(files "")
|
|
if(arg_FILES)
|
|
list(APPEND files ${arg_FILES})
|
|
endif()
|
|
|
|
set(directories "")
|
|
if(arg_DIRECTORIES)
|
|
list(APPEND directories ${arg_DIRECTORIES})
|
|
endif()
|
|
|
|
set(relative_file_paths "")
|
|
|
|
# For each file in FILES, we only add the file name as a suffix, and not the path relative to
|
|
# the current source dir, because that's how install(FILES) behaves. The final installed
|
|
# destination is ${arg_INSTALL_PATH}/${file_name}.
|
|
foreach(file_path IN LISTS files)
|
|
get_filename_component(relative_file_path "${file_path}" NAME)
|
|
list(APPEND relative_file_paths "${relative_file_path}")
|
|
endforeach()
|
|
|
|
# For each file globbed in DIRECTORIES, we add the file path relative to the current source dir
|
|
# + all components of the given DIRECTORY except for the last one.
|
|
# That's how install(DIRECTORY) behaves.
|
|
# So the final installed destination is
|
|
# ${arg_INSTALL_PATH}/${directory_without_last_component}/${path_to_file}.
|
|
foreach(directory IN LISTS directories)
|
|
file(GLOB_RECURSE files_in_directory "${directory}/*")
|
|
set(directory_abs_path "${CMAKE_CURRENT_SOURCE_DIR}/${directory}")
|
|
get_filename_component(parent_dir "${directory_abs_path}" DIRECTORY)
|
|
foreach(file_path IN LISTS files_in_directory)
|
|
file(RELATIVE_PATH relative_file_path "${parent_dir}" "${file_path}")
|
|
list(APPEND relative_file_paths "${relative_file_path}")
|
|
endforeach()
|
|
endforeach()
|
|
|
|
set(file_index 0)
|
|
foreach(relative_file_path IN LISTS relative_file_paths)
|
|
set(per_file_forward_args "")
|
|
|
|
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 "${relative_file_path}"
|
|
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()
|
|
|
|
# Append a short hash based on the installed relative path of the file, to avoid spdx id
|
|
# clashes for files with the same name installed into different dirs.
|
|
get_filename_component(file_name "${installed_file_relative_path}" NAME)
|
|
string(SHA1 rel_path_hash "${installed_file_relative_path}")
|
|
string(SUBSTRING "${rel_path_hash}" 0 4 short_hash)
|
|
set(file_name "${file_name}-${short_hash}")
|
|
|
|
_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()
|
|
|
|
# Add source file relationships from which the binary file was generated.
|
|
if(NOT QT_SBOM_SKIP_SOURCE_FILES)
|
|
_qt_internal_sbom_add_source_files(
|
|
${sources_option}
|
|
SPDX_ID "${spdx_id}"
|
|
OUT_RELATIONSHIPS_VAR source_relationships
|
|
)
|
|
else()
|
|
message(DEBUG "Skipping sbom source file processing for file "
|
|
"'${installed_file_relative_path}' because QT_SBOM_SKIP_SOURCE_FILES is set")
|
|
endif()
|
|
|
|
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
|
|
# the project source or build dir.
|
|
function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var)
|
|
set(opt_args "")
|
|
set(single_args
|
|
PATH
|
|
REPO_PROJECT_NAME_LOWERCASE
|
|
OUT_SUCCESS
|
|
)
|
|
set(multi_args "")
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
|
|
_qt_internal_validate_all_args_are_parsed(arg)
|
|
|
|
set(is_in_source_dir FALSE)
|
|
set(is_in_build_dir FALSE)
|
|
|
|
if(NOT arg_REPO_PROJECT_NAME_LOWERCASE)
|
|
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name)
|
|
else()
|
|
set(repo_project_name "${arg_REPO_PROJECT_NAME_LOWERCASE}")
|
|
endif()
|
|
|
|
if(NOT DEFINED arg_PATH)
|
|
message(FATAL_ERROR "PATH must be set")
|
|
endif()
|
|
set(path "${arg_PATH}")
|
|
|
|
set(handled FALSE)
|
|
|
|
if(path MATCHES "$<.+>")
|
|
# TODO: Paths wrapped in genexes are usually absolute paths that we also want to handle,
|
|
# but can't at configure time. We'll need a separate processing step at build time.
|
|
# Keep these as is for now, but signal failure of handling.
|
|
set(path_out "${path}")
|
|
else()
|
|
if(IS_ABSOLUTE "${path}")
|
|
set(path_in "${path}")
|
|
|
|
string(FIND "${path}" "${PROJECT_SOURCE_DIR}/" src_idx)
|
|
string(FIND "${path}" "${PROJECT_BINARY_DIR}/" dest_idx)
|
|
|
|
if(src_idx EQUAL "0")
|
|
set(is_in_source_dir TRUE)
|
|
elseif(dest_idx EQUAL "0")
|
|
set(is_in_build_dir TRUE)
|
|
endif()
|
|
else()
|
|
# We consider relative paths to be relative to the current source dir.
|
|
set(is_in_source_dir TRUE)
|
|
set(path_in "${CMAKE_CURRENT_SOURCE_DIR}/${path}")
|
|
endif()
|
|
|
|
# Resolve any .. and replace the absolute path with a path relative to the source dir
|
|
# or build dir, prefixed with a root marker.
|
|
get_filename_component(path_in_real "${path_in}" REALPATH)
|
|
|
|
# Replace the absolute prefixes with markers.
|
|
if(is_in_source_dir)
|
|
set(handled TRUE)
|
|
set(marker "/src_dir")
|
|
string(REPLACE "${PROJECT_SOURCE_DIR}/" "${marker}/${repo_project_name}/"
|
|
path_out "${path_in_real}")
|
|
elseif(is_in_build_dir)
|
|
set(handled TRUE)
|
|
set(marker "/build_dir")
|
|
string(REPLACE "${PROJECT_BINARY_DIR}/" "${marker}/${repo_project_name}/"
|
|
path_out "${path_in_real}")
|
|
else()
|
|
# If it's not a source dir or a build dir, it might be some kind of weird genex
|
|
# or marker that we don't handle yet.
|
|
set(path_out "${path_in_real}")
|
|
endif()
|
|
endif()
|
|
|
|
set(${out_var} "${path_out}" PARENT_SCOPE)
|
|
if(arg_OUT_SUCCESS)
|
|
set(${arg_OUT_SUCCESS} "${handled}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Collect source file "generated from" relationship comments for a given target file.
|
|
function(_qt_internal_sbom_add_target_source_files target spdx_id out_relationships)
|
|
get_target_property(sources ${target} SOURCES)
|
|
if(NOT sources)
|
|
set(sources "")
|
|
endif()
|
|
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 "")
|
|
|
|
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
|
|
|
|
foreach(source IN LISTS sources)
|
|
# Filter out $<TARGET_OBJECTS: genexes>.
|
|
if(source MATCHES "^\\$<TARGET_OBJECTS:.*>$")
|
|
continue()
|
|
endif()
|
|
|
|
# Filter out prl files.
|
|
if(source MATCHES "\.prl$")
|
|
continue()
|
|
endif()
|
|
|
|
# Filter out pkg-config. pc files.
|
|
if(source MATCHES "\.pc$")
|
|
continue()
|
|
endif()
|
|
|
|
# Filter out metatypes .json.gen files.
|
|
if(source MATCHES "\.json\.gen$")
|
|
continue()
|
|
endif()
|
|
|
|
_qt_internal_sbom_map_path_to_reproducible_relative_path(source_path
|
|
PATH "${source}"
|
|
REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}"
|
|
)
|
|
|
|
set(source_entry
|
|
"${spdx_id} GENERATED_FROM NOASSERTION\nRelationshipComment: ${source_path}"
|
|
)
|
|
set(source_non_empty "$<BOOL:${source_path}>")
|
|
# Some sources are conditional on genexes, so we evaluate them.
|
|
set(relationship "$<${source_non_empty}:$<GENEX_EVAL:${source_entry}>>")
|
|
list(APPEND relationships "${relationship}")
|
|
endforeach()
|
|
|
|
set(${arg_OUT_RELATIONSHIPS_VAR} "${relationships}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Collects app bundle related information and paths from an executable's target properties.
|
|
# Output variables:
|
|
# <out_var>_name bundle base name, e.g. 'Linguist'.
|
|
# <out_var>_dir_name bundle dir name, e.g. 'Linguist.app'.
|
|
# <out_var>_contents_dir bundle contents dir, e.g. 'Linguist.app/Contents'
|
|
# <out_var>_contents_binary_dir bundle contents dir, e.g. 'Linguist.app/Contents/MacOS'
|
|
function(_qt_internal_get_executable_bundle_info out_var target)
|
|
get_target_property(target_type ${target} TYPE)
|
|
if(NOT "${target_type}" STREQUAL "EXECUTABLE")
|
|
message(FATAL_ERROR "The target ${target} is not an executable")
|
|
endif()
|
|
|
|
get_target_property(output_name ${target} OUTPUT_NAME)
|
|
if(NOT output_name)
|
|
set(output_name "${target}")
|
|
endif()
|
|
|
|
set(${out_var}_name "${output_name}")
|
|
set(${out_var}_dir_name "${${out_var}_name}.app")
|
|
set(${out_var}_contents_dir "${${out_var}_dir_name}/Contents")
|
|
set(${out_var}_contents_binary_dir "${${out_var}_contents_dir}/MacOS")
|
|
|
|
set(${out_var}_name "${${out_var}_name}" PARENT_SCOPE)
|
|
set(${out_var}_dir_name "${${out_var}_dir_name}" PARENT_SCOPE)
|
|
set(${out_var}_contents_dir "${${out_var}_contents_dir}" PARENT_SCOPE)
|
|
set(${out_var}_contents_binary_dir "${${out_var}_contents_binary_dir}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Helper function to add binary 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 (the case for debug tools and apps in debug-and-release builds).
|
|
function(_qt_internal_sbom_handle_multi_config_target_binary_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_binary_file(
|
|
"${target}"
|
|
"${file_path}"
|
|
${arg_OPTIONS}
|
|
${is_optional}
|
|
CONFIG ${config}
|
|
)
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# Helper to retrieve a list of multi-config aware option names that can be parsed by the
|
|
# file handling functions.
|
|
# 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.
|
|
#
|
|
# Result is cached in a global property.
|
|
function(_qt_internal_sbom_get_multi_config_single_args out_var)
|
|
get_cmake_property(single_args
|
|
_qt_internal_sbom_multi_config_single_args)
|
|
|
|
if(single_args)
|
|
set(${out_var} ${single_args} PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
set(single_args "")
|
|
|
|
set(single_args_to_process
|
|
INSTALL_PATH
|
|
RUNTIME_PATH
|
|
LIBRARY_PATH
|
|
ARCHIVE_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)
|
|
if(is_multi_config AND CMAKE_CONFIGURATION_TYPES)
|
|
list(APPEND configs ${CMAKE_CONFIGURATION_TYPES})
|
|
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
|
|
_qt_internal_sbom_multi_config_single_args "${single_args}")
|
|
set(${out_var} ${single_args} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Helper to apped a an option and a value to a list of options, while being multi-config aware.
|
|
# It appends e.g. either RUNTIME_PATH foo or RUNTIME_PATH_DEBUG foo to the out_var_args variable.
|
|
function(_qt_internal_sbom_append_multi_config_aware_single_arg_option
|
|
arg_name arg_value config out_var_args)
|
|
set(values "${${out_var_args}}")
|
|
|
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
|
if(is_multi_config)
|
|
string(TOUPPER ${config} config_upper)
|
|
list(APPEND values "${arg_name}_${config_upper}" "${arg_value}")
|
|
else()
|
|
list(APPEND values "${arg_name}" "${arg_value}")
|
|
endif()
|
|
|
|
set(${out_var_args} "${values}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Helper to check whether a given option was set in the outer scope, while being multi-config
|
|
# aware.
|
|
# It checks e.g. if either arg_RUNTIME_PATH or arg_RUNTIME_PATH_DEBUG is set in the outer scope.
|
|
function(_qt_internal_sbom_get_and_check_multi_config_aware_single_arg_option
|
|
arg_prefix arg_name config out_var)
|
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
|
|
|
# Prefer the multi config option if it is set.
|
|
if(is_multi_config)
|
|
string(TOUPPER ${config} config_upper)
|
|
set(outer_scope_var_name "${arg_prefix}_${arg_name}_${config_upper}")
|
|
set(option_name "${arg_name}_${config_upper}")
|
|
endif()
|
|
|
|
if(NOT is_multi_config OR NOT DEFINED ${outer_scope_var_name})
|
|
set(outer_scope_var_name "${arg_prefix}_${arg_name}")
|
|
set(option_name "${arg_name}")
|
|
endif()
|
|
|
|
if(NOT DEFINED ${outer_scope_var_name})
|
|
message(FATAL_ERROR "Missing ${option_name}")
|
|
endif()
|
|
|
|
set(${out_var} "${${outer_scope_var_name}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Checks if given config is not the first config in a multi-config build, and thus file installation
|
|
# for that config should be optional.
|
|
function(_qt_internal_sbom_is_config_optional_in_multi_config config out_var)
|
|
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
|
|
|
if(QT_MULTI_CONFIG_FIRST_CONFIG)
|
|
set(first_config_type "${QT_MULTI_CONFIG_FIRST_CONFIG}")
|
|
elseif(CMAKE_CONFIGURATION_TYPES)
|
|
list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
|
|
endif()
|
|
|
|
if(is_multi_config AND NOT (cmake_config STREQUAL first_config_type))
|
|
set(is_optional TRUE)
|
|
else()
|
|
set(is_optional FALSE)
|
|
endif()
|
|
|
|
set(${out_var} "${is_optional}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Checks if given config is not the first config in a multi-config build, and thus file installation
|
|
# for that config should be optional, sets the actual option name.
|
|
function(_qt_internal_sbom_get_target_file_is_optional_in_multi_config config out_var)
|
|
_qt_internal_sbom_is_config_optional_in_multi_config("${config}" is_optional)
|
|
|
|
if(is_optional)
|
|
set(option "OPTIONAL")
|
|
else()
|
|
set(option "")
|
|
endif()
|
|
|
|
set(${out_var} "${option}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Get a sanitized spdx id for a file.
|
|
# For consistency, we prefix the id with SPDXRef-PackagedFile-. This is not a requirement.
|
|
function(_qt_internal_sbom_get_file_spdx_id target out_var)
|
|
_qt_internal_sbom_get_sanitized_spdx_id(spdx_id "SPDXRef-PackagedFile-${target}")
|
|
set(${out_var} "${spdx_id}" PARENT_SCOPE)
|
|
endfunction()
|