CMake: Generate an SPDX v2.3 SBOM file for each built repository

This change adds a new -sbom configure option to allow generating and
installing an SPDX v2.3 SBOM file when building a qt repo.

The -sbom-dir option can be used to configure the location where
each repo sbom file will be installed.

By default it is installed into

 $prefix/$archdatadir/sbom/$sbom_lower_project_name.sdpx

which is basically ~/Qt/sbom/qtbase-6.8.0.spdx

The file is installed as part of the default installation rules, but
it can also be installed manually using the "sbom" installation
component, or "sbom_$lower_project_name" in a top-level build. For
example: cmake install . --component sbom_qtbase

CMake 3.19+ is needed to read the qt_attribution.json files for
copyrights, license info, etc. When using an older cmake version,
configuration will error out. It is possible to opt into using an
older cmake version, but the generated sbom will lack all the
attribution file information.
Using an older cmake version is untested and not officially supported.

Implementation notes.

The bulk of the implementation is split into 4 new files:

- QtPublicSbomHelpers.cmake - for Qt-specific collecting, processing
  and dispatching the generation of various pieces of the SBOM document
  e.g. a SDPX package associated with a target like Core, a SDPX
  file entry for each target binary file (per-config shared library,
  archive, executable, etc)

- QtPublicSbomGenerationHelpers.cmake - for non-Qt specific
  implementation of SPDX generation. This also has some code that was
  taken from the cmake-sbom 3rd party project, so it is dual licensed
  under the usual Qt build system BSD license, as well as the MIT
  license of the 3rd party project

- QtPublicGitHelpers.cmake - for git related features, mainly to embed
  queried hashes or tags into version strings, is dual-licensed for
  the same reasons as QtPublicSbomGenerationHelpers.cmake

- QtSbomHelpers.cmake - Qt-specific functions that just forward
  arguments to the public functions. These are meant to be used in our
  Qt CMakeLists.txt instead of the public _qt_internal_add_sbom ones
  for naming consistency. These function would mostly be used to
  annotate 3rd party libraries with sbom info and to add sbom info
  for unusual target setups (like the Bootstrap library), because most
  of the handling is already done automatically via
  qt_internal_add_module/plugin/etc.

The files are put into Public cmake files, with the future hope of
making this available to user projects in some capacity.

The distinction of Qt-specific and non-Qt specific code might blur a
bit, and thus the separation across files might not always be
consistent, but it was best effort.

The main purpose of the code is to collect various information about
targets and their relationships and generate equivalent SPDX info.

Collection is currently done for the following targets: Qt modules,
plugins, apps, tools, system libraries, bundled 3rd party libraries
and partial 3rd party sources compiled directly as part of Qt targets.

Each target has an equivalent SPDX package generated with information
like version, license, copyright, CPE (common vulnerability
identifier), files that belong to the package, and relationships on
other SPDX packages (associated cmake targets), mostly gathered from
direct linking dependencies.

Each package might also contain files, e.g. libQt6Core.so for the Core
target. Each file also has info like license id, copyrights, but also
the list of source files that were used to generate the file and a
sha1 checksum.

SPDX documents can also refer to packages in other SPDX documents, and
those are referred to via external document references. This is the
case when building qtdeclarative and we refer to Core.

For qt provided targets, we have complete information regarding
licenses, and copyrights.

For bundled 3rd party libraries, we should also have most information,
which is usually parsed from the
src/3rdparty/libfoo/qt_attribution.json files.
If there are multiple attribution files, or if the files have multiple
entries, we create a separate SBOM package for each of those entries,
because each might have a separate copyright or version, and an sbom
package can have only one version (although many copyrights).

For system libraries we usually lack the information because we don't
have attribution files for Find scripts. So the info needs to be
manually annotated via arguments to the sbom function calls, or the
FindFoo.cmake scripts expose that information in some form and we
can query it.

There are also corner cases like 3rdparty sources being directly
included in a Qt library, like the m4dc files for Gui, or PCRE2 for
Bootstrap.
Or QtWebEngine libraries (either Qt bundled or Chromium bundled or
system libraries) which get linked in by GN instead of CMake, so there
are no direct targets for them.
The information for these need to be annotated manually as well.

There is also a distinction to be made for static Qt builds (or any
static Qt library in a shared build), where the system libraries found
during the Qt build might not be the same that are linked into the
final user application or library.

The actual generation of the SBOM is done by file(GENERATE)-ing one
.cmake file for each target, file, external ref, etc, which will be
included in a top-level cmake script.

The top-level cmake script will run through each included file, to
append to a "staging" spdx file, which will then be used in a
configure_file() call to replace some final
variables, like embedding a file checksum.

There are install rules to generate a complete SBOM during
installation, and an optional 'sbom' custom target that allows
building an incomplete SBOM during the build step.

The build target is just for convenience and faster development
iteration time. It is incomplete because it is missing the installed
file SHA1 checksums and the document verification code (the sha1 of
all sha1s). We can't compute those during the build before the files
are actually installed.

A complete SBOM can only be achieved at installation time. The install
script will include all the generated helper files, but also set some
additional variables to ensure checksumming happens, and also handle
multi-config installation, among other small things.

For multi-config builds, CMake doesn't offer a way to run code after
all configs are installed, because they might not always be installed,
someone might choose to install just Release.
To handle that, we rely on ninja installing each config sequentially
(because ninja places the install rules into the 'console' pool which
runs one task at a time).
For each installed config we create a config-specific marker file.
Once all marker files are present, whichever config ends up being
installed as the last one, we run the sbom generation once, and then
delete all marker files.

There are a few internal variables that can be set during
configuration to enable various checks (and other features) on the
generated spdx files:

- QT_INTERNAL_SBOM_VERIFY
- QT_INTERNAL_SBOM_AUDIT
- QT_INTERNAL_SBOM_AUDIT_NO_ERROR
- QT_INTERNAL_SBOM_GENERATE_JSON
- QT_INTERNAL_SBOM_SHOW_TABLE
- QT_INTERNAL_SBOM_DEFAULT_CHECKS

These use 3rd party python tools, so they are not enabled by default.
If enabled, they run at installation time after the sbom is installed.
We will hopefully enable them in CI.

Overall, the code is still a bit messy in a few places, due to time
constraints, but can be improved later.

Some possible TODOs for the future:
- Do we need to handle 3rd party libs linked into a Qt static library
  in a Qt shared build, where the Qt static lib is not installed, but
  linked into a Qt shared library, somehow specially?
  We can record a package for it, but we can't
  create a spdx file record for it (and associated source
  relationships) because we don't install the file, and spdx requires
  the file to be installed and checksummed. Perhaps we can consider
  adding some free-form text snippet to the package itself?

- Do we want to add parsing of .cpp source files for Copyrights, to
  embed them into the packages? This will likely slow down
  configuration quite a bit.

- Currently sbom info attached to WrapFoo packages in one repo is
  not exported / available in other repos. E.g. If we annotate
  WrapZLIB in qtbase with CPE_VENDOR zlib, this info will not be
  available when looking up WrapZLIB in qtimageformats.
  This is because they are IMPORTED libraries, and are not
  exported. We might want to record this info in the future.

[ChangeLog][Build System] A new -sbom configure option can be used
to generate and install a SPDX SBOM (Software Bill of Materials) file
for each built Qt repository.

Task-number: QTBUG-122899
Change-Id: I9c730a6bbc47e02ce1836fccf00a14ec8eb1a5f4
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Reviewed-by:  Alexey Edelev <alexey.edelev@qt.io>
(cherry picked from commit 37a5e001277db9e1392a242171ab2b88cb6c3049)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Alexandru Croitor 2024-03-07 18:02:56 +01:00 committed by Qt Cherry-pick Bot
parent ac36373f6c
commit 65bf57ce7c
25 changed files with 4397 additions and 8 deletions

View File

@ -130,23 +130,49 @@ function(qt_internal_add_cmake_library target)
)
endfunction()
macro(qt_internal_get_3rdparty_library_sbom_options option_args single_args multi_args)
set(${option_args} "")
set(${single_args}
PACKAGE_VERSION
CPE_VENDOR
CPE_PRODUCT
LICENSE_EXPRESSION
DOWNLOAD_LOCATION
${__qt_internal_sbom_single_args}
)
set(${multi_args}
COPYRIGHTS
CPE # Common Platform Enumeration, free-form
${__qt_internal_sbom_multi_args}
)
endmacro()
# This function replaces qmake's qt_helper_lib feature. It is intended to
# compile 3rdparty libraries as part of the build.
#
function(qt_internal_add_3rdparty_library target)
qt_internal_get_add_library_option_args(library_option_args)
qt_internal_get_3rdparty_library_sbom_options(
sbom_option_args
sbom_single_args
sbom_multi_args
)
set(option_args
EXCEPTIONS
INSTALL
SKIP_AUTOMOC
${sbom_option_args}
)
set(single_args
OUTPUT_DIRECTORY
QMAKE_LIB_NAME
${sbom_single_args}
)
set(multi_args
${__default_private_args}
${__default_public_args}
${sbom_multi_args}
)
cmake_parse_arguments(PARSE_ARGV 1 arg
@ -253,6 +279,12 @@ function(qt_internal_add_3rdparty_library target)
)
if(NOT BUILD_SHARED_LIBS OR arg_INSTALL)
set(will_install TRUE)
else()
set(will_install FALSE)
endif()
if(will_install)
qt_generate_3rdparty_lib_pri_file("${target}" "${arg_QMAKE_LIB_NAME}" pri_file)
if(pri_file)
qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules")
@ -327,6 +359,55 @@ function(qt_internal_add_3rdparty_library target)
INTERPROCEDURAL_OPTIMIZATION OFF
)
endif()
if(QT_GENERATE_SBOM)
set(sbom_args "")
list(APPEND sbom_args TYPE QT_THIRD_PARTY_MODULE)
if(NOT will_install)
list(APPEND sbom_args NO_INSTALL)
endif()
qt_get_cmake_configurations(configs)
foreach(config IN LISTS configs)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
RUNTIME_PATH
"${INSTALL_BINDIR}"
"${config}"
sbom_args
)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
LIBRARY_PATH
"${INSTALL_LIBDIR}"
"${config}"
sbom_args
)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
ARCHIVE_PATH
"${INSTALL_LIBDIR}"
"${config}"
sbom_args
)
endforeach()
_qt_internal_forward_function_args(
FORWARD_APPEND
FORWARD_PREFIX arg
FORWARD_OUT_VAR sbom_args
FORWARD_SINGLE
${sbom_single_args}
FORWARD_MULTI
${sbom_multi_args}
)
_qt_internal_extend_sbom(${target} ${sbom_args})
endif()
qt_add_list_file_finalizer(qt_internal_finalize_3rdparty_library ${target})
endfunction()
function(qt_internal_finalize_3rdparty_library target)
_qt_internal_finalize_sbom(${target})
endfunction()
function(qt_install_3rdparty_library_wrap_config_extra_file target)

View File

@ -4,10 +4,27 @@
# This function creates a CMake target for a Qt internal app.
# Such projects had a load(qt_app) command.
function(qt_internal_add_app target)
set(option_args
NO_INSTALL
INSTALL_VERSIONED_LINK
EXCEPTIONS
NO_UNITY_BUILD
)
set(single_args
${__default_target_info_args}
${__qt_internal_sbom_single_args}
INSTALL_DIR
)
set(multi_args
${__default_private_args}
${__qt_internal_sbom_multi_args}
PUBLIC_LIBRARIES
)
cmake_parse_arguments(PARSE_ARGV 1 arg
"NO_INSTALL;INSTALL_VERSIONED_LINK;EXCEPTIONS;NO_UNITY_BUILD"
"${__default_target_info_args};INSTALL_DIR"
"${__default_private_args};PUBLIC_LIBRARIES"
"${option_args}"
"${single_args}"
"${multi_args}"
)
_qt_internal_validate_all_args_are_parsed(arg)
@ -67,6 +84,10 @@ function(qt_internal_add_app target)
MOC_OPTIONS ${arg_MOC_OPTIONS}
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
ATTRIBUTION_ENTRY_INDEX "${arg_ATTRIBUTION_ENTRY_INDEX}"
ATTRIBUTION_FILE_PATHS ${arg_ATTRIBUTION_FILE_PATHS}
ATTRIBUTION_FILE_DIR_PATHS ${arg_ATTRIBUTION_FILE_DIR_PATHS}
SBOM_DEPENDENCIES ${arg_SBOM_DEPENDENCIES}
TARGET_VERSION ${arg_TARGET_VERSION}
TARGET_PRODUCT ${arg_TARGET_PRODUCT}
TARGET_DESCRIPTION ${arg_TARGET_DESCRIPTION}
@ -96,6 +117,38 @@ function(qt_internal_add_app target)
TARGETS ${target})
endif()
if(QT_GENERATE_SBOM)
set(sbom_args "")
list(APPEND sbom_args TYPE QT_APP)
qt_get_cmake_configurations(cmake_configs)
foreach(cmake_config IN LISTS cmake_configs)
qt_get_install_target_default_args(
OUT_VAR unused_install_targets_default_args
OUT_VAR_RUNTIME runtime_install_destination
RUNTIME "${arg_INSTALL_DIR}"
CMAKE_CONFIG "${cmake_config}"
ALL_CMAKE_CONFIGS ${cmake_configs})
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
RUNTIME_PATH
"${runtime_install_destination}"
"${cmake_config}"
sbom_args
)
endforeach()
_qt_internal_forward_function_args(
FORWARD_APPEND
FORWARD_PREFIX arg
FORWARD_OUT_VAR sbom_args
FORWARD_OPTIONS
NO_INSTALL
)
_qt_internal_extend_sbom(${target} ${sbom_args})
endif()
qt_add_list_file_finalizer(qt_internal_finalize_app ${target})
endfunction()
@ -143,4 +196,5 @@ function(qt_internal_finalize_app target)
# set after a qt_internal_add_app call.
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH)
qt_internal_apply_staging_prefix_build_rpath_workaround()
_qt_internal_finalize_sbom(${target})
endfunction()

View File

@ -133,6 +133,10 @@ target_include_directories(GlobalConfigPrivate INTERFACE
)
add_library(Qt::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
add_library(${QT_CMAKE_EXPORT_NAMESPACE}::GlobalConfigPrivate ALIAS GlobalConfigPrivate)
qt_internal_add_sbom(GlobalConfigPrivate
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
qt_internal_setup_public_platform_target()

View File

@ -196,6 +196,7 @@ function(qt_internal_get_qt_build_private_helpers out_var)
QtResourceHelpers
QtRpathHelpers
QtSanitizerHelpers
QtSbomHelpers
QtScopeFinalizerHelpers
QtSeparateDebugInfo
QtSimdHelpers
@ -278,7 +279,10 @@ function(qt_internal_get_qt_build_public_helpers out_var)
QtPublicExternalProjectHelpers
QtPublicFinalizerHelpers
QtPublicFindPackageHelpers
QtPublicGitHelpers
QtPublicPluginHelpers
QtPublicSbomGenerationHelpers
QtPublicSbomHelpers
QtPublicTargetHelpers
QtPublicTestHelpers
QtPublicToolHelpers

View File

@ -193,6 +193,8 @@ macro(qt_internal_setup_configure_install_paths)
qt_configure_process_path(INSTALL_DESCRIPTIONSDIR
"${INSTALL_ARCHDATADIR}/modules"
"Module description files directory")
qt_configure_process_path(INSTALL_SBOMDIR "${INSTALL_ARCHDATADIR}/sbom"
"SBOM [PREFIX/sbom]")
endmacro()
macro(qt_internal_set_cmake_install_libdir)

View File

@ -308,6 +308,12 @@ macro(qt_build_repo_begin)
if(QT_INTERNAL_SYNCED_MODULES)
set_property(GLOBAL PROPERTY _qt_synced_modules ${QT_INTERNAL_SYNCED_MODULES})
endif()
_qt_internal_sbom_begin_project(
INSTALL_PREFIX "${QT_STAGING_PREFIX}"
INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}"
QT_CPE
)
endmacro()
# Runs delayed actions on some of the Qt targets.
@ -371,6 +377,8 @@ macro(qt_build_repo_end)
set(QT_INTERNAL_FRESH_REQUESTED "FALSE" CACHE INTERNAL "")
endif()
_qt_internal_sbom_end_project()
if(NOT QT_SUPERBUILD)
qt_internal_qt_configure_end()
endif()

View File

@ -138,6 +138,10 @@ function(qt_internal_add_executable name)
MOC_OPTIONS ${arg_MOC_OPTIONS}
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
ATTRIBUTION_ENTRY_INDEX "${arg_ATTRIBUTION_ENTRY_INDEX}"
ATTRIBUTION_FILE_PATHS ${arg_ATTRIBUTION_FILE_PATHS}
ATTRIBUTION_FILE_DIR_PATHS ${arg_ATTRIBUTION_FILE_DIR_PATHS}
SBOM_DEPENDENCIES ${arg_SBOM_DEPENDENCIES}
)
set_target_properties("${name}" PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"

View File

@ -233,8 +233,25 @@ macro(qt_find_package)
qt_find_package_promote_targets_to_global_scope(
"${qt_find_package_target_name}")
endif()
endif()
set(_qt_find_package_sbom_args "")
if(_qt_find_package_found_version)
list(APPEND _qt_find_package_sbom_args
PACKAGE_VERSION "${_qt_find_package_found_version}"
)
endif()
# Work around: QTBUG-125371
if(NOT "${ARGV0}" STREQUAL "Qt6")
_qt_internal_sbom_record_system_library_usage(
"${qt_find_package_target_name}"
TYPE SYSTEM_LIBRARY
FRIENDLY_PACKAGE_NAME "${ARGV0}"
${_qt_find_package_sbom_args}
)
endif()
endif()
endforeach()
if(arg_MODULE_NAME AND arg_QMAKE_LIB

View File

@ -138,22 +138,42 @@ endfunction()
add_library(PlatformCommonInternal INTERFACE)
qt_internal_add_target_aliases(PlatformCommonInternal)
target_link_libraries(PlatformCommonInternal INTERFACE Platform)
qt_internal_add_sbom(PlatformCommonInternal
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
add_library(PlatformModuleInternal INTERFACE)
qt_internal_add_target_aliases(PlatformModuleInternal)
target_link_libraries(PlatformModuleInternal INTERFACE PlatformCommonInternal)
qt_internal_add_sbom(PlatformModuleInternal
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
add_library(PlatformPluginInternal INTERFACE)
qt_internal_add_target_aliases(PlatformPluginInternal)
target_link_libraries(PlatformPluginInternal INTERFACE PlatformCommonInternal)
qt_internal_add_sbom(PlatformPluginInternal
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
add_library(PlatformAppInternal INTERFACE)
qt_internal_add_target_aliases(PlatformAppInternal)
target_link_libraries(PlatformAppInternal INTERFACE PlatformCommonInternal)
qt_internal_add_sbom(PlatformAppInternal
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
add_library(PlatformToolInternal INTERFACE)
qt_internal_add_target_aliases(PlatformToolInternal)
target_link_libraries(PlatformToolInternal INTERFACE PlatformAppInternal)
qt_internal_add_sbom(PlatformToolInternal
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
qt_internal_add_global_definition(QT_NO_JAVA_STYLE_ITERATORS)
qt_internal_add_global_definition(QT_NO_QASCONST)

View File

@ -33,6 +33,7 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
SSG_HEADER_FILTERS
HEADER_SYNC_SOURCE_DIRECTORY
${__default_target_info_args}
${__qt_internal_sbom_single_args}
)
set(${multi_args}
QMAKE_MODULE_CONFIG
@ -43,6 +44,7 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
${__default_private_args}
${__default_public_args}
${__default_private_module_args}
${__qt_internal_sbom_multi_args}
)
endmacro()
@ -235,6 +237,10 @@ function(qt_internal_add_module target)
set_target_properties(${target} PROPERTIES _qt_is_internal_module TRUE)
set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES _qt_is_internal_module)
endif()
if(arg_HEADER_MODULE)
set_target_properties(${target} PROPERTIES _qt_is_header_module TRUE)
set_property(TARGET ${target} APPEND PROPERTY EXPORT_PROPERTIES _qt_is_header_module)
endif()
if(NOT arg_CONFIG_MODULE_NAME)
set(arg_CONFIG_MODULE_NAME "${module_lower}")
@ -635,6 +641,10 @@ function(qt_internal_add_module target)
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
PRECOMPILED_HEADER ${arg_PRECOMPILED_HEADER}
NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
ATTRIBUTION_ENTRY_INDEX "${arg_ATTRIBUTION_ENTRY_INDEX}"
ATTRIBUTION_FILE_PATHS ${arg_ATTRIBUTION_FILE_PATHS}
ATTRIBUTION_FILE_DIR_PATHS ${arg_ATTRIBUTION_FILE_DIR_PATHS}
SBOM_DEPENDENCIES ${arg_SBOM_DEPENDENCIES}
)
# The public module define is not meant to be used when building the module itself,
@ -909,6 +919,43 @@ set(QT_ALLOW_MISSING_TOOLS_PACKAGES TRUE)")
endif()
qt_describe_module(${target})
set(sbom_args "")
if(QT_GENERATE_SBOM)
list(APPEND sbom_args TYPE QT_MODULE)
qt_get_cmake_configurations(configs)
foreach(config IN LISTS configs)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
RUNTIME_PATH
"${INSTALL_BINDIR}"
"${config}"
sbom_args
)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
LIBRARY_PATH
"${INSTALL_LIBDIR}"
"${config}"
sbom_args
)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
ARCHIVE_PATH
"${INSTALL_LIBDIR}"
"${config}"
sbom_args
)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
FRAMEWORK_PATH
"${INSTALL_LIBDIR}/${fw_versioned_binary_dir}"
"${config}"
sbom_args
)
endforeach()
_qt_internal_extend_sbom(${target} ${sbom_args})
endif()
qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${arg_NO_PRIVATE_MODULE})
endfunction()
@ -958,6 +1005,7 @@ function(qt_finalize_module target)
qt_generate_module_pri_file("${target}" ${ARGN})
qt_internal_generate_pkg_config_file(${target})
qt_internal_apply_apple_privacy_manifest(${target})
_qt_internal_finalize_sbom(${target})
endfunction()
# Get a set of Qt module related values based on the target.

View File

@ -72,6 +72,11 @@ function(qt_internal_setup_public_platform_target)
# Generate a pkgconfig for Qt::Platform.
qt_internal_generate_pkg_config_file(Platform)
qt_internal_add_sbom(Platform
TYPE QT_MODULE
IMMEDIATE_FINALIZATION
)
endfunction()
function(qt_internal_get_platform_definition_include_dir install_interface build_interface)

View File

@ -15,10 +15,12 @@ macro(qt_internal_get_internal_add_plugin_keywords option_args single_args multi
INSTALL_DIRECTORY
ARCHIVE_INSTALL_DIRECTORY
${__default_target_info_args}
${__qt_internal_sbom_single_args}
)
set(${multi_args}
${__default_private_args}
${__default_public_args}
${__qt_internal_sbom_multi_args}
DEFAULT_IF
)
endmacro()
@ -312,6 +314,10 @@ function(qt_internal_add_plugin target)
MOC_OPTIONS ${arg_MOC_OPTIONS}
ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS}
DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}
ATTRIBUTION_ENTRY_INDEX "${arg_ATTRIBUTION_ENTRY_INDEX}"
ATTRIBUTION_FILE_PATHS ${arg_ATTRIBUTION_FILE_PATHS}
ATTRIBUTION_FILE_DIR_PATHS ${arg_ATTRIBUTION_FILE_DIR_PATHS}
SBOM_DEPENDENCIES ${arg_SBOM_DEPENDENCIES}
)
qt_internal_add_repo_local_defines("${target}")
@ -414,6 +420,24 @@ function(qt_internal_add_plugin target)
if(NOT arg_SKIP_INSTALL)
list(APPEND finalizer_extra_args INSTALL_PATH "${install_directory}")
endif()
if(QT_GENERATE_SBOM)
set(sbom_args "")
list(APPEND sbom_args TYPE QT_PLUGIN)
qt_get_cmake_configurations(configs)
foreach(config IN LISTS configs)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
INSTALL_PATH
"${install_directory}"
"${config}"
sbom_args
)
endforeach()
_qt_internal_extend_sbom(${target} ${sbom_args})
endif()
qt_add_list_file_finalizer(qt_finalize_plugin ${target} ${finalizer_extra_args})
if(NOT arg_SKIP_INSTALL)
@ -442,6 +466,8 @@ function(qt_finalize_plugin target)
qt_generate_plugin_pri_file("${target}")
endif()
endif()
_qt_internal_finalize_sbom(${target})
endfunction()
function(qt_get_sanitized_plugin_type plugin_type out_var)

View File

@ -574,7 +574,7 @@ function(qt_generate_install_prefixes out_var)
set(vars INSTALL_BINDIR INSTALL_INCLUDEDIR INSTALL_LIBDIR INSTALL_MKSPECSDIR INSTALL_ARCHDATADIR
INSTALL_PLUGINSDIR INSTALL_LIBEXECDIR INSTALL_QMLDIR INSTALL_DATADIR INSTALL_DOCDIR
INSTALL_TRANSLATIONSDIR INSTALL_SYSCONFDIR INSTALL_EXAMPLESDIR INSTALL_TESTSDIR
INSTALL_DESCRIPTIONSDIR)
INSTALL_DESCRIPTIONSDIR INSTALL_SBOMDIR)
foreach(var ${vars})
get_property(docstring CACHE "${var}" PROPERTY HELPSTRING)

View File

@ -150,6 +150,8 @@ 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")
@ -261,6 +263,11 @@ defstub(set_package_properties)
defstub(qt_qml_find_python)
defstub(qt_set01)
defstub(qt_internal_check_if_linker_is_available)
defstub(qt_internal_add_sbom)
defstub(qt_internal_extend_sbom)
defstub(qt_internal_sbom_add_license)
defstub(qt_internal_extend_sbom_dependencies)
defstub(qt_find_package_extend_sbom)
####################################################################################################
# Define functions/macros that are called in qt_cmdline.cmake files
@ -934,6 +941,7 @@ endforeach()
translate_path_input(headerdir INSTALL_INCLUDEDIR)
translate_path_input(plugindir INSTALL_PLUGINSDIR)
translate_path_input(translationdir INSTALL_TRANSLATIONSDIR)
translate_path_input(sbomdir INSTALL_SBOMDIR)
if(NOT "${INPUT_device}" STREQUAL "")
push("-DQT_QMAKE_TARGET_MKSPEC=devices/${INPUT_device}")

View File

@ -434,6 +434,10 @@ function(_qt_internal_create_versionless_targets targets install_namespace)
_qt_package_name
_qt_package_version
_qt_private_module_target_name
_qt_sbom_spdx_id
_qt_sbom_spdx_repo_document_namespace
_qt_sbom_spdx_relative_installed_repo_document_path
_qt_sbom_spdx_repo_project_name_lowercase
)
set(supported_target_types STATIC_LIBRARY MODULE_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY

View File

@ -35,6 +35,37 @@ macro(_qt_internal_find_third_party_dependencies target target_dep_list)
else()
find_dependency(${__qt_${target}_find_package_args})
endif()
_qt_internal_get_package_components_id(
PACKAGE_NAME "${__qt_${target}_pkg}"
COMPONENTS ${__qt_${target}_components}
OPTIONAL_COMPONENTS ${__qt_${target}_optional_components}
OUT_VAR_KEY __qt_${target}_package_components_id
)
if(${__qt_${target}_pkg}_FOUND
AND __qt_${target}_third_party_package_${__qt_${target}_package_components_id}_provided_targets)
set(__qt_${target}_sbom_args "")
if(${__qt_${target}_pkg}_VERSION)
list(APPEND __qt_${target}_sbom_args
PACKAGE_VERSION "${${__qt_${target}_pkg}_VERSION}"
)
endif()
# Work around: QTBUG-125371
if(NOT "${ARGV0}" STREQUAL "Qt6")
foreach(__qt_${target}_provided_target
IN LISTS
__qt_${target}_third_party_package_${__qt_${target}_package_components_id}_provided_targets)
_qt_internal_sbom_record_system_library_usage(
"${__qt_${target}_provided_target}"
TYPE SYSTEM_LIBRARY
FRIENDLY_PACKAGE_NAME "${__qt_${target}_pkg}"
${__qt_${target}_sbom_args}
)
endforeach()
endif()
endif()
endforeach()
endmacro()

View File

@ -0,0 +1,153 @@
# Copyright (C) 2024 The Qt Company Ltd.
# Copyright (C) 2023-2024 Jochem Rutgers
# SPDX-License-Identifier: BSD-3-Clause AND MIT
macro(_qt_internal_find_git_package)
find_package(Git)
endmacro()
# Helper to set the various git version variables in the parent scope across multiple return points.
macro(_qt_internal_set_git_query_variables)
set("${arg_OUT_VAR_PREFIX}git_hash" "${version_git_hash}" PARENT_SCOPE)
set("${arg_OUT_VAR_PREFIX}git_hash_short" "${version_git_head}" PARENT_SCOPE)
set("${arg_OUT_VAR_PREFIX}git_version" "${git_version}" PARENT_SCOPE)
# git version sanitized for file paths.
string(REGEX REPLACE "[^-a-zA-Z0-9_.]+" "+" git_version_path "${git_version}")
set("${arg_OUT_VAR_PREFIX}git_version_path" "${git_version_path}" PARENT_SCOPE)
endmacro()
# Caches the results per working-directory in global cmake properties.
# Sets the following variables in the outer scope:
# - git_hash: Full git hash.
# - git_hash_short: Short git hash.
# - git_version: Git version string.
# - git_version_path: Git version string sanitized for file paths.
function(_qt_internal_query_git_version)
set(opt_args
EMPTY_VALUE_WHEN_NOT_GIT_REPO
)
set(single_args
WORKING_DIRECTORY
OUT_VAR_PREFIX
)
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_EMPTY_VALUE_WHEN_NOT_GIT_REPO)
set(version_git_head "")
set(version_git_hash "")
set(version_git_branch "")
set(version_git_tag "")
set(git_version "")
else()
set(version_git_head "unknown")
set(version_git_hash "")
set(version_git_branch "dev")
set(version_git_tag "")
set(git_version "${version_git_head}+${version_git_branch}")
endif()
if(NOT Git_FOUND)
message(STATUS "Git not found, skipping querying git version.")
_qt_internal_set_git_query_variables()
return()
endif()
if(arg_WORKING_DIRECTORY)
set(working_directory "${arg_WORKING_DIRECTORY}")
else()
set(working_directory "${PROJECT_SOURCE_DIR}")
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --is-inside-work-tree
WORKING_DIRECTORY "${working_directory}"
OUTPUT_VARIABLE is_inside_work_tree_output
RESULT_VARIABLE is_inside_work_tree_result
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
if((NOT is_inside_work_tree_result EQUAL 0) OR (NOT is_inside_work_tree_output STREQUAL "true"))
message(STATUS "Git repo not found, skipping querying git version.")
_qt_internal_set_git_query_variables()
return()
endif()
get_cmake_property(git_hash_cache _qt_git_hash_cache_${working_directory})
get_cmake_property(git_hash_short_cache _qt_git_hash_short_cache_${working_directory})
get_cmake_property(git_version_cache _qt_git_version_cache_${working_directory})
get_cmake_property(git_version_path_cache _qt_git_version_path_cache_${working_directory})
if(git_hash_cache)
set(git_hash "${git_hash_cache}")
set(git_hash_short "${git_hash_short_cache}")
set(git_version "${git_version_cache}")
set(git_version_path "${git_version_path_cache}")
_qt_internal_set_git_query_variables()
return()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY "${working_directory}"
OUTPUT_VARIABLE version_git_head
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
WORKING_DIRECTORY "${working_directory}"
OUTPUT_VARIABLE version_git_hash
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY "${working_directory}"
OUTPUT_VARIABLE version_git_branch
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${GIT_EXECUTABLE} tag --points-at HEAD
WORKING_DIRECTORY "${working_directory}"
OUTPUT_VARIABLE version_git_tag
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX REPLACE "[ \t\r\n].*$" "" version_git_tag "${version_git_tag}")
execute_process(
COMMAND ${GIT_EXECUTABLE} status -s
WORKING_DIRECTORY "${working_directory}"
OUTPUT_VARIABLE version_git_dirty
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT "${version_git_dirty}" STREQUAL "")
set(version_git_dirty "+dirty")
endif()
if(NOT "${version_git_tag}" STREQUAL "")
set(git_version "${version_git_tag}")
if("${git_version}" MATCHES "^v[0-9]+\.")
string(REGEX REPLACE "^v" "" git_version "${git_version}")
endif()
set(git_version "${git_version}${version_git_dirty}")
else()
set(git_version
"${version_git_head}+${version_git_branch}${version_git_dirty}"
)
endif()
set_property(GLOBAL PROPERTY _qt_git_hash_cache_${working_directory} "${git_hash}")
set_property(GLOBAL PROPERTY _qt_git_hash_short_cache_${working_directory} "${git_hash_short}")
set_property(GLOBAL PROPERTY _qt_git_version_cache_${working_directory} "${git_version}")
set_property(GLOBAL PROPERTY _qt_git_version_path_cache_${working_directory}
"${git_version_path}")
_qt_internal_set_git_query_variables()
endfunction()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

24
cmake/QtSbomHelpers.cmake Normal file
View File

@ -0,0 +1,24 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# For now these are simple internal forwarding wrappers for the public counterparts, which are
# meant to be used in qt repo CMakeLists.txt files.
function(qt_internal_add_sbom)
_qt_internal_add_sbom(${ARGN})
endfunction()
function(qt_internal_extend_sbom)
_qt_internal_extend_sbom(${ARGN})
endfunction()
function(qt_internal_sbom_add_license)
_qt_internal_sbom_add_license(${ARGN})
endfunction()
function(qt_internal_extend_sbom_dependencies)
_qt_internal_extend_sbom_dependencies(${ARGN})
endfunction()
function(qt_find_package_extend_sbom)
_qt_find_package_extend_sbom(${ARGN})
endfunction()

View File

@ -77,9 +77,17 @@ function(qt_watch_current_list_dir variable access value current_list_file stack
qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
elseif(func STREQUAL "qt_internal_finalize_app")
qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
elseif(func STREQUAL "qt_internal_finalize_tool")
qt_internal_finalize_tool(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
elseif(func STREQUAL "qt_internal_finalize_3rdparty_library")
qt_internal_finalize_3rdparty_library(
${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
elseif(func STREQUAL "qt_internal_export_additional_targets_file_finalizer")
qt_internal_export_additional_targets_file_finalizer(
${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
elseif(func STREQUAL "_qt_internal_finalize_sbom")
_qt_internal_finalize_sbom(
${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9})
else()
message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.")
endif()

View File

@ -45,6 +45,7 @@ function(qt_internal_extend_target target)
set(single_args
PRECOMPILED_HEADER
EXTRA_LINKER_SCRIPT_CONTENT
ATTRIBUTION_ENTRY_INDEX
)
set(multi_args
${__default_public_args}
@ -54,6 +55,9 @@ function(qt_internal_extend_target target)
CONDITION_INDEPENDENT_SOURCES
COMPILE_FLAGS
EXTRA_LINKER_SCRIPT_EXPORTS
SBOM_DEPENDENCIES
ATTRIBUTION_FILE_PATHS
ATTRIBUTION_FILE_DIR_PATHS
)
cmake_parse_arguments(PARSE_ARGV 1 arg
@ -210,6 +214,42 @@ function(qt_internal_extend_target target)
endif()
endforeach()
if(arg_LIBRARIES)
_qt_internal_append_to_target_property_without_duplicates(${target}
_qt_extend_target_libraries "${arg_LIBRARIES}"
)
endif()
if(arg_PUBLIC_LIBRARIES)
_qt_internal_append_to_target_property_without_duplicates(${target}
_qt_extend_target_public_libraries "${arg_PUBLIC_LIBRARIES}"
)
endif()
if(arg_SBOM_DEPENDENCIES)
_qt_internal_extend_sbom_dependencies(${target}
SBOM_DEPENDENCIES ${arg_SBOM_DEPENDENCIES}
)
endif()
if(NOT "${arg_ATTRIBUTION_ENTRY_INDEX}" STREQUAL "")
_qt_internal_extend_sbom(${target}
ATTRIBUTION_ENTRY_INDEX "${arg_ATTRIBUTION_ENTRY_INDEX}"
)
endif()
if(arg_ATTRIBUTION_FILE_PATHS)
_qt_internal_extend_sbom(${target}
ATTRIBUTION_FILE_PATHS ${arg_ATTRIBUTION_FILE_PATHS}
)
endif()
if(arg_ATTRIBUTION_FILE_DIR_PATHS)
_qt_internal_extend_sbom(${target}
ATTRIBUTION_FILE_DIR_PATHS ${arg_ATTRIBUTION_FILE_DIR_PATHS}
)
endif()
set(target_private "${target}Private")
get_target_property(is_internal_module ${target} _qt_is_internal_module)
# Internal modules don't have Private targets but we still need to
@ -298,7 +338,7 @@ endfunction()
function(qt_get_install_target_default_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
""
"OUT_VAR;CMAKE_CONFIG;RUNTIME;LIBRARY;ARCHIVE;INCLUDES;BUNDLE"
"OUT_VAR;OUT_VAR_RUNTIME;CMAKE_CONFIG;RUNTIME;LIBRARY;ARCHIVE;INCLUDES;BUNDLE"
"ALL_CMAKE_CONFIGS")
_qt_internal_validate_all_args_are_parsed(arg)
@ -348,6 +388,13 @@ function(qt_get_install_target_default_args)
BUNDLE DESTINATION "${bundle}${suffix}"
INCLUDES DESTINATION "${includes}${suffix}")
set(${arg_OUT_VAR} "${args}" PARENT_SCOPE)
if(arg_OUT_VAR_RUNTIME)
set(args
"${runtime}${suffix}"
)
set(${arg_OUT_VAR_RUNTIME} "${args}" PARENT_SCOPE)
endif()
endfunction()
macro(qt_internal_setup_default_target_function_options)
@ -391,6 +438,15 @@ macro(qt_internal_setup_default_target_function_options)
TARGET_COPYRIGHT
)
set(__qt_internal_sbom_single_args
ATTRIBUTION_ENTRY_INDEX
)
set(__qt_internal_sbom_multi_args
SBOM_DEPENDENCIES
ATTRIBUTION_FILE_PATHS
ATTRIBUTION_FILE_DIR_PATHS
)
# Collection of arguments so they can be shared across qt_internal_add_executable
# and qt_internal_add_test_helper.
set(__qt_internal_add_executable_optional_args
@ -408,10 +464,12 @@ macro(qt_internal_setup_default_target_function_options)
INSTALL_DIRECTORY
VERSION
${__default_target_info_args}
${__qt_internal_sbom_single_args}
)
set(__qt_internal_add_executable_multi_args
${__default_private_args}
${__default_public_args}
${__qt_internal_sbom_multi_args}
)
endmacro()

View File

@ -56,12 +56,16 @@ function(qt_internal_add_tool target_name)
INSTALL_DIR
CORE_LIBRARY
TRY_RUN_FLAGS
${__default_target_info_args})
${__default_target_info_args}
${__qt_internal_sbom_single_args}
)
set(multi_value_keywords
EXTRA_CMAKE_FILES
EXTRA_CMAKE_INCLUDES
PUBLIC_LIBRARIES
${__default_private_args})
${__default_private_args}
${__qt_internal_sbom_multi_args}
)
cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_keywords}"
@ -128,6 +132,10 @@ function(qt_internal_add_tool target_name)
LINK_OPTIONS ${arg_LINK_OPTIONS}
MOC_OPTIONS ${arg_MOC_OPTIONS}
DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools}
ATTRIBUTION_ENTRY_INDEX "${arg_ATTRIBUTION_ENTRY_INDEX}"
ATTRIBUTION_FILE_PATHS ${arg_ATTRIBUTION_FILE_PATHS}
ATTRIBUTION_FILE_DIR_PATHS ${arg_ATTRIBUTION_FILE_DIR_PATHS}
SBOM_DEPENDENCIES ${arg_SBOM_DEPENDENCIES}
TARGET_VERSION ${arg_TARGET_VERSION}
TARGET_PRODUCT ${arg_TARGET_PRODUCT}
TARGET_DESCRIPTION ${arg_TARGET_DESCRIPTION}
@ -186,8 +194,21 @@ function(qt_internal_add_tool target_name)
set_property(GLOBAL APPEND PROPERTY QT_USER_FACING_TOOL_TARGETS ${target_name})
endif()
if(QT_GENERATE_SBOM)
set(sbom_args "")
list(APPEND sbom_args TYPE QT_TOOL)
endif()
if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET)
set(will_install TRUE)
else()
set(will_install FALSE)
if(QT_GENERATE_SBOM)
list(APPEND sbom_args NO_INSTALL)
endif()
endif()
if(will_install)
# Assign a tool to an export set, and mark the module to which the tool belongs.
qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}")
@ -202,6 +223,7 @@ function(qt_internal_add_tool target_name)
foreach(cmake_config ${cmake_configs})
qt_get_install_target_default_args(
OUT_VAR install_targets_default_args
OUT_VAR_RUNTIME runtime_install_destination
RUNTIME "${install_dir}"
CMAKE_CONFIG "${cmake_config}"
ALL_CMAKE_CONFIGS ${cmake_configs})
@ -214,6 +236,15 @@ function(qt_internal_add_tool target_name)
unset(install_optional_arg)
endif()
if(QT_GENERATE_SBOM)
_qt_internal_sbom_append_multi_config_aware_single_arg_option(
RUNTIME_PATH
"${runtime_install_destination}"
"${cmake_config}"
sbom_args
)
endif()
qt_install(TARGETS "${target_name}"
${install_initial_call_args}
${install_optional_arg}
@ -240,6 +271,16 @@ function(qt_internal_add_tool target_name)
qt_enable_separate_debug_info(${target_name} "${install_dir}" QT_EXECUTABLE)
qt_internal_install_pdb_files(${target_name} "${install_dir}")
if(QT_GENERATE_SBOM)
_qt_internal_extend_sbom(${target_name} ${sbom_args})
endif()
qt_add_list_file_finalizer(qt_internal_finalize_tool ${target_name})
endfunction()
function(qt_internal_finalize_tool target)
_qt_internal_finalize_sbom(${target})
endfunction()
function(_qt_internal_add_try_run_post_build target try_run_flags)

View File

@ -45,6 +45,7 @@ The following table describes the mapping of configure options to CMake argument
| -device-option <key=value> | -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 |
| -qtinlinenamespace | -DQT_INLINE_NAMESPACE=ON | Make the namespace specified by -qtnamespace an inline one. |
| -qtnamespace <name> | -DQT_NAMESPACE=<name> | |
| -qtlibinfix <infix> | -DQT_LIBINFIX=<infix> | |

View File

@ -25,6 +25,8 @@ except -sysconfdir should be located under -prefix:
-libexecdir <dir> ..... Helper programs [ARCHDATADIR/bin on Windows,
ARCHDATADIR/libexec otherwise]
-qmldir <dir> ......... QML imports [ARCHDATADIR/qml]
-sbomdir <dir> ....... Software Bill of Materials (SBOM)
installation directory [ARCHDATADIR/sbom]
-datadir <dir> ........ Arch-independent data [PREFIX]
-docdir <dir> ......... Documentation [DATADIR/doc]
-translationdir <dir> . Translations [DATADIR/translations]
@ -99,6 +101,9 @@ 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]
-qt-host-path <path> . Specify path to a Qt host build for cross-compiling.
-qtnamespace <name> .. Wrap all Qt library code in 'namespace <name> {...}'.
-qtinlinenamespace ... Make -qtnamespace an inline namespace