mirror of https://github.com/qt/qtbase.git
266 lines
10 KiB
CMake
266 lines
10 KiB
CMake
# Copyright (C) 2024 The Qt Company Ltd.
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
# Walks a target's direct dependencies and assembles a list of relationships between the packages
|
|
# of the target dependencies.
|
|
# Currently handles various Qt targets and system libraries.
|
|
function(_qt_internal_sbom_handle_target_dependencies target)
|
|
set(opt_args "")
|
|
set(single_args
|
|
SPDX_ID
|
|
OUT_RELATIONSHIPS
|
|
)
|
|
set(multi_args
|
|
LIBRARIES
|
|
PUBLIC_LIBRARIES
|
|
)
|
|
cmake_parse_arguments(PARSE_ARGV 1 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()
|
|
set(package_spdx_id "${arg_SPDX_ID}")
|
|
|
|
|
|
set(libraries "")
|
|
if(arg_LIBRARIES)
|
|
list(APPEND libraries "${arg_LIBRARIES}")
|
|
endif()
|
|
|
|
get_target_property(extend_libraries "${target}" _qt_extend_target_libraries)
|
|
if(extend_libraries)
|
|
list(APPEND libraries ${extend_libraries})
|
|
endif()
|
|
|
|
get_target_property(target_type ${target} TYPE)
|
|
set(valid_target_types
|
|
EXECUTABLE
|
|
SHARED_LIBRARY
|
|
MODULE_LIBRARY
|
|
STATIC_LIBRARY
|
|
OBJECT_LIBRARY
|
|
)
|
|
if(target_type IN_LIST valid_target_types)
|
|
get_target_property(link_libraries "${target}" LINK_LIBRARIES)
|
|
if(link_libraries)
|
|
list(APPEND libraries ${link_libraries})
|
|
endif()
|
|
endif()
|
|
|
|
set(public_libraries "")
|
|
if(arg_PUBLIC_LIBRARIES)
|
|
list(APPEND public_libraries "${arg_PUBLIC_LIBRARIES}")
|
|
endif()
|
|
|
|
get_target_property(extend_public_libraries "${target}" _qt_extend_target_public_libraries)
|
|
if(extend_public_libraries)
|
|
list(APPEND public_libraries ${extend_public_libraries})
|
|
endif()
|
|
|
|
set(sbom_dependencies "")
|
|
if(arg_SBOM_DEPENDENCIES)
|
|
list(APPEND sbom_dependencies "${arg_SBOM_DEPENDENCIES}")
|
|
endif()
|
|
|
|
get_target_property(extend_sbom_dependencies "${target}" _qt_extend_target_sbom_dependencies)
|
|
if(extend_sbom_dependencies)
|
|
list(APPEND sbom_dependencies ${extend_sbom_dependencies})
|
|
endif()
|
|
|
|
list(REMOVE_DUPLICATES libraries)
|
|
list(REMOVE_DUPLICATES public_libraries)
|
|
list(REMOVE_DUPLICATES sbom_dependencies)
|
|
|
|
set(all_direct_libraries ${libraries} ${public_libraries} ${sbom_dependencies})
|
|
list(REMOVE_DUPLICATES all_direct_libraries)
|
|
|
|
set(spdx_dependencies "")
|
|
set(external_spdx_dependencies "")
|
|
|
|
# Go through each direct linked lib.
|
|
foreach(direct_lib IN LISTS all_direct_libraries)
|
|
if(NOT TARGET "${direct_lib}")
|
|
continue()
|
|
endif()
|
|
|
|
# Check for Qt-specific system library targets. These are marked via qt_find_package calls.
|
|
get_target_property(is_system_library "${direct_lib}" _qt_internal_sbom_is_system_library)
|
|
if(is_system_library)
|
|
|
|
# We need to check if the dependency is a FindWrap dependency that points either to a
|
|
# system library or a vendored / bundled library. We need to depend on whichever one
|
|
# the FindWrap script points to.
|
|
__qt_internal_walk_libs(
|
|
"${direct_lib}"
|
|
lib_walked_targets
|
|
_discarded_out_var
|
|
"sbom_targets"
|
|
"collect_targets")
|
|
|
|
# Detect if we are dealing with a vendored / bundled lib.
|
|
set(bundled_targets_found FALSE)
|
|
if(lib_walked_targets)
|
|
foreach(lib_walked_target IN LISTS lib_walked_targets)
|
|
get_target_property(is_3rdparty_bundled_lib
|
|
"${lib_walked_target}" _qt_module_is_3rdparty_library)
|
|
_qt_internal_sbom_get_spdx_id_for_target("${lib_walked_target}" lib_spdx_id)
|
|
|
|
# Add a dependency on the vendored lib instead of the Wrap target.
|
|
if(is_3rdparty_bundled_lib AND lib_spdx_id)
|
|
list(APPEND spdx_dependencies "${lib_spdx_id}")
|
|
set(bundled_targets_found TRUE)
|
|
endif()
|
|
endforeach()
|
|
|
|
if(bundled_targets_found)
|
|
# If we handled a bundled target, we can move on to process the next direct_lib.
|
|
continue()
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT bundled_targets_found)
|
|
# If we haven't found a bundled target, then it's a regular system library
|
|
# dependency. Make sure to mark the system library as consumed, so that we later
|
|
# generate an sbom for it.
|
|
# Also fall through to the code that actually adds the dependency on the target.
|
|
_qt_internal_append_to_cmake_property_without_duplicates(
|
|
_qt_internal_sbom_consumed_system_library_targets
|
|
"${direct_lib}"
|
|
)
|
|
endif()
|
|
endif()
|
|
|
|
# Get the spdx id of the dependency.
|
|
_qt_internal_sbom_get_spdx_id_for_target("${direct_lib}" lib_spdx_id)
|
|
if(NOT lib_spdx_id)
|
|
message(DEBUG "Could not add target dependency on target ${direct_lib} "
|
|
"because no spdx id for it could be found.")
|
|
continue()
|
|
endif()
|
|
|
|
# Check if the target sbom is defined in an external document.
|
|
|
|
_qt_internal_sbom_is_external_target_dependency("${direct_lib}"
|
|
OUT_VAR is_dependency_in_external_document
|
|
)
|
|
|
|
if(NOT is_dependency_in_external_document)
|
|
# If the target is not in the external document, it must be one built as part of the
|
|
# current project.
|
|
list(APPEND spdx_dependencies "${lib_spdx_id}")
|
|
else()
|
|
# Refer to the package in the external document. This can be the case
|
|
# in a top-level build, where a system library is reused across repos, or for any
|
|
# regular dependency that was built as part of a different project.
|
|
_qt_internal_sbom_add_external_target_dependency("${direct_lib}"
|
|
extra_spdx_dependencies
|
|
)
|
|
if(extra_spdx_dependencies)
|
|
list(APPEND external_spdx_dependencies ${extra_spdx_dependencies})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
set(relationships "")
|
|
# Keep the external dependencies first, so they are neatly ordered.
|
|
foreach(dep_spdx_id IN LISTS external_spdx_dependencies spdx_dependencies)
|
|
set(relationship
|
|
"${package_spdx_id} DEPENDS_ON ${dep_spdx_id}"
|
|
)
|
|
list(APPEND relationships "${relationship}")
|
|
endforeach()
|
|
|
|
set(${arg_OUT_RELATIONSHIPS} "${relationships}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Checks whether the current target will have its sbom generated into the current repo sbom
|
|
# document, or whether it is present in an external sbom document.
|
|
function(_qt_internal_sbom_is_external_target_dependency target)
|
|
set(opt_args
|
|
SYSTEM_LIBRARY
|
|
)
|
|
set(single_args
|
|
OUT_VAR
|
|
)
|
|
set(multi_args "")
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
|
|
_qt_internal_validate_all_args_are_parsed(arg)
|
|
|
|
get_target_property(is_imported "${target}" IMPORTED)
|
|
get_target_property(is_custom_sbom_target "${target}" _qt_sbom_is_custom_sbom_target)
|
|
|
|
_qt_internal_sbom_get_root_project_name_lower_case(current_repo_project_name)
|
|
get_property(target_repo_project_name TARGET ${target}
|
|
PROPERTY _qt_sbom_spdx_repo_project_name_lowercase)
|
|
|
|
if(NOT "${target_repo_project_name}" STREQUAL ""
|
|
AND NOT "${target_repo_project_name}" STREQUAL "${current_repo_project_name}")
|
|
set(part_of_other_repo TRUE)
|
|
else()
|
|
set(part_of_other_repo FALSE)
|
|
endif()
|
|
|
|
set(${arg_OUT_VAR} "${part_of_other_repo}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Handles generating an external document reference SDPX element for each target package that is
|
|
# located in a different spdx document.
|
|
function(_qt_internal_sbom_add_external_target_dependency target out_spdx_dependencies)
|
|
_qt_internal_sbom_get_spdx_id_for_target("${target}" dep_spdx_id)
|
|
|
|
if(NOT dep_spdx_id)
|
|
message(DEBUG "Could not add external target dependency on ${target} "
|
|
"because no spdx id could be found")
|
|
set(${out_spdx_dependencies} "" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
set(spdx_dependencies "")
|
|
|
|
# Get the external document path and the repo it belongs to for the given target.
|
|
get_property(relative_installed_repo_document_path TARGET ${target}
|
|
PROPERTY _qt_sbom_spdx_relative_installed_repo_document_path)
|
|
|
|
get_property(project_name_lowercase TARGET ${target}
|
|
PROPERTY _qt_sbom_spdx_repo_project_name_lowercase)
|
|
|
|
if(relative_installed_repo_document_path AND project_name_lowercase)
|
|
_qt_internal_sbom_get_external_document_ref_spdx_id(
|
|
"${project_name_lowercase}" external_document_ref)
|
|
|
|
get_cmake_property(known_external_document
|
|
_qt_known_external_documents_${external_document_ref})
|
|
|
|
set(dependency "${external_document_ref}:${dep_spdx_id}")
|
|
|
|
list(APPEND spdx_dependencies "${dependency}")
|
|
|
|
# Only add a reference to the external document package, if we haven't done so already.
|
|
if(NOT known_external_document)
|
|
set(install_prefixes "")
|
|
|
|
get_cmake_property(install_prefix _qt_internal_sbom_install_prefix)
|
|
list(APPEND install_prefixes "${install_prefix}")
|
|
|
|
set(external_document "${relative_installed_repo_document_path}")
|
|
|
|
_qt_internal_sbom_generate_add_external_reference(
|
|
EXTERNAL_DOCUMENT_FILE_PATH "${external_document}"
|
|
EXTERNAL_DOCUMENT_INSTALL_PREFIXES ${install_prefixes}
|
|
EXTERNAL_DOCUMENT_SPDX_ID "${external_document_ref}"
|
|
)
|
|
|
|
set_property(GLOBAL PROPERTY
|
|
_qt_known_external_documents_${external_document_ref} TRUE)
|
|
set_property(GLOBAL APPEND PROPERTY
|
|
_qt_known_external_documents "${external_document_ref}")
|
|
endif()
|
|
else()
|
|
message(AUTHOR_WARNING
|
|
"Missing spdx document path for external target dependency: ${target}")
|
|
endif()
|
|
|
|
set(${out_spdx_dependencies} "${spdx_dependencies}" PARENT_SCOPE)
|
|
endfunction()
|