diff options
Diffstat (limited to 'cmake/QtPublicSbomCommonGenerationHelpers.cmake')
| -rw-r--r-- | cmake/QtPublicSbomCommonGenerationHelpers.cmake | 668 |
1 files changed, 668 insertions, 0 deletions
diff --git a/cmake/QtPublicSbomCommonGenerationHelpers.cmake b/cmake/QtPublicSbomCommonGenerationHelpers.cmake new file mode 100644 index 00000000000..9de2055b5b6 --- /dev/null +++ b/cmake/QtPublicSbomCommonGenerationHelpers.cmake @@ -0,0 +1,668 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Helper function to get common project related variables for SBOM generation for both SPDX and +# CycloneDX formats. +function(_qt_internal_sbom_get_common_project_variables) + set(opt_args "") + set(single_args + # Forwarded + OUTPUT + OUTPUT_RELATIVE_PATH + COPYRIGHT + PROJECT + PROJECT_FOR_SPDX_ID + SUPPLIER + SUPPLIER_URL + + # Custom inputs + DEFAULT_SBOM_FILE_NAME_EXTENSION + + # Out vars + OUT_VAR_PROJECT_NAME + OUT_VAR_CURRENT_UTC + OUT_VAR_CURRENT_YEAR + OUT_VAR_OUTPUT + OUT_VAR_OUTPUT_RELATIVE_PATH + OUT_VAR_PROJECT_FOR_SPDX_ID + OUT_VAR_COPYRIGHT + OUT_VAR_SUPPLIER + OUT_VAR_SUPPLIER_URL + OUT_VAR_DEFAULT_PROJECT_COMMENT + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + + if(QT_SBOM_FAKE_TIMESTAMP) + set(current_utc "2590-01-01T11:33:55Z") + set(current_year "2590") + else() + string(TIMESTAMP current_utc UTC) + string(TIMESTAMP current_year "%Y" UTC) + endif() + + set(${arg_OUT_VAR_CURRENT_UTC} "${current_utc}" PARENT_SCOPE) + set(${arg_OUT_VAR_CURRENT_YEAR} "${current_year}" PARENT_SCOPE) + + _qt_internal_sbom_set_default_option_value(PROJECT "${PROJECT_NAME}") + set(${arg_OUT_VAR_PROJECT_NAME} "${arg_PROJECT}" PARENT_SCOPE) + + _qt_internal_sbom_get_git_version_vars() + + _qt_internal_path_join(default_sbom_file_name + "${arg_PROJECT}" + "${arg_PROJECT}-sbom-${QT_SBOM_GIT_VERSION_PATH}.${arg_DEFAULT_SBOM_FILE_NAME_EXTENSION}") + _qt_internal_path_join(default_install_sbom_path + "\${CMAKE_INSTALL_PREFIX}/" "${CMAKE_INSTALL_DATAROOTDIR}" "${default_sbom_file_name}" + ) + + _qt_internal_sbom_set_default_option_value(OUTPUT "${default_install_sbom_path}") + _qt_internal_sbom_set_default_option_value(OUTPUT_RELATIVE_PATH + "${default_sbom_file_name}") + + set(${arg_OUT_VAR_OUTPUT} "${arg_OUTPUT}" PARENT_SCOPE) + set(${arg_OUT_VAR_OUTPUT_RELATIVE_PATH} "${arg_OUTPUT_RELATIVE_PATH}" PARENT_SCOPE) + + _qt_internal_sbom_set_default_option_value(PROJECT_FOR_SPDX_ID "Package-${arg_PROJECT}") + string(REGEX REPLACE "[^A-Za-z0-9.]+" "-" arg_PROJECT_FOR_SPDX_ID "${arg_PROJECT_FOR_SPDX_ID}") + string(REGEX REPLACE "-+$" "" arg_PROJECT_FOR_SPDX_ID "${arg_PROJECT_FOR_SPDX_ID}") + + # Prevent collision with other generated SPDXID with -[0-9]+ suffix. + string(REGEX REPLACE "-([0-9]+)$" "\\1" arg_PROJECT_FOR_SPDX_ID "${arg_PROJECT_FOR_SPDX_ID}") + + set(project_spdx_id "SPDXRef-${arg_PROJECT_FOR_SPDX_ID}") + set(${arg_OUT_VAR_PROJECT_FOR_SPDX_ID} "${project_spdx_id}" PARENT_SCOPE) + + _qt_internal_sbom_set_default_option_value_and_error_if_empty(SUPPLIER "") + set(${arg_OUT_VAR_SUPPLIER} "${arg_SUPPLIER}" PARENT_SCOPE) + + _qt_internal_sbom_set_default_option_value_and_error_if_empty(SUPPLIER_URL + "${PROJECT_HOMEPAGE_URL}") + set(${arg_OUT_VAR_SUPPLIER_URL} "${arg_SUPPLIER_URL}" PARENT_SCOPE) + + _qt_internal_sbom_set_default_option_value(COPYRIGHT "${current_year} ${arg_SUPPLIER}") + set(${arg_OUT_VAR_COPYRIGHT} "${arg_COPYRIGHT}" PARENT_SCOPE) + + get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(cmake_configs "${CMAKE_CONFIGURATION_TYPES}") + else() + set(cmake_configs "${CMAKE_BUILD_TYPE}") + endif() + + set(cmake_version "Built by CMake ${CMAKE_VERSION}") + set(system_name_and_processor "${CMAKE_SYSTEM_NAME} (${CMAKE_SYSTEM_PROCESSOR})") + set(default_project_comment + "${cmake_version} with ${cmake_configs} configuration for ${system_name_and_processor}") + set(${arg_OUT_VAR_DEFAULT_PROJECT_COMMENT} "${default_project_comment}" PARENT_SCOPE) +endfunction() + +# Helper function to save SBOM project path values like relative build and install dirs, +# in global properties. +function(_qt_internal_sbom_save_common_path_variables_in_global_properties) + set(opt_args "") + set(single_args + OUTPUT + OUTPUT_RELATIVE_PATH + SBOM_DIR + PROPERTY_SUFFIX + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + get_filename_component(output_file_name_without_ext "${arg_OUTPUT}" NAME_WLE) + get_filename_component(output_file_ext "${arg_OUTPUT}" LAST_EXT) + + set(computed_sbom_file_name_without_ext "${output_file_name_without_ext}${multi_config_suffix}") + set(computed_sbom_file_name "${output_file_name_without_ext}${output_file_ext}") + + # In a super build and in a no-prefix build, put all the build time sboms into the same dir in, + # in the qtbase build dir. + if(QT_BUILDING_QT AND (QT_SUPERBUILD OR (NOT QT_WILL_INSTALL))) + set(build_sbom_root_dir "${QT_BUILD_DIR}") + else() + set(build_sbom_root_dir "${arg_SBOM_DIR}") + endif() + + get_filename_component(output_relative_dir "${arg_OUTPUT_RELATIVE_PATH}" DIRECTORY) + + set(build_sbom_dir "${build_sbom_root_dir}/${output_relative_dir}") + set(build_sbom_path "${build_sbom_dir}/${computed_sbom_file_name}") + set(build_sbom_path_without_ext + "${build_sbom_dir}/${computed_sbom_file_name_without_ext}") + + set(install_sbom_path "${arg_OUTPUT}") + + get_filename_component(install_sbom_dir "${install_sbom_path}" DIRECTORY) + set(install_sbom_path_without_ext "${install_sbom_dir}/${output_file_name_without_ext}") + + set(suffix "${arg_PROPERTY_SUFFIX}") + + set_property(GLOBAL PROPERTY _qt_sbom_build_output_path${suffix} "${build_sbom_path}") + set_property(GLOBAL PROPERTY _qt_sbom_build_output_path_without_ext${suffix} + "${build_sbom_path_without_ext}") + set_property(GLOBAL PROPERTY _qt_sbom_build_output_dir${suffix} "${build_sbom_dir}") + + set_property(GLOBAL PROPERTY _qt_sbom_install_output_path${suffix} "${install_sbom_path}") + set_property(GLOBAL PROPERTY _qt_sbom_install_output_path_without_ext${suffix} + "${install_sbom_path_without_ext}") + set_property(GLOBAL PROPERTY _qt_sbom_install_output_dir${suffix} "${install_sbom_dir}") +endfunction() + +# Helper function to get SBOM project path values like relative build and install dirs, +function(_qt_internal_sbom_get_common_path_variables_from_global_properties) + set(opt_args "") + set(single_args + SBOM_FORMAT + OUT_VAR_SBOM_BUILD_OUTPUT_PATH + OUT_VAR_SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT + OUT_VAR_SBOM_BUILD_OUTPUT_DIR + OUT_VAR_SBOM_INSTALL_OUTPUT_PATH + OUT_VAR_SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT + OUT_VAR_SBOM_INSTALL_OUTPUT_DIR + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + endif() + + get_property(sbom_build_output_path GLOBAL PROPERTY _qt_sbom_build_output_path${suffix}) + get_property(sbom_build_output_path_without_ext GLOBAL PROPERTY + _qt_sbom_build_output_path_without_ext${suffix}) + get_property(sbom_build_output_dir GLOBAL PROPERTY _qt_sbom_build_output_dir${suffix}) + + get_property(sbom_install_output_path GLOBAL PROPERTY _qt_sbom_install_output_path${suffix}) + get_property(sbom_install_output_path_without_ext GLOBAL PROPERTY + _qt_sbom_install_output_path_without_ext${suffix}) + get_property(sbom_install_output_dir GLOBAL PROPERTY _qt_sbom_install_output_dir${suffix}) + + if(arg_OUT_VAR_SBOM_BUILD_OUTPUT_PATH) + set(${arg_OUT_VAR_SBOM_BUILD_OUTPUT_PATH} "${sbom_build_output_path}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT) + set(${arg_OUT_VAR_SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT} + "${sbom_build_output_path_without_ext}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_SBOM_BUILD_OUTPUT_DIR) + set(${arg_OUT_VAR_SBOM_BUILD_OUTPUT_DIR} "${sbom_build_output_dir}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_SBOM_INSTALL_OUTPUT_PATH) + set(${arg_OUT_VAR_SBOM_INSTALL_OUTPUT_PATH} "${sbom_install_output_path}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT) + set(${arg_OUT_VAR_SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT} + "${sbom_install_output_path_without_ext}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_SBOM_INSTALL_OUTPUT_DIR) + set(${arg_OUT_VAR_SBOM_INSTALL_OUTPUT_DIR} "${sbom_install_output_dir}" PARENT_SCOPE) + endif() +endfunction() + +# Helper function to create a staging file for SBOM generation. +# It is the file that will be incrementally assembled by having content appended to it. +# Also creates the intro file that will add the assembled content for the SBOM project, aka for the +# main SPDX package or root CycloneDX component. +function(_qt_internal_sbom_create_sbom_staging_file) + set(opt_args "") + set(single_args + CONTENT + SBOM_FORMAT + REPO_PROJECT_NAME_LOWERCASE + OUT_VAR_CREATE_STAGING_FILE + OUT_VAR_SBOM_DIR + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + # Create the directory that will contain all sbom related files. + _qt_internal_get_current_project_sbom_dir(sbom_dir) + file(MAKE_DIRECTORY "${sbom_dir}") + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(doc_base_name "SPDXRef-DOCUMENT") + set(doc_extension "spdx.in") + set(suffix "") + set(extra_content " + set(QT_SBOM_EXTERNAL_DOC_REFS \"\") +") + _qt_internal_get_staging_area_spdx_file_path(staging_area_file) + set(starting_message "Starting SPDX SBOM generation in build dir: ${staging_area_file}") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(doc_base_name "cydx-document") + set(doc_extension "cdx.in.toml") + set(suffix "_cydx") + set(extra_content "") + _qt_internal_get_staging_area_cydx_file_path(staging_area_file) + set(starting_message + "Starting CycloneDX SBOM TOML file generation in build dir: ${staging_area_file}") + endif() + + # Generate project document intro spdx file. + set(document_intro_file_name + "${sbom_dir}/${doc_base_name}-${arg_REPO_PROJECT_NAME_LOWERCASE}.${doc_extension}") + file(GENERATE OUTPUT "${document_intro_file_name}" CONTENT "${content}") + + get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(multi_config_suffix "-$<CONFIG>") + else() + set(multi_config_suffix "") + endif() + + # Create cmake file to append the document intro spdx to the staging file. + set(create_staging_file + "${sbom_dir}/append_document_to_staging${suffix}${multi_config_suffix}.cmake") + + set(content " + cmake_minimum_required(VERSION 3.16) + message(STATUS \"${starting_message}\") + ${extra_content} + file(READ \"${document_intro_file_name}\" content) + # Override any previous file because we're starting from scratch. + file(WRITE \"${staging_area_file}\" \"\${content}\") +") + file(GENERATE OUTPUT "${create_staging_file}" CONTENT "${content}") + + set(${arg_OUT_VAR_CREATE_STAGING_FILE} "${create_staging_file}" PARENT_SCOPE) + set(${arg_OUT_VAR_SBOM_DIR} "${sbom_dir}" PARENT_SCOPE) +endfunction() + +# Helper function to save common project info like supplier, project name, spdx id in global +# properties. +function(_qt_internal_sbom_save_project_info_in_global_properties) + set(opt_args "") + set(single_args + SUPPLIER + SUPPLIER_URL + NAMESPACE + PROJECT + PROJECT_SPDX_ID + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set_property(GLOBAL PROPERTY _qt_sbom_project_supplier "${arg_SUPPLIER}") + set_property(GLOBAL PROPERTY _qt_sbom_project_supplier_url "${arg_SUPPLIER_URL}") + set_property(GLOBAL PROPERTY _qt_sbom_project_namespace "${arg_NAMESPACE}") + + set_property(GLOBAL PROPERTY _qt_sbom_project_name "${arg_PROJECT}") + set_property(GLOBAL PROPERTY _qt_sbom_project_spdx_id "${arg_PROJECT_SPDX_ID}") +endfunction() + +# Helper function to get cmake include files for SBOM generation from global properties. +function(_qt_internal_sbom_get_cmake_include_files) + set(opt_args "") + set(single_args + SBOM_FORMAT + OUT_VAR_INCLUDES + OUT_VAR_BEFORE_CHECKSUM_INCLUDES + OUT_VAR_AFTER_CHECKSUM_INCLUDES + OUT_VAR_POST_GENERATION_INCLUDES + OUT_VAR_VERIFY_INCLUDES + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + endif() + + _qt_internal_sbom_collect_cmake_include_files(includes + JOIN_WITH_NEWLINES + PROPERTIES _qt_sbom_cmake_include_files${suffix} _qt_sbom_cmake_end_include_files${suffix} + ) + + # Before checksum includes are included after the verification codes have been collected + # and before their merged checksum(s) has been computed. + _qt_internal_sbom_collect_cmake_include_files(before_checksum_includes + JOIN_WITH_NEWLINES + PROPERTIES _qt_sbom_cmake_before_checksum_include_files${suffix} + ) + + # After checksum includes are included after the checksum has been computed and written to the + # QT_SBOM_VERIFICATION_CODE variable. + _qt_internal_sbom_collect_cmake_include_files(after_checksum_includes + JOIN_WITH_NEWLINES + PROPERTIES _qt_sbom_cmake_after_checksum_include_files${suffix} + ) + + # Post generation includes are included for both build and install time sboms, after + # sbom generation has finished. + _qt_internal_sbom_collect_cmake_include_files(post_generation_includes + JOIN_WITH_NEWLINES + PROPERTIES _qt_sbom_cmake_post_generation_include_files${suffix} + ) + + # Verification only makes sense on installation, where the checksums are present. + _qt_internal_sbom_collect_cmake_include_files(verify_includes + JOIN_WITH_NEWLINES + PROPERTIES _qt_sbom_cmake_verify_include_files${suffix} + ) + + if(arg_OUT_VAR_INCLUDES) + set(${arg_OUT_VAR_INCLUDES} "${includes}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_INCLUDES) + set(${arg_OUT_VAR_BEFORE_CHECKSUM_INCLUDES} "${before_checksum_includes}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_INCLUDES) + set(${arg_OUT_VAR_AFTER_CHECKSUM_INCLUDES} "${after_checksum_includes}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_INCLUDES) + set(${arg_OUT_VAR_POST_GENERATION_INCLUDES} "${post_generation_includes}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_INCLUDES) + set(${arg_OUT_VAR_VERIFY_INCLUDES} "${verify_includes}" PARENT_SCOPE) + endif() +endfunction() + +# Clears cmake include files for the current project from the global properties. +function(_qt_internal_sbom_clear_cmake_include_files) + set(opt_args "") + set(single_args + SBOM_FORMAT + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + endif() + + # Clean up properties, so that they are empty for possible next repo in a top-level build. + set_property(GLOBAL PROPERTY _qt_sbom_cmake_include_files${suffix} "") + set_property(GLOBAL PROPERTY _qt_sbom_cmake_end_include_files${suffix} "") + set_property(GLOBAL PROPERTY _qt_sbom_cmake_before_checksum_include_files${suffix} "") + set_property(GLOBAL PROPERTY _qt_sbom_cmake_after_checksum_include_files${suffix} "") + set_property(GLOBAL PROPERTY _qt_sbom_cmake_post_generation_include_files${suffix} "") + set_property(GLOBAL PROPERTY _qt_sbom_cmake_verify_include_files${suffix} "") +endfunction() + +# Creates cmake build targets to create build-time SBOMs (for testing purposes only, because they +# lack checksums for installed files). +# Also creates the assemble_sbom cmake file that is used by both build-time and install-time +# sbom generation. +function(_qt_internal_sbom_create_build_time_sbom_targets) + set(opt_args "") + set(single_args + SBOM_FORMAT + REPO_PROJECT_NAME_LOWERCASE + REAL_QT_REPO_PROJECT_NAME_LOWERCASE + SBOM_BUILD_OUTPUT_PATH + SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT + SBOM_BUILD_OUTPUT_DIR + INCLUDES + POST_GENERATION_INCLUDES + OUT_VAR_ASSEMBLE_SBOM_INCLUDE_PATH + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "") + set(extra_content " + set(QT_SBOM_PACKAGES \"\") + set(QT_SBOM_PACKAGES_WITH_VERIFICATION_CODES \"\") +") + _qt_internal_get_staging_area_spdx_file_path(staging_area_file) + set(final_message "Finalizing SPDX SBOM generation in build dir") + set(build_comment "SPDX document") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + set(extra_content "") + _qt_internal_get_staging_area_cydx_file_path(staging_area_file) + set(final_message "Finalizing Cyclone DX SBOM TOML generation in build dir") + set(build_comment "Cyclone DX document") + endif() + + get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(multi_config_suffix "-$<CONFIG>") + else() + set(multi_config_suffix "") + endif() + + _qt_internal_get_current_project_sbom_dir(sbom_dir) + set(content " + # QT_SBOM_BUILD_TIME be set to FALSE at install time, so don't override if it's set. + # This allows reusing the same cmake file for both build and install. + if(NOT DEFINED QT_SBOM_BUILD_TIME) + set(QT_SBOM_BUILD_TIME TRUE) + endif() + if(NOT QT_SBOM_OUTPUT_PATH) + set(QT_SBOM_OUTPUT_DIR \"${arg_SBOM_BUILD_OUTPUT_DIR}\") + set(QT_SBOM_OUTPUT_PATH \"${arg_SBOM_BUILD_OUTPUT_PATH}\") + set(QT_SBOM_OUTPUT_PATH_WITHOUT_EXT \"${arg_SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT}\") + file(MAKE_DIRECTORY \"${arg_SBOM_BUILD_OUTPUT_DIR}\") + endif() + ${extra_content} + ${arg_INCLUDES} + if(QT_SBOM_BUILD_TIME) + message(STATUS \"${final_message}: \${QT_SBOM_OUTPUT_PATH}\") + configure_file(\"${staging_area_file}\" \"\${QT_SBOM_OUTPUT_PATH}\") + ${arg_POST_GENERATION_INCLUDES} + endif() +") + set(assemble_sbom "${sbom_dir}/assemble_sbom${suffix}${multi_config_suffix}.cmake") + file(GENERATE OUTPUT "${assemble_sbom}" CONTENT "${content}") + + if(NOT TARGET sbom) + add_custom_target(sbom) + endif() + + # Create a build target to create a build-time sbom (no verification codes or sha1s). + set(repo_sbom_target "sbom_${arg_REPO_PROJECT_NAME_LOWERCASE}${suffix}") + set(comment "") + string(APPEND comment "Assembling build time ${build_comment} without checksums for " + "${arg_REPO_PROJECT_NAME_LOWERCASE}. Just for testing.") + add_custom_target(${repo_sbom_target} + COMMAND "${CMAKE_COMMAND}" -P "${assemble_sbom}" + COMMENT "${comment}" + VERBATIM + USES_TERMINAL # To avoid running two configs of the command in parallel + ) + + get_cmake_property(qt_repo_deps _qt_repo_deps_${arg_REAL_QT_REPO_PROJECT_NAME_LOWERCASE}) + if(qt_repo_deps) + foreach(repo_dep IN LISTS qt_repo_deps) + set(repo_dep_sbom "sbom_${repo_dep}${suffix}") + if(TARGET "${repo_dep_sbom}") + add_dependencies(${repo_sbom_target} ${repo_dep_sbom}) + endif() + endforeach() + endif() + + add_dependencies(sbom ${repo_sbom_target}) + + set(${arg_OUT_VAR_ASSEMBLE_SBOM_INCLUDE_PATH} "${assemble_sbom}" PARENT_SCOPE) +endfunction() + +# Helper function to setup install markers for multi-config generators. +# Makes sure to wait for all configurations to finish installation before actually generating +# the SBOM and removing the markers. +function(_qt_internal_sbom_setup_multi_config_install_markers) + set(opt_args "") + set(single_args + SBOM_DIR + SBOM_FORMAT + REPO_PROJECT_NAME_LOWERCASE + OUT_VAR_EXTRA_CODE_BEGIN + OUT_VAR_EXTRA_CODE_INNER_END + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set(extra_code_begin "") + set(extra_code_inner_end "") + + get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + if(NOT is_multi_config) + set(${arg_OUT_VAR_EXTRA_CODE_BEGIN} "${extra_code_begin}" PARENT_SCOPE) + set(${arg_OUT_VAR_EXTRA_CODE_INNER_END} "${extra_code_inner_end}" PARENT_SCOPE) + return() + endif() + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "_spdx") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + endif() + + set(configs ${CMAKE_CONFIGURATION_TYPES}) + + set(install_markers_dir "${arg_SBOM_DIR}") + set(install_marker_path "${install_markers_dir}/finished_install${suffix}-$<CONFIG>.cmake") + + set(install_marker_code " + message(STATUS \"Writing install marker for config $<CONFIG>: ${install_marker_path} \") + file(WRITE \"${install_marker_path}\" \"\") +") + + install(CODE "${install_marker_code}" COMPONENT sbom) + if(QT_SUPERBUILD) + install(CODE "${install_marker_code}" + COMPONENT "sbom_${arg_REPO_PROJECT_NAME_LOWERCASE}${suffix}" + EXCLUDE_FROM_ALL) + endif() + + set(install_markers "") + foreach(config IN LISTS configs) + set(marker_path "${install_markers_dir}/finished_install${suffix}-${config}.cmake") + list(APPEND install_markers "${marker_path}") + # Remove the markers on reconfiguration, just in case there are stale ones. + if(EXISTS "${marker_path}") + file(REMOVE "${marker_path}") + endif() + endforeach() + + # Escape the semicolons in install_makers, so they don't break argument parsing in + # _qt_internal_sbom_setup_sbom_install_code when they are forwarded there. + string(REPLACE ";" "\\;" install_markers "${install_markers}") + + set(extra_code_begin " + set(QT_SBOM_INSTALL_MARKERS${suffix} \"${install_markers}\") + foreach(QT_SBOM_INSTALL_MARKER IN LISTS QT_SBOM_INSTALL_MARKERS${suffix}) + if(NOT EXISTS \"\${QT_SBOM_INSTALL_MARKER}\") + set(QT_SBOM_INSTALLED_ALL_CONFIGS${suffix} FALSE) + endif() + endforeach() +") + set(extra_code_inner_end " + foreach(QT_SBOM_INSTALL_MARKER IN LISTS QT_SBOM_INSTALL_MARKERS${suffix}) + message(STATUS + \"Removing install marker: \${QT_SBOM_INSTALL_MARKER} \") + file(REMOVE \"\${QT_SBOM_INSTALL_MARKER}\") + endforeach() +") + + set(${arg_OUT_VAR_EXTRA_CODE_BEGIN} "${extra_code_begin}" PARENT_SCOPE) + set(${arg_OUT_VAR_EXTRA_CODE_INNER_END} "${extra_code_inner_end}" PARENT_SCOPE) +endfunction() + +# Helper function to setup the fake checksum code snippet. +function(_qt_internal_sbom_setup_fake_checksum) + set(opt_args "") + set(single_args + OUT_VAR_FAKE_CHECKSUM_CODE + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + # Allow skipping checksum computation for testing purposes, while installing just the sbom + # documents, without requiring to build and install all the actual files. + set(extra_code "") + if(QT_SBOM_FAKE_CHECKSUM) + string(APPEND extra_code " + set(QT_SBOM_FAKE_CHECKSUM TRUE)") + endif() + + set(${arg_OUT_VAR_FAKE_CHECKSUM_CODE} "${extra_code}" PARENT_SCOPE) +endfunction() + +# Helper function to setup the install-time SBOM generation code. +function(_qt_internal_sbom_setup_sbom_install_code) + set(opt_args "") + set(single_args + SBOM_FORMAT + REPO_PROJECT_NAME_LOWERCASE + + SBOM_INSTALL_OUTPUT_PATH + SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT + SBOM_INSTALL_OUTPUT_DIR + + ASSEMBLE_SBOM_INCLUDE_PATH + + EXTRA_CODE_BEGIN + EXTRA_CODE_INNER_END + PROCESS_VERIFICATION_CODES + + BEFORE_CHECKSUM_INCLUDES + AFTER_CHECKSUM_INCLUDES + POST_GENERATION_INCLUDES + VERIFY_INCLUDES + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "_spdx") + _qt_internal_get_staging_area_spdx_file_path(staging_area_file) + set(final_message "Finalizing SBOM generation in install dir") + set(process_verification_codes " + include(\"${arg_PROCESS_VERIFICATION_CODES}\") +") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + set(final_message "Finalizing intermediate TOML generation in install dir") + + set(process_verification_codes "") + _qt_internal_get_staging_area_cydx_file_path(staging_area_file) + endif() + + set(assemble_sbom_install " + set(QT_SBOM_INSTALLED_ALL_CONFIGS${suffix} TRUE) + ${arg_EXTRA_CODE_BEGIN} + if(QT_SBOM_INSTALLED_ALL_CONFIGS${suffix}) + set(QT_SBOM_BUILD_TIME FALSE) + set(QT_SBOM_OUTPUT_DIR \"${arg_SBOM_INSTALL_OUTPUT_DIR}\") + set(QT_SBOM_OUTPUT_PATH \"${arg_SBOM_INSTALL_OUTPUT_PATH}\") + set(QT_SBOM_OUTPUT_PATH_WITHOUT_EXT \"${arg_SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT}\") + file(MAKE_DIRECTORY \"${arg_SBOM_INSTALL_OUTPUT_DIR}\") + include(\"${arg_ASSEMBLE_SBOM_INCLUDE_PATH}\") + ${arg_BEFORE_CHECKSUM_INCLUDES} + ${process_verification_codes} + ${arg_AFTER_CHECKSUM_INCLUDES} + message(STATUS \"${final_message}: \${QT_SBOM_OUTPUT_PATH}\") + configure_file(\"${staging_area_file}\" \"\${QT_SBOM_OUTPUT_PATH}\") + ${arg_POST_GENERATION_INCLUDES} + ${arg_VERIFY_INCLUDES} + ${arg_EXTRA_CODE_INNER_END} + else() + message(STATUS \"Skipping SBOM finalization because not all configs were installed.\") + endif() +") + + install(CODE "${assemble_sbom_install}" COMPONENT sbom) + if(QT_SUPERBUILD) + install(CODE "${assemble_sbom_install}" COMPONENT "sbom_${arg_REPO_PROJECT_NAME_LOWERCASE}" + EXCLUDE_FROM_ALL) + endif() +endfunction() |
