diff --git a/cmake/QtBuildHelpers.cmake b/cmake/QtBuildHelpers.cmake index 9a11a91826e..4d50f15518e 100644 --- a/cmake/QtBuildHelpers.cmake +++ b/cmake/QtBuildHelpers.cmake @@ -421,6 +421,8 @@ macro(qt_internal_setup_build_and_global_variables) qt_internal_setup_build_tools() + qt_internal_setup_sbom() + # Depends on qt_internal_setup_default_install_prefix qt_internal_setup_build_examples() diff --git a/cmake/QtBuildOptionsHelpers.cmake b/cmake/QtBuildOptionsHelpers.cmake index 18dfec47346..1f7b72cf1cd 100644 --- a/cmake/QtBuildOptionsHelpers.cmake +++ b/cmake/QtBuildOptionsHelpers.cmake @@ -300,6 +300,63 @@ macro(qt_internal_setup_build_tools) unset(_qt_build_tools_by_default_default) endmacro() +# A heuristic to determine that the currently processed project is a cmake build test project. +function(qt_internal_current_project_is_cmake_build_test_project out_var) + set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + + set(result FALSE) + + if(current_dir MATCHES "tests/auto/cmake") + set(result TRUE) + endif() + + set(${out_var} "${result}" PARENT_SCOPE) +endfunction() + +function(qt_internal_compute_sbom_default out_var) + # Default to generating the SBOM, except for: + # - developer-builds + # - no-prefix builds. + # - standalone tests or examples + # - cmake build tests + # Regular developers of Qt (which would pass -developer-build) likely don't need SBOMs. + # -no-prefix builds don't make much sense for SBOMs because the installed file checksums + # will be missing, and thus the SBOMs will not be complete / valid. + # Honor any explicitly or previously set value. + qt_internal_current_project_is_cmake_build_test_project(is_cmake_build_test) + + if(FEATURE_developer_build + OR QT_FEATURE_developer_build + OR FEATURE_no_prefix + OR QT_FEATURE_no_prefix + OR QT_BUILD_STANDALONE_EXAMPLES + OR QT_BUILD_STANDALONE_TESTS + OR QT_INTERNAL_BUILD_STANDALONE_PARTS + OR is_cmake_build_test + ) + set(enable_sbom OFF) + else() + set(enable_sbom ON) + endif() + set(${out_var} "${enable_sbom}" PARENT_SCOPE) +endfunction() + +macro(qt_internal_setup_sbom) + qt_internal_compute_sbom_default(_qt_generate_sbom_default) + + option(QT_GENERATE_SBOM "Generate SBOM documents in SPDX v2.3 tag:value format." + "${_qt_generate_sbom_default}") + + option(QT_SBOM_GENERATE_JSON + "Generate SBOM documents in SPDX v2.3 JSON format if dependencies are available" ON) + option(QT_SBOM_REQUIRE_GENERATE_JSON + "Error out if JSON SBOM generation dependencies are not found." OFF) + + option(QT_SBOM_VERIFY "Verify generated SBOM documents." ON) + option(QT_SBOM_REQUIRE_VERIFY + "Error out if SBOM verification dependencies are not found." OFF) +endmacro() + macro(qt_internal_setup_build_examples) option(QT_BUILD_EXAMPLES "Build Qt examples" OFF) option(QT_BUILD_EXAMPLES_BY_DEFAULT diff --git a/cmake/QtProcessConfigureArgs.cmake b/cmake/QtProcessConfigureArgs.cmake index dca6b7cbb81..6fdce4082d7 100644 --- a/cmake/QtProcessConfigureArgs.cmake +++ b/cmake/QtProcessConfigureArgs.cmake @@ -150,8 +150,6 @@ while(NOT "${configure_args}" STREQUAL "") elseif(arg STREQUAL "-no-prefix") set(no_prefix_option TRUE) push("-DFEATURE_no_prefix=ON") - elseif(arg STREQUAL "-sbom") - push("-DQT_GENERATE_SBOM=ON") elseif(arg STREQUAL "-cmake-file-api") set(cmake_file_api TRUE) elseif(arg STREQUAL "-no-cmake-file-api") @@ -317,6 +315,11 @@ endfunction() # Add the common command line options for every qt repo. macro(qt_add_common_commandline_options) qt_commandline_option(headersclean TYPE boolean) + qt_commandline_option(sbom TYPE boolean) + qt_commandline_option(sbom-json TYPE boolean) + qt_commandline_option(sbom-json-required TYPE boolean) + qt_commandline_option(sbom-verify TYPE boolean) + qt_commandline_option(sbom-verify-required TYPE boolean) endmacro() function(qt_commandline_prefix arg var) @@ -927,6 +930,11 @@ translate_boolean_input(unity_build QT_UNITY_BUILD) translate_string_input(unity_build_batch_size QT_UNITY_BUILD_BATCH_SIZE) translate_boolean_input(ccache QT_USE_CCACHE) translate_boolean_input(vcpkg QT_USE_VCPKG) +translate_boolean_input(sbom QT_GENERATE_SBOM) +translate_boolean_input(sbom-json QT_SBOM_GENERATE_JSON) +translate_boolean_input(sbom-json-required QT_SBOM_REQUIRE_GENERATE_JSON) +translate_boolean_input(sbom-verify QT_SBOM_VERIFY) +translate_boolean_input(sbom-verify-required QT_SBOM_REQUIRE_VERIFY) translate_boolean_input(shared BUILD_SHARED_LIBS) translate_boolean_input(warnings_are_errors WARNINGS_ARE_ERRORS) translate_boolean_input(qtinlinenamespace QT_INLINE_NAMESPACE) diff --git a/cmake/QtPublicSbomGenerationHelpers.cmake b/cmake/QtPublicSbomGenerationHelpers.cmake index 2efa574fdf0..f85a97dacde 100644 --- a/cmake/QtPublicSbomGenerationHelpers.cmake +++ b/cmake/QtPublicSbomGenerationHelpers.cmake @@ -229,8 +229,10 @@ endfunction() function(_qt_internal_sbom_end_project_generate) set(opt_args GENERATE_JSON + GENERATE_JSON_REQUIRED GENERATE_SOURCE_SBOM - VERIFY + VERIFY_SBOM + VERIFY_SBOM_REQUIRED VERIFY_NTIA_COMPLIANT LINT_SOURCE_SBOM LINT_SOURCE_SBOM_NO_ERROR @@ -258,13 +260,33 @@ function(_qt_internal_sbom_end_project_generate) _qt_internal_get_staging_area_spdx_file_path(staging_area_spdx_file) if(arg_GENERATE_JSON AND NOT QT_INTERNAL_NO_SBOM_PYTHON_OPS) - _qt_internal_sbom_find_and_handle_sbom_op_dependencies(REQUIRED OP_KEY "GENERATE_JSON") - _qt_internal_sbom_generate_json() + set(op_args + OP_KEY "GENERATE_JSON" + OUT_VAR_DEPS_FOUND deps_found + ) + if(arg_GENERATE_JSON_REQUIRED) + list(APPEND op_args REQUIRED) + endif() + + _qt_internal_sbom_find_and_handle_sbom_op_dependencies(${op_args}) + if(deps_found) + _qt_internal_sbom_generate_json() + endif() endif() - if(arg_VERIFY AND NOT QT_INTERNAL_NO_SBOM_PYTHON_OPS) - _qt_internal_sbom_find_and_handle_sbom_op_dependencies(REQUIRED OP_KEY "VERIFY_SBOM") - _qt_internal_sbom_verify_valid() + if(arg_VERIFY_SBOM AND NOT QT_INTERNAL_NO_SBOM_PYTHON_OPS) + set(op_args + OP_KEY "VERIFY_SBOM" + OUT_VAR_DEPS_FOUND deps_found + ) + if(arg_VERIFY_SBOM_REQUIRED) + list(APPEND op_args REQUIRED) + endif() + + _qt_internal_sbom_find_and_handle_sbom_op_dependencies(${op_args}) + if(deps_found) + _qt_internal_sbom_verify_valid() + endif() endif() if(arg_VERIFY_NTIA_COMPLIANT AND NOT QT_INTERNAL_NO_SBOM_PYTHON_OPS) diff --git a/cmake/QtPublicSbomHelpers.cmake b/cmake/QtPublicSbomHelpers.cmake index 8ee853f65f8..db41ff7e6cd 100644 --- a/cmake/QtPublicSbomHelpers.cmake +++ b/cmake/QtPublicSbomHelpers.cmake @@ -245,24 +245,44 @@ function(_qt_internal_sbom_end_project) endif() set(end_project_options "") - if(QT_INTERNAL_SBOM_VERIFY OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) - list(APPEND end_project_options VERIFY) + + if(QT_SBOM_GENERATE_JSON OR QT_INTERNAL_SBOM_GENERATE_JSON OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) + list(APPEND end_project_options GENERATE_JSON) endif() + + # Tring to generate the JSON might fail if the python dependencies are not available. + # 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 + OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) + list(APPEND end_project_options GENERATE_JSON_REQUIRED) + endif() + + if(QT_SBOM_VERIFY OR QT_INTERNAL_SBOM_VERIFY OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) + list(APPEND end_project_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) + list(APPEND end_project_options VERIFY_SBOM_REQUIRED) + endif() + if(QT_INTERNAL_SBOM_VERIFY_NTIA_COMPLIANT OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) list(APPEND end_project_options VERIFY_NTIA_COMPLIANT) endif() + if(QT_INTERNAL_SBOM_SHOW_TABLE OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) list(APPEND end_project_options SHOW_TABLE) endif() + if(QT_INTERNAL_SBOM_AUDIT OR QT_INTERNAL_SBOM_AUDIT_NO_ERROR) list(APPEND end_project_options AUDIT) endif() + if(QT_INTERNAL_SBOM_AUDIT_NO_ERROR) list(APPEND end_project_options AUDIT_NO_ERROR) endif() - if(QT_INTERNAL_SBOM_GENERATE_JSON OR QT_INTERNAL_SBOM_DEFAULT_CHECKS) - list(APPEND end_project_options GENERATE_JSON) - endif() if(QT_GENERATE_SOURCE_SBOM) list(APPEND end_project_options GENERATE_SOURCE_SBOM) diff --git a/cmake/configure-cmake-mapping.md b/cmake/configure-cmake-mapping.md index 0e281ac2190..a5a811bb2f0 100644 --- a/cmake/configure-cmake-mapping.md +++ b/cmake/configure-cmake-mapping.md @@ -45,7 +45,11 @@ The following table describes the mapping of configure options to CMake argument | -device-option | -DQT_QMAKE_DEVICE_OPTIONS=key1=value1;key2=value2 | Only used for generation qmake-compatibility files. | | | | The device options are written into mkspecs/qdevice.pri. | | -appstore-compliant | -DFEATURE_appstore_compliant=ON | | -| -sbom | -DQT_GENERATE_SBOM=ON | Enables generation and installation of an SBOM | +| -sbom | -DQT_GENERATE_SBOM=ON | Enables generation and installation of a SPDX SBOM documents | +| -sbom-json | -DQT_SBOM_GENERATE_JSON=ON | Enables generation of SPDX SBOM in JSON format | +| -sbom-json-required | -DQT_SBOM_REQUIRE_GENERATE_JSON=ON | Fails the build if Python deps are not found | +| -sbom-verify | -DQT_SBOM_VERIFY=ON | Enables verification of generated SBOMs | +| -sbom-verify-required | -DQT_SBOM_REQUIRE_VERIFY=ON | Fails the build if Python deps are not found | | -qtinlinenamespace | -DQT_INLINE_NAMESPACE=ON | Make the namespace specified by -qtnamespace an inline one. | | -qtnamespace | -DQT_NAMESPACE= | | | -qtlibinfix | -DQT_LIBINFIX= | | diff --git a/config_help.txt b/config_help.txt index fb9268ab663..deb38c9c2f1 100644 --- a/config_help.txt +++ b/config_help.txt @@ -105,8 +105,18 @@ Build options: through an app store by default, in particular Android, iOS, tvOS, and watchOS. [auto] - -sbom ................ Enable Software Bill of Materials (SBOM) generation - [no] + -sbom ................ Enable generation of Software Bill of Materials (SBOM) + documents in SPDX tag:value format + [yes; no for developer builds] + -sbom-json ........... Enable SBOM generation in SPDX JSON format [auto] + (if Python dependencies are available) + -sbom-json-required .. Fails the build if the Python dependencies for JSON + generation are not found [no] + -sbom-verify ......... Verify generated SBOM files [auto] (if Python + dependencies are available) + -sbom-verify-required Fails the build if the Python dependencies for SBOM + verification are not found [no] + -qt-host-path . Specify path to a Qt host build for cross-compiling. -qtnamespace .. Wrap all Qt library code in 'namespace {...}'.