summaryrefslogtreecommitdiffstats
path: root/cmake/QtPublicSbomHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtPublicSbomHelpers.cmake')
-rw-r--r--cmake/QtPublicSbomHelpers.cmake568
1 files changed, 470 insertions, 98 deletions
diff --git a/cmake/QtPublicSbomHelpers.cmake b/cmake/QtPublicSbomHelpers.cmake
index 1a8702bf594..3d66e7ff783 100644
--- a/cmake/QtPublicSbomHelpers.cmake
+++ b/cmake/QtPublicSbomHelpers.cmake
@@ -85,7 +85,8 @@ function(_qt_internal_sbom_begin_project)
_qt_internal_sbom_get_root_project_name_for_spdx_id(repo_project_name_for_spdx_id)
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
- set(begin_project_generate_args "")
+ set(begin_project_generate_args_spdx "")
+ set(begin_project_generate_args_cydx "")
if(arg_SUPPLIER_URL)
set(repo_supplier_url "${arg_SUPPLIER_URL}")
@@ -93,7 +94,8 @@ function(_qt_internal_sbom_begin_project)
_qt_internal_sbom_get_default_supplier_url(repo_supplier_url)
endif()
if(repo_supplier_url)
- list(APPEND begin_project_generate_args SUPPLIER_URL "${repo_supplier_url}")
+ list(APPEND begin_project_generate_args_spdx SUPPLIER_URL "${repo_supplier_url}")
+ list(APPEND begin_project_generate_args_cydx SUPPLIER_URL "${repo_supplier_url}")
endif()
set(sbom_project_version_args "")
@@ -121,6 +123,15 @@ function(_qt_internal_sbom_begin_project)
)
endif()
+ if(QT_SBOM_GENERATE_CYDX_V1_6)
+ _qt_internal_sbom_get_cyclone_bom_serial_number(
+ SPDX_NAMESPACE "${repo_spdx_namespace}"
+ OUT_VAR_UUID cyclone_dx_bom_serial_number_uuid
+ )
+ list(APPEND begin_project_generate_args_cydx
+ BOM_SERIAL_NUMBER_UUID "${cyclone_dx_bom_serial_number_uuid}")
+ endif()
+
if(arg_INSTALL_SBOM_DIR)
set(install_sbom_dir "${arg_INSTALL_SBOM_DIR}")
elseif(INSTALL_SBOMDIR)
@@ -143,17 +154,28 @@ function(_qt_internal_sbom_begin_project)
list(APPEND compute_project_file_name_args VERSION_SUFFIX "${explicit_version}")
endif()
- _qt_internal_sbom_compute_project_file_name(repo_project_file_name
+ _qt_internal_sbom_compute_project_file_name(repo_project_file_name_spdx
+ SPDX_TAG_VALUE
+ PROJECT_NAME "${repo_project_name_lowercase}"
+ ${compute_project_file_name_args}
+ )
+
+ _qt_internal_sbom_compute_project_file_name(repo_project_file_name_cydx
+ CYCLONEDX_TOML
PROJECT_NAME "${repo_project_name_lowercase}"
${compute_project_file_name_args}
)
- _qt_internal_path_join(repo_spdx_relative_install_path
- "${arg_INSTALL_SBOM_DIR}" "${repo_project_file_name}")
+ _qt_internal_path_join(repo_spdx_relative_install_path_spdx
+ "${install_sbom_dir}" "${repo_project_file_name_spdx}")
+ _qt_internal_path_join(repo_spdx_relative_install_path_cydx
+ "${install_sbom_dir}" "${repo_project_file_name_cydx}")
# Prepend DESTDIR, to allow relocating installed sbom. Needed for CI.
- _qt_internal_path_join(repo_spdx_install_path
- "\$ENV{DESTDIR}${install_prefix}" "${repo_spdx_relative_install_path}")
+ _qt_internal_path_join(repo_spdx_install_path_spdx
+ "\$ENV{DESTDIR}${install_prefix}" "${repo_spdx_relative_install_path_spdx}")
+ _qt_internal_path_join(repo_spdx_install_path_cydx
+ "\$ENV{DESTDIR}${install_prefix}" "${repo_spdx_relative_install_path_cydx}")
if(arg_LICENSE_EXPRESSION)
set(repo_license "${arg_LICENSE_EXPRESSION}")
@@ -164,7 +186,8 @@ function(_qt_internal_sbom_begin_project)
set(repo_license "")
endif()
if(repo_license)
- list(APPEND begin_project_generate_args LICENSE "${repo_license}")
+ list(APPEND begin_project_generate_args_spdx LICENSE "${repo_license}")
+ list(APPEND begin_project_generate_args_cydx LICENSE "${repo_license}")
endif()
if(arg_COPYRIGHTS)
@@ -174,7 +197,8 @@ function(_qt_internal_sbom_begin_project)
_qt_internal_sbom_get_default_qt_copyright_header(repo_copyright)
endif()
if(repo_copyright)
- list(APPEND begin_project_generate_args COPYRIGHT "${repo_copyright}")
+ list(APPEND begin_project_generate_args_spdx COPYRIGHT "${repo_copyright}")
+ list(APPEND begin_project_generate_args_cydx COPYRIGHT "${repo_copyright}")
endif()
if(arg_SUPPLIER)
@@ -184,7 +208,8 @@ function(_qt_internal_sbom_begin_project)
endif()
if(repo_supplier)
# This must not contain spaces!
- list(APPEND begin_project_generate_args SUPPLIER "${repo_supplier}")
+ list(APPEND begin_project_generate_args_spdx SUPPLIER "${repo_supplier}")
+ list(APPEND begin_project_generate_args_cydx SUPPLIER "${repo_supplier}")
endif()
if(arg_CPE)
@@ -195,7 +220,8 @@ function(_qt_internal_sbom_begin_project)
set(qt_cpe "")
endif()
if(qt_cpe)
- list(APPEND begin_project_generate_args CPE "${qt_cpe}")
+ list(APPEND begin_project_generate_args_spdx CPE "${qt_cpe}")
+ list(APPEND begin_project_generate_args_cydx CPE "${qt_cpe}")
endif()
if(arg_DOWNLOAD_LOCATION)
@@ -204,11 +230,12 @@ function(_qt_internal_sbom_begin_project)
_qt_internal_sbom_get_qt_repo_source_download_location(download_location)
endif()
if(download_location)
- list(APPEND begin_project_generate_args DOWNLOAD_LOCATION "${download_location}")
+ list(APPEND begin_project_generate_args_spdx DOWNLOAD_LOCATION "${download_location}")
+ list(APPEND begin_project_generate_args_cydx DOWNLOAD_LOCATION "${download_location}")
endif()
if(arg_DOCUMENT_CREATOR_TOOL)
- list(APPEND begin_project_generate_args
+ list(APPEND begin_project_generate_args_spdx
DOCUMENT_CREATOR_TOOL "${arg_DOCUMENT_CREATOR_TOOL}")
endif()
@@ -229,24 +256,42 @@ function(_qt_internal_sbom_begin_project)
set(project_comment PROJECT_COMMENT "${project_comment}")
endif()
- _qt_internal_sbom_begin_project_generate(
- OUTPUT "${repo_spdx_install_path}"
- OUTPUT_RELATIVE_PATH "${repo_spdx_relative_install_path}"
- PROJECT "${repo_project_name_lowercase}"
- ${project_comment}
- PROJECT_FOR_SPDX_ID "${repo_project_name_for_spdx_id}"
- NAMESPACE "${repo_spdx_namespace}"
- ${begin_project_generate_args}
- OUT_VAR_PROJECT_SPDX_ID repo_project_spdx_id
- )
+ if(QT_SBOM_GENERATE_SPDX_V2)
+ _qt_internal_sbom_begin_project_generate(
+ OUTPUT "${repo_spdx_install_path_spdx}"
+ OUTPUT_RELATIVE_PATH "${repo_spdx_relative_install_path_spdx}"
+ PROJECT "${repo_project_name_lowercase}"
+ ${project_comment}
+ PROJECT_FOR_SPDX_ID "${repo_project_name_for_spdx_id}"
+ NAMESPACE "${repo_spdx_namespace}"
+ ${begin_project_generate_args_spdx}
+ OUT_VAR_PROJECT_SPDX_ID repo_project_spdx_id
+ )
+ endif()
+
+ if(QT_SBOM_GENERATE_CYDX_V1_6)
+ _qt_internal_sbom_begin_project_generate_cyclone(
+ OUTPUT "${repo_spdx_install_path_cydx}"
+ OUTPUT_RELATIVE_PATH "${repo_spdx_relative_install_path_cydx}"
+ PROJECT "${repo_project_name_lowercase}"
+ ${project_comment}
+ PROJECT_FOR_SPDX_ID "${repo_project_name_for_spdx_id}"
+ NAMESPACE "${repo_spdx_namespace}"
+ ${begin_project_generate_args_cydx}
+ OUT_VAR_PROJECT_SPDX_ID repo_project_spdx_id
+ )
+ endif()
set_property(GLOBAL PROPERTY _qt_internal_project_attribution_files "")
set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_document_namespace
"${repo_spdx_namespace}")
+ set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid
+ "${cyclone_dx_bom_serial_number_uuid}")
+
set_property(GLOBAL PROPERTY _qt_internal_sbom_relative_installed_repo_document_path
- "${repo_spdx_relative_install_path}")
+ "${repo_spdx_relative_install_path_spdx}")
set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_project_name_lowercase
"${repo_project_name_lowercase}")
@@ -312,7 +357,10 @@ endfunction()
function(_qt_internal_sbom_setup_project_ops)
set(options "")
- if(QT_SBOM_GENERATE_JSON OR QT_INTERNAL_SBOM_GENERATE_JSON OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
+ if(QT_SBOM_GENERATE_JSON
+ OR QT_SBOM_GENERATE_SPDX_V2_JSON
+ OR QT_INTERNAL_SBOM_GENERATE_JSON
+ OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
list(APPEND options GENERATE_JSON)
endif()
@@ -320,20 +368,48 @@ function(_qt_internal_sbom_setup_project_ops)
# The user can explicitly request to fail the build if dependencies are not found.
# error out. For internal options that the CI uses, we always want to fail the build if the
# deps are not found.
- if(QT_SBOM_REQUIRE_GENERATE_JSON OR QT_INTERNAL_SBOM_GENERATE_JSON
+ if(QT_SBOM_REQUIRE_GENERATE_JSON
+ OR QT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON
+ OR QT_INTERNAL_SBOM_GENERATE_JSON
OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
list(APPEND options GENERATE_JSON_REQUIRED)
endif()
- if(QT_SBOM_VERIFY OR QT_INTERNAL_SBOM_VERIFY OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
+ if(QT_SBOM_VERIFY
+ OR QT_SBOM_VERIFY_SPDX_V2
+ OR QT_INTERNAL_SBOM_VERIFY
+ OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
list(APPEND options VERIFY_SBOM)
endif()
# Do the same requirement check for SBOM verification.
- if(QT_SBOM_REQUIRE_VERIFY OR QT_INTERNAL_SBOM_VERIFY OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
+ if(QT_SBOM_REQUIRE_VERIFY
+ OR QT_SBOM_REQUIRE_VERIFY_SPDX_V2
+ OR QT_INTERNAL_SBOM_VERIFY
+ OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
list(APPEND options VERIFY_SBOM_REQUIRED)
endif()
+ if(QT_SBOM_GENERATE_CYDX_V1_6)
+ list(APPEND options GENERATE_CYCLONE_DX_V1_6)
+ endif()
+
+ if(QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6)
+ list(APPEND options GENERATE_CYCLONE_DX_V1_6_REQUIRED)
+ endif()
+
+ if(QT_SBOM_VERIFY_CYDX_V1_6)
+ list(APPEND options VERIFY_CYCLONE_DX_V1_6)
+ endif()
+
+ if(QT_SBOM_REQUIRE_VERIFY_CYDX_V1_6)
+ list(APPEND options VERIFY_CYCLONE_DX_V1_6_REQUIRED)
+ endif()
+
+ if(QT_SBOM_VERBOSE_CYDX_V1_6)
+ list(APPEND options VERBOSE_CYCLONE_DX_V1_6)
+ endif()
+
if(QT_SBOM_VERIFY_NTIA_COMPLIANT
OR QT_INTERNAL_SBOM_VERIFY_NTIA_COMPLIANT OR QT_INTERNAL_SBOM_DEFAULT_CHECKS)
list(APPEND options VERIFY_NTIA_COMPLIANT)
@@ -367,12 +443,20 @@ function(_qt_internal_sbom_setup_project_ops)
endfunction()
# Sets up SBOM generation and verification options.
-# By default SBOM generation is disabled.
-# By default JSON generation and SBOM verification are enabled by default, if the dependencies
-# are present, otherwise they will be silently skipped. Unless the user explicitly requests to
-# fail the build if the dependencies are not found.
#
-# The QT_GENERATE_SBOM_DEFAULT option can be set by a project to change the default value.
+# By default, the main toggle for SBOM generation is disabled. The GENERATE_SBOM_DEFAULT option
+# overrides that value and can be set by a project that sets up SBOM generation.
+#
+# If the main toggle gets enabled, we enable SPDX V2.3 tag:value generation, and try to enable
+# CycloneDX V1.6 generation. Try, because CDX generation needs python dependencies. If they are
+# not found, the generation is silently skipped.
+#
+# By default SPDX v2.3 JSON generation and verification is enabled, if the python dependencies
+# are found. Otherwise they will be silently skipped.
+# Unless the user explicitly requests to fail the build if the dependencies are not found.
+# The same can be done for CycloneDX generation.
+#
+# Some older variables that were added pre-CycloneDX generation are deprecated.
function(_qt_internal_setup_sbom)
set(opt_args "")
set(single_args
@@ -388,22 +472,159 @@ function(_qt_internal_setup_sbom)
set(default_value "${arg_GENERATE_SBOM_DEFAULT}")
endif()
- option(QT_GENERATE_SBOM "Generate SBOM documents in SPDX v2.3 tag:value format."
- "${default_value}")
+ # Main SBOM toggle. Used to be the toggle for SPDX v2.3 only, but now would also enable Cyclone
+ # DX as well.
+ set(sbom_help_string "Generate SBOM.")
+ option(QT_GENERATE_SBOM "${sbom_help_string}" "${default_value}")
+
+
+ # Toggle for SPDX V2.3 generation.
+ set(spdx_v2_help_string "Generate SBOM documents in SPDX v2.3 tag:value format.")
+ option(QT_SBOM_GENERATE_SPDX_V2 "${spdx_v2_help_string}" ON)
+
+
+ # Toggles for CycloneDX V1.6 generation.
+ set(cydx_help_string "Generate SBOM documents in CycloneDX v1.6 JSON format.")
+ option(QT_SBOM_GENERATE_CYDX_V1_6 "${cydx_help_string}" ON)
- string(CONCAT help_string
+ set(cydx_require_help_string
+ "Error out if CycloneDX SBOM generation dependencies are not found.")
+ option(QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6 "${cydx_require_help_string}" OFF)
+
+
+ # Options for SPDX v2.3 JSON generation and verification.
+
+ string(CONCAT spdx_v23_json_help_string
"Generate SBOM documents in SPDX v2.3 JSON format if required python dependency "
- "spdx-tools is available"
+ "spdx-tools is available."
)
- option(QT_SBOM_GENERATE_JSON
- "${help_string}" ON)
- option(QT_SBOM_REQUIRE_GENERATE_JSON
- "Error out if JSON SBOM generation depdendency is not found." OFF)
+ set(spdx_v23_json_require_help_string
+ "Error out if JSON SBOM generation depdendency is not found.")
+
+ set(spdx_v23_verify_help_string
+ "Verify generated SBOM documents using python spdx-tools package.")
- option(QT_SBOM_VERIFY "Verify generated SBOM documents using python spdx-tools package." ON)
- option(QT_SBOM_REQUIRE_VERIFY
- "Error out if SBOM verification dependencies are not found." OFF)
+ set(spdx_v23_verify_require_help_string
+ "Error out if SBOM verification dependencies are not found.")
+
+ option(QT_SBOM_GENERATE_SPDX_V2_JSON "${spdx_v23_json_help_string}" ON)
+ option(QT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON "${spdx_v23_json_require_help_string}" OFF)
+
+ option(QT_SBOM_VERIFY_SPDX_V2 "${spdx_v23_verify_help_string}" ON)
+ option(QT_SBOM_REQUIRE_VERIFY_SPDX_V2 "${spdx_v23_verify_require_help_string}" OFF)
+
+
+ # Options for CycloneDX verification and verbosity.
+
+ set(cydx_verify_help_string
+ "Verify generated CycloneDX document against its json schema.")
+ option(QT_SBOM_VERIFY_CYDX_V1_6 "${cydx_verify_help_string}" ON)
+
+ set(cydx_verify_require_help_string
+ "Error out if SBOM verification dependencies are not found.")
+ option(QT_SBOM_REQUIRE_VERIFY_CYDX_V1_6 "${cydx_verify_require_help_string}" OFF)
+
+ set(cydx_verbose_help_string
+ "Enable verbose output for CycloneDX generation.")
+ option(QT_SBOM_VERBOSE_CYDX_V1_6 "${cydx_verbose_help_string}" OFF)
+
+
+ # Deprecated options, superseded by the options above.
+ # Only add them if the values was previously defined, but update the doc string.
+
+ if(DEFINED QT_SBOM_GENERATE_JSON)
+ option(QT_SBOM_GENERATE_JSON "Deprecated: ${spdx_v23_json_help_string}" ON)
+ endif()
+ if(DEFINED QT_SBOM_REQUIRE_GENERATE_JSON)
+ option(QT_SBOM_REQUIRE_GENERATE_JSON "Deprecated: ${spdx_v23_json_require_help_string}" OFF)
+ endif()
+ if(DEFINED QT_SBOM_VERIFY)
+ option(QT_SBOM_VERIFY "Deprecated: ${spdx_v23_verify_help_string}" ON)
+ endif()
+ if(DEFINED QT_SBOM_REQUIRE_VERIFY)
+ option(QT_SBOM_REQUIRE_VERIFY "Deprecated: ${spdx_v23_verify_require_help_string}" OFF)
+ endif()
+
+ # Semi-public, undocumented options to allow enabling all SBOM stuff, for easier testing.
+ if(QT_SBOM_GENERATE_AND_VERIFY_ALL)
+ set(QT_SBOM_GENERATE_ALL ON)
+ set(QT_SBOM_GENERATE_REQUIRED_ALL ON)
+ set(QT_SBOM_VERIFY_REQUIRED_ALL ON)
+ endif()
+
+ if(QT_SBOM_GENERATE_ALL)
+ set(QT_GENERATE_SBOM ON CACHE BOOL "${sbom_help_string}" FORCE)
+ set(QT_SBOM_GENERATE_SPDX_V2 ON CACHE BOOL "${spdx_v2_help_string}" FORCE)
+ set(QT_SBOM_GENERATE_SPDX_V2_JSON ON CACHE BOOL "${spdx_v23_json_help_string}" FORCE)
+ set(QT_SBOM_GENERATE_CYDX_V1_6 ON CACHE BOOL "${cydx_help_string}" FORCE)
+ unset(QT_SBOM_GENERATE_ALL CACHE)
+ unset(QT_SBOM_GENERATE_ALL)
+ endif()
+
+ if(QT_SBOM_GENERATE_REQUIRED_ALL)
+ set(QT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON ON CACHE BOOL
+ "${spdx_v23_json_require_help_string}" FORCE)
+ set(QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6 ON CACHE BOOL "${cydx_require_help_string}" FORCE)
+
+ unset(QT_SBOM_GENERATE_REQUIRED_ALL CACHE)
+ unset(QT_SBOM_GENERATE_REQUIRED_ALL)
+ endif()
+
+ if(QT_SBOM_VERIFY_REQUIRED_ALL)
+ set(QT_SBOM_VERIFY_SPDX_V2 ON CACHE BOOL "${spdx_v23_verify_help_string}" FORCE)
+ set(QT_SBOM_VERIFY_CYDX_V1_6 ON CACHE BOOL "${cydx_verify_help_string}" FORCE)
+
+ set(QT_SBOM_REQUIRE_VERIFY_SPDX_V2 ON CACHE BOOL "${spdx_v23_verify_require_help_string}"
+ FORCE)
+ set(QT_SBOM_REQUIRE_VERIFY_CYDX_V1_6 ON CACHE BOOL "${cydx_verify_require_help_string}"
+ FORCE)
+
+ unset(QT_SBOM_VERIFY_ALL CACHE)
+ unset(QT_SBOM_VERIFY_ALL)
+ endif()
+
+ # Various sanity checks.
+
+ # Disable SPDX v2.3 JSON generation if tag:value generation is disabled.
+ if(QT_GENERATE_SBOM
+ AND QT_SBOM_GENERATE_SPDX_V2_JSON
+ AND NOT QT_SBOM_GENERATE_SPDX_V2)
+ if(NOT QT_NO_SBOM_INFORMATIONAL_MESSAGES)
+ message(STATUS
+ "Disabling SPDX v2.3 SBOM JSON generation because tag:value generation is "
+ "disabled and that is a requirement for JSON generation.")
+ endif()
+ set(QT_SBOM_GENERATE_SPDX_V2_JSON OFF CACHE BOOL "${spdx_v23_json_help_string}" FORCE)
+ set(QT_SBOM_VERIFY_SPDX_V2 OFF CACHE BOOL "${spdx_v23_verify_help_string}" FORCE)
+ endif()
+
+ # Disable CycloneDX generation if dependencies are not found and it wasn't required.
+ if(QT_GENERATE_SBOM
+ AND QT_SBOM_GENERATE_CYDX_V1_6
+ AND NOT QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6)
+ _qt_internal_sbom_find_cydx_dependencies(OUT_VAR_DEPS_FOUND deps_found)
+ if(NOT deps_found)
+ if(NOT QT_NO_SBOM_INFORMATIONAL_MESSAGES)
+ message(STATUS
+ "Disabling Cyclone DX SBOM generation because dependencies were not found, "
+ "and generation was not marked as required.")
+ endif()
+ set(QT_SBOM_GENERATE_CYDX_V1_6 OFF CACHE BOOL "${cydx_help_string}" FORCE)
+ endif()
+ endif()
+
+ # Disable sbom generation if none of the formats are enabled. Failing to do so will cause
+ # errors in _qt_internal_sbom_begin_project.
+ if(QT_GENERATE_SBOM
+ AND NOT QT_SBOM_GENERATE_SPDX_V2
+ AND NOT QT_SBOM_GENERATE_CYDX_V1_6)
+ if(NOT QT_NO_SBOM_INFORMATIONAL_MESSAGES)
+ message(STATUS
+ "Disabling SBOM generation because none of the supported formats were enabled.")
+ endif()
+ set(QT_GENERATE_SBOM OFF CACHE BOOL "${sbom_help_string}" FORCE)
+ endif()
endfunction()
# Ends repo sbom project generation.
@@ -415,10 +636,6 @@ function(_qt_internal_sbom_end_project)
return()
endif()
- # Now that we know which system libraries are linked against because we added all
- # subdirectories, we can add the recorded system libs to the sbom.
- _qt_internal_sbom_add_recorded_system_libraries()
-
# Run sbom finalization for targets that had it scheduled, but haven't run yet.
# This can happen when _qt_internal_sbom_end_project is called within the same
# subdirectory scope as where the targets are meant to be finalized, but that would be too late
@@ -462,7 +679,24 @@ function(_qt_internal_sbom_end_project)
endif()
endwhile()
- _qt_internal_sbom_end_project_generate()
+ # Now that we know which system libraries are linked against because we added all
+ # subdirectories and finalized all targets, we can add the recorded system libs to the sbom.
+ _qt_internal_sbom_add_recorded_system_libraries()
+
+ # Add any external target dependencies, for CycloneDX generation.
+ # E.g. For QtSvg, we need to create a QtCore component in the QtSvg document, so that we
+ # can declare a dependency on it.
+ if(QT_SBOM_GENERATE_CYDX_V1_6)
+ _qt_internal_sbom_add_cydx_external_target_dependencies()
+ endif()
+
+ if(QT_SBOM_GENERATE_SPDX_V2)
+ _qt_internal_sbom_end_project_generate()
+ endif()
+
+ if(QT_SBOM_GENERATE_CYDX_V1_6)
+ _qt_internal_sbom_end_project_generate_cyclone()
+ endif()
# Clean up external document ref properties, because each repo needs to start from scratch
# in a top-level build.
@@ -777,7 +1011,8 @@ function(_qt_internal_sbom_add_target target)
set_target_properties(${target} PROPERTIES _qt_sbom_is_qt_module TRUE)
endif()
- set(project_package_options "")
+ set(project_package_options_spdx "")
+ set(project_package_options_cydx "")
if(arg_FRIENDLY_PACKAGE_NAME)
set(package_name_for_spdx_id "${arg_FRIENDLY_PACKAGE_NAME}")
@@ -887,7 +1122,8 @@ function(_qt_internal_sbom_add_target target)
endif()
if(license_expression)
- list(APPEND project_package_options LICENSE_CONCLUDED "${license_expression}")
+ list(APPEND project_package_options_spdx LICENSE_CONCLUDED "${license_expression}")
+ list(APPEND project_package_options_cydx LICENSE_CONCLUDED "${license_expression}")
endif()
if(license_expression AND
@@ -898,7 +1134,9 @@ function(_qt_internal_sbom_add_target target)
LICENSE_CONCLUDED_EXPRESSION "${license_expression}"
OUT_VAR qt_entity_license_declared_expression)
if(qt_entity_license_declared_expression)
- list(APPEND project_package_options
+ list(APPEND project_package_options_spdx
+ LICENSE_DECLARED "${qt_entity_license_declared_expression}")
+ list(APPEND project_package_options_cydx
LICENSE_DECLARED "${qt_entity_license_declared_expression}")
endif()
endif()
@@ -923,7 +1161,8 @@ function(_qt_internal_sbom_add_target target)
endif()
if(copyrights)
list(JOIN copyrights "\n" copyrights)
- list(APPEND project_package_options COPYRIGHT "<text>${copyrights}</text>")
+ list(APPEND project_package_options_spdx COPYRIGHT "<text>${copyrights}</text>")
+ list(APPEND project_package_options_cydx COPYRIGHT "${copyrights}")
endif()
set(package_version "")
@@ -943,7 +1182,12 @@ function(_qt_internal_sbom_add_target target)
endif()
if(package_version)
- list(APPEND project_package_options VERSION "${package_version}")
+ list(APPEND project_package_options_spdx VERSION "${package_version}")
+ list(APPEND project_package_options_cydx VERSION "${package_version}")
+
+ # Also export the value in a target property, to make it available for cydx generation.
+ set_property(TARGET "${target}" PROPERTY _qt_sbom_package_version "${package_version}")
+ set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_sbom_package_version)
endif()
set(supplier "")
@@ -961,7 +1205,8 @@ function(_qt_internal_sbom_add_target target)
endif()
if(supplier)
- list(APPEND project_package_options SUPPLIER "Organization: ${supplier}")
+ list(APPEND project_package_options_spdx SUPPLIER "Organization: ${supplier}")
+ list(APPEND project_package_options_cydx CYDX_SUPPLIER "${supplier}")
endif()
set(download_location "")
@@ -1002,11 +1247,12 @@ function(_qt_internal_sbom_add_target target)
endif()
if(download_location)
- list(APPEND project_package_options DOWNLOAD_LOCATION "${download_location}")
+ list(APPEND project_package_options_spdx DOWNLOAD_LOCATION "${download_location}")
+ list(APPEND project_package_options_cydx DOWNLOAD_LOCATION "${download_location}")
endif()
_qt_internal_sbom_get_package_purpose("${sbom_entity_type}" package_purpose)
- list(APPEND project_package_options PURPOSE "${package_purpose}")
+ list(APPEND project_package_options_spdx PURPOSE "${package_purpose}")
set(cpe_values "")
@@ -1046,7 +1292,8 @@ function(_qt_internal_sbom_add_target target)
endif()
if(cpe_values)
- list(APPEND project_package_options CPE ${cpe_values})
+ list(APPEND project_package_options_spdx CPE ${cpe_values})
+ list(APPEND project_package_options_cydx CPE ${cpe_values})
endif()
# Assemble arguments to forward to the function that handles purl options.
@@ -1088,12 +1335,16 @@ function(_qt_internal_sbom_add_target target)
list(APPEND purl_args PURL_VALUES ${qa_purls_replaced})
endif()
- list(APPEND purl_args OUT_VAR purl_package_options)
+ list(APPEND purl_args
+ OUT_VAR_PURL_VALUES purl_values
+ OUT_VAR_SPDX_EXT_REF_VALUES spdx_ext_ref_values
+ )
_qt_internal_sbom_handle_purl_values(${target} ${purl_args})
- if(purl_package_options)
- list(APPEND project_package_options ${purl_package_options})
+ if(spdx_ext_ref_values)
+ list(APPEND project_package_options_spdx ${spdx_ext_ref_values})
+ list(APPEND project_package_options_cydx PURL_VALUES ${purl_values})
endif()
if(arg_USE_ATTRIBUTION_FILES)
@@ -1136,32 +1387,75 @@ function(_qt_internal_sbom_add_target target)
endif()
if(package_comment)
- list(APPEND project_package_options COMMENT "<text>\n${package_comment}</text>")
+ list(APPEND project_package_options_spdx COMMENT "<text>\n${package_comment}</text>")
+ list(APPEND project_package_options_cydx COMMENT "\n${package_comment}")
endif()
_qt_internal_sbom_handle_target_dependencies("${target}"
SPDX_ID "${package_spdx_id}"
LIBRARIES "${arg_LIBRARIES}"
PUBLIC_LIBRARIES "${arg_PUBLIC_LIBRARIES}"
- OUT_RELATIONSHIPS relationships
+ OUT_CYDX_DEPENDENCIES cydx_dependencies
+ OUT_SPDX_RELATIONSHIPS spdx_relationships
+ OUT_EXTERNAL_TARGET_DEPENDENCIES external_target_dependencies
)
+ if(cydx_dependencies)
+ list(APPEND project_package_options_cydx DEPENDENCIES ${cydx_dependencies})
+ endif()
+
+ # These are processed at the end of document generation.
+ if(external_target_dependencies)
+ _qt_internal_sbom_record_external_target_dependecies(
+ TARGETS ${external_target_dependencies}
+ )
+ endif()
get_cmake_property(project_spdx_id _qt_internal_sbom_project_spdx_id)
- list(APPEND relationships "${project_spdx_id} CONTAINS ${package_spdx_id}")
+ list(APPEND spdx_relationships "${project_spdx_id} CONTAINS ${package_spdx_id}")
if(arg_SBOM_RELATIONSHIPS)
- list(APPEND relationships "${arg_SBOM_RELATIONSHIPS}")
+ list(APPEND spdx_relationships "${arg_SBOM_RELATIONSHIPS}")
endif()
- list(REMOVE_DUPLICATES relationships)
- list(JOIN relationships "\nRelationship: " relationships)
- list(APPEND project_package_options RELATIONSHIP "${relationships}")
+ list(REMOVE_DUPLICATES spdx_relationships)
+ list(JOIN spdx_relationships "\nRelationship: " relationships)
+ list(APPEND project_package_options_spdx RELATIONSHIP "${relationships}")
- _qt_internal_sbom_generate_add_package(
- PACKAGE "${package_name_for_spdx_id}"
- SPDXID "${package_spdx_id}"
- ${project_package_options}
- )
+ if(QT_SBOM_GENERATE_SPDX_V2)
+ _qt_internal_sbom_generate_add_package(
+ PACKAGE "${package_name_for_spdx_id}"
+ SPDXID "${package_spdx_id}"
+ ${project_package_options_spdx}
+ )
+ endif()
+
+ if(QT_SBOM_GENERATE_CYDX_V1_6)
+ get_property(external_targets
+ GLOBAL PROPERTY _qt_internal_sbom_external_target_dependencies)
+
+ # Prevent against case when a system library is also an external target dependency,
+ # which would lead to its creation twice, once via
+ # _qt_internal_sbom_add_recorded_system_libraries
+ # and second time via
+ # _qt_internal_sbom_add_cydx_external_target_dependencies.
+ # Skip the case when it's done via the first function, and only allow the second.
+ # TODO: Can this be done better somehow?
+ if(NOT target IN_LIST external_targets)
+ _qt_internal_sbom_handle_qt_entity_cydx_properties(
+ SBOM_ENTITY_TYPE "${sbom_entity_type}"
+ OUT_CYDX_PROPERTIES cydx_properties
+ )
+
+ _qt_internal_sbom_generate_cyclone_add_package(
+ PACKAGE "${package_name_for_spdx_id}"
+ SPDXID "${package_spdx_id}"
+ SBOM_ENTITY_TYPE "${sbom_entity_type}"
+ ${project_package_options_cydx}
+ CONTAINING_COMPONENT "${project_spdx_id}"
+ CYDX_PROPERTIES ${cydx_properties}
+ )
+ endif()
+ endif()
set(no_install_option "")
if(arg_NO_INSTALL)
@@ -1199,25 +1493,27 @@ function(_qt_internal_sbom_add_target target)
set(license_option LICENSE_EXPRESSION "${license_expression}")
endif()
- _qt_internal_sbom_handle_target_binary_files("${target}"
- ${no_install_option}
- ${framework_option}
- ${install_prefix_option}
- SBOM_ENTITY_TYPE "${sbom_entity_type}"
- ${target_binary_multi_config_args}
- SPDX_ID "${package_spdx_id}"
- ${copyrights_option}
- ${license_option}
- )
+ if(QT_SBOM_GENERATE_SPDX_V2)
+ _qt_internal_sbom_handle_target_binary_files("${target}"
+ ${no_install_option}
+ ${framework_option}
+ ${install_prefix_option}
+ SBOM_ENTITY_TYPE "${sbom_entity_type}"
+ ${target_binary_multi_config_args}
+ SPDX_ID "${package_spdx_id}"
+ ${copyrights_option}
+ ${license_option}
+ )
- _qt_internal_sbom_handle_target_custom_files("${target}"
- ${no_install_option}
- ${install_prefix_option}
- PACKAGE_TYPE "${sbom_entity_type}"
- PACKAGE_SPDX_ID "${package_spdx_id}"
- ${copyrights_option}
- ${license_option}
- )
+ _qt_internal_sbom_handle_target_custom_files("${target}"
+ ${no_install_option}
+ ${install_prefix_option}
+ PACKAGE_TYPE "${sbom_entity_type}"
+ PACKAGE_SPDX_ID "${package_spdx_id}"
+ ${copyrights_option}
+ ${license_option}
+ )
+ endif()
endfunction()
# Helper to add sbom information for a possibly non-existing target.
@@ -1576,7 +1872,11 @@ function(_qt_internal_sbom_record_target_spdx_id target)
SBOM_ENTITY_TYPE "${arg_SBOM_ENTITY_TYPE}"
PACKAGE_NAME "${package_name_for_spdx_id}"
)
- _qt_internal_sbom_save_spdx_id_for_target("${target}" "${package_spdx_id}")
+ _qt_internal_sbom_save_spdx_id_for_target("${target}"
+ SPDX_ID "${package_spdx_id}"
+ PACKAGE_NAME "${package_name_for_spdx_id}"
+ SBOM_ENTITY_TYPE "${arg_SBOM_ENTITY_TYPE}"
+ )
_qt_internal_sbom_is_qt_entity_type("${arg_SBOM_ENTITY_TYPE}" is_qt_entity_type)
_qt_internal_sbom_save_spdx_id_for_qt_entity_type(
@@ -1615,10 +1915,36 @@ function(_qt_internal_sbom_generate_target_package_spdx_id out_var)
endfunction()
# Save a spdx id for a target inside its target properties.
-# Also saves the repo document namespace and relative installed repo document path.
# These are used when generating a SPDX external document reference for exported targets, to
# include them in relationships.
-function(_qt_internal_sbom_save_spdx_id_for_target target spdx_id)
+# Also saves the repo document namespace and relative installed repo document path.
+# Also saves the sbom entity type and package name, because it's needed when creating CycloneDX
+# components where the target is in an external document.
+function(_qt_internal_sbom_save_spdx_id_for_target target)
+ set(opt_args "")
+ set(single_args
+ SPDX_ID
+ PACKAGE_NAME
+ SBOM_ENTITY_TYPE
+ )
+ 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_SPDX_ID)
+ message(FATAL_ERROR "arg_SPDX_ID must be set")
+ endif()
+
+ if(NOT arg_PACKAGE_NAME)
+ message(FATAL_ERROR "PACKAGE_NAME must be set")
+ endif()
+
+ if(NOT arg_SBOM_ENTITY_TYPE)
+ message(FATAL_ERROR "SBOM_ENTITY_TYPE must be set")
+ endif()
+
+ set(spdx_id "${arg_SPDX_ID}")
+
message(DEBUG "Saving spdx id for target ${target}: ${spdx_id}")
set(target_unaliased "${target}")
@@ -1631,6 +1957,9 @@ function(_qt_internal_sbom_save_spdx_id_for_target target spdx_id)
get_property(repo_document_namespace
GLOBAL PROPERTY _qt_internal_sbom_repo_document_namespace)
+ get_property(bom_serial_number_uuid
+ GLOBAL PROPERTY _qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid)
+
get_property(relative_installed_repo_document_path
GLOBAL PROPERTY _qt_internal_sbom_relative_installed_repo_document_path)
@@ -1643,6 +1972,10 @@ function(_qt_internal_sbom_save_spdx_id_for_target target spdx_id)
"${repo_document_namespace}")
set_property(TARGET ${target_unaliased} PROPERTY
+ _qt_sbom_cydx_bom_serial_number_uuid
+ "${bom_serial_number_uuid}")
+
+ set_property(TARGET ${target_unaliased} PROPERTY
_qt_sbom_spdx_relative_installed_repo_document_path
"${relative_installed_repo_document_path}")
@@ -1650,11 +1983,22 @@ function(_qt_internal_sbom_save_spdx_id_for_target target spdx_id)
_qt_sbom_spdx_repo_project_name_lowercase
"${project_name_lowercase}")
+ set_property(TARGET ${target_unaliased} PROPERTY
+ _qt_sbom_package_name
+ "${arg_PACKAGE_NAME}")
+
+ set_property(TARGET ${target_unaliased} PROPERTY
+ _qt_sbom_entity_type
+ "${arg_SBOM_ENTITY_TYPE}")
+
# Export the properties, so they can be queried by other repos.
# We also do it for versionless targets.
set(export_properties
+ _qt_sbom_entity_type
+ _qt_sbom_package_name
_qt_sbom_spdx_id
_qt_sbom_spdx_repo_document_namespace
+ _qt_sbom_cydx_bom_serial_number_uuid
_qt_sbom_spdx_relative_installed_repo_document_path
_qt_sbom_spdx_repo_project_name_lowercase
)
@@ -1719,11 +2063,18 @@ function(_qt_internal_sbom_save_spdx_id_for_qt_entity_type target is_qt_entity_t
versionless_target
versionless_private_target
)
+
+ get_property(package_name TARGET "${target}" PROPERTY _qt_sbom_package_name)
+ get_property(sbom_entity_type TARGET "${target}" PROPERTY _qt_sbom_entity_type)
endif()
foreach(target_name IN LISTS ${target_names})
if(TARGET "${target_name}")
- _qt_internal_sbom_save_spdx_id_for_target("${target_name}" "${package_spdx_id}")
+ _qt_internal_sbom_save_spdx_id_for_target("${target_name}"
+ SPDX_ID "${package_spdx_id}"
+ PACKAGE_NAME "${package_name}"
+ SBOM_ENTITY_TYPE "${sbom_entity_type}"
+ )
endif()
endforeach()
endfunction()
@@ -2025,7 +2376,12 @@ endfunction()
function(_qt_internal_sbom_compute_project_file_name out_var)
set(opt_args
- EXTENSION_JSON
+ SPDX_TAG_VALUE
+ SPDX_JSON
+ CYCLONEDX_JSON
+ CYCLONEDX_TOML
+
+ EXTENSION_JSON # deprecated, used by WebEngine
)
set(single_args
PROJECT_NAME
@@ -2040,6 +2396,16 @@ function(_qt_internal_sbom_compute_project_file_name out_var)
message(FATAL_ERROR "PROJECT_NAME must be set")
endif()
+ if(NOT arg_SPDX_JSON
+ AND NOT arg_SPDX_TAG_VALUE
+ AND NOT arg_CYCLONEDX_TOML
+ AND NOT arg_CYCLONEDX_JSON
+ AND NOT arg_EXTENSION_JSON
+ )
+ message(FATAL_ERROR "One of the following options should be set: "
+ "SPDX_TAG_VALUE, SPDX_JSON, CYCLONEDX_JSON, CYCLONEDX_TOML")
+ endif()
+
string(TOLOWER "${arg_PROJECT_NAME}" project_name_lowercase)
set(version_suffix "")
@@ -2050,10 +2416,16 @@ function(_qt_internal_sbom_compute_project_file_name out_var)
set(version_suffix "-${QT_REPO_MODULE_VERSION}")
endif()
- if(arg_EXTENSION_JSON)
+ if(arg_SPDX_TAG_VALUE)
+ set(extension "spdx")
+ elseif(arg_SPDX_JSON OR arg_EXTENSION_JSON)
set(extension "spdx.json")
+ elseif(arg_CYCLONEDX_TOML)
+ set(extension "cdx.toml")
+ elseif(arg_CYCLONEDX_JSON)
+ set(extension "cdx.json")
else()
- set(extension "spdx")
+ message(FATAL_ERROR "Unknown file extension for SBOM generation.")
endif()
set(result