qtbase/cmake/QtPublicSbomSystemDepHelpers.cmake
Alexandru Croitor 27d2b54b5d CMake: Split SBOM implementation into separate files
The SBOM implementation got somewhat large. Split the code into
several new QtPublicSbomFooHelpers.cmake files, to make it more
manageable.

No code or behavior was changed.

Pick-to: 6.8 6.9
Task-number: QTBUG-122899
Change-Id: Ia0ca1792eec21d12c4bb4cabe63279e1f5c07e3d
Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
2025-01-10 18:42:22 +01:00

163 lines
7.0 KiB
CMake

# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Records information about a system library target, usually due to a qt_find_package call.
# This information is later used to generate packages for the system libraries, but only after
# confirming that the library was used (linked) into any of the Qt targets.
function(_qt_internal_sbom_record_system_library_usage target)
if(NOT QT_GENERATE_SBOM)
return()
endif()
set(opt_args "")
set(single_args
TYPE
PACKAGE_VERSION
FRIENDLY_PACKAGE_NAME
)
set(multi_args "")
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
_qt_internal_validate_all_args_are_parsed(arg)
if(NOT arg_TYPE)
message(FATAL_ERROR "TYPE must be set")
endif()
# A package might be looked up more than once, make sure to record it once.
get_property(already_recorded GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_target_${target})
if(already_recorded)
return()
endif()
set_property(GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_target_${target} TRUE)
# Defer spdx id creation until _qt_internal_sbom_begin_project is called, so we know the
# project name. The project name is used in the package infix generation of the system library,
# but _qt_internal_sbom_record_system_library_usage might be called before sbom generation
# has started, e.g. during _qt_internal_find_third_party_dependencies.
set(spdx_options
${target}
TYPE "${arg_TYPE}"
PACKAGE_NAME "${arg_FRIENDLY_PACKAGE_NAME}"
)
get_cmake_property(sbom_repo_begin_called _qt_internal_sbom_repo_begin_called)
if(sbom_repo_begin_called AND TARGET "${target}")
_qt_internal_sbom_record_system_library_spdx_id(${target} ${spdx_options})
else()
set_property(GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_spdx_options_${target} "${spdx_options}")
endif()
# Defer sbom info creation until we detect usage of the system library (whether the library is
# linked into any other target).
set_property(GLOBAL APPEND PROPERTY
_qt_internal_sbom_recorded_system_library_targets "${target}")
set_property(GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_options_${target} "${ARGN}")
endfunction()
# Helper to record spdx ids of all system library targets that were found so far.
function(_qt_internal_sbom_record_system_library_spdx_ids)
get_property(recorded_targets GLOBAL PROPERTY _qt_internal_sbom_recorded_system_library_targets)
if(NOT recorded_targets)
return()
endif()
foreach(target IN LISTS recorded_targets)
get_property(args GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_spdx_options_${target})
# qt_find_package PROVIDED_TARGETS might refer to non-existent targets in certain cases,
# like zstd::libzstd_shared for qt_find_package(WrapZSTD), because we are not sure what
# kind of zstd build was done. Make sure to check if the target exists before recording it.
if(TARGET "${target}")
set(target_unaliased "${target}")
get_target_property(aliased_target "${target}" ALIASED_TARGET)
if(aliased_target)
set(target_unaliased ${aliased_target})
endif()
_qt_internal_sbom_record_system_library_spdx_id(${target_unaliased} ${args})
else()
message(DEBUG
"Skipping recording system library for SBOM because target does not exist: "
" ${target}")
endif()
endforeach()
endfunction()
# Helper to record the spdx id of a system library target.
function(_qt_internal_sbom_record_system_library_spdx_id target)
# Save the spdx id before the sbom info is added, so we can refer to it in relationships.
_qt_internal_sbom_record_target_spdx_id(${ARGN} OUT_VAR package_spdx_id)
if(NOT package_spdx_id)
message(FATAL_ERROR "Could not generate spdx id for system library target: ${target}")
endif()
set_property(GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_package_${target} "${package_spdx_id}")
endfunction()
# Goes through the list of consumed system libraries (those that were linked in) and creates
# sbom packages for them.
# Uses information from recorded system libraries (calls to qt_find_package).
function(_qt_internal_sbom_add_recorded_system_libraries)
get_property(recorded_targets GLOBAL PROPERTY _qt_internal_sbom_recorded_system_library_targets)
get_property(consumed_targets GLOBAL PROPERTY _qt_internal_sbom_consumed_system_library_targets)
set(unconsumed_targets "${recorded_targets}")
set(generated_package_names "")
foreach(target IN LISTS consumed_targets)
# Some system targets like qtspeech SpeechDispatcher::SpeechDispatcher might be aliased,
# and we can't set properties on them, so unalias the target name.
set(target_original "${target}")
get_target_property(aliased_target "${target}" ALIASED_TARGET)
if(aliased_target)
set(target ${aliased_target})
endif()
get_property(args GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_options_${target})
get_property(package_name GLOBAL PROPERTY
_qt_internal_sbom_recorded_system_library_package_${target})
set_property(GLOBAL PROPERTY _qt_internal_sbom_recorded_system_library_target_${target} "")
set_property(GLOBAL PROPERTY _qt_internal_sbom_recorded_system_library_options_${target} "")
set_property(GLOBAL PROPERTY _qt_internal_sbom_recorded_system_library_package_${target} "")
# Guard against generating a package multiple times. Can happen when multiple targets belong
# to the same package.
if(sbom_generated_${package_name})
continue()
endif()
# Automatic system library sbom recording happens at project root source dir scope, which
# means it might accidentally pick up a qt_attribution.json file from the project root,
# that is not intended to be use for system libraries.
# For now, explicitly disable using the root attribution file.
list(APPEND args NO_CURRENT_DIR_ATTRIBUTION)
list(APPEND generated_package_names "${package_name}")
set(sbom_generated_${package_name} TRUE)
_qt_internal_extend_sbom(${target} ${args})
_qt_internal_finalize_sbom(${target})
list(REMOVE_ITEM unconsumed_targets "${target_original}")
endforeach()
message(DEBUG "System libraries that were recorded, but not consumed: ${unconsumed_targets}")
message(DEBUG "Generated SBOMs for the following system packages: ${generated_package_names}")
# Clean up, before configuring next repo project.
set_property(GLOBAL PROPERTY _qt_internal_sbom_consumed_system_library_targets "")
set_property(GLOBAL PROPERTY _qt_internal_sbom_recorded_system_library_targets "")
endfunction()