Skip to content

Commit

Permalink
CMake: Support manual multiple projects within-a-repo SBOM generation
Browse files Browse the repository at this point in the history
Certain repositories like qtwebengine contain multiple projects from
the perspective of online installer packaging. In this case the
QtWebEngine and QtPdf projects are expected to have separate SBOM
documents.

Introduce a new QT_SKIP_SBOM_AUTO_PROJECT variable that can be set
before qt_build_repo to disable the auto-generation of an SBOM
document for the current repo project.

Introduce two new internal functions
qt_internal_sbom_begin/end_qt_repo_project to allow to manually start
and end the SBOM generation for a project within a repo.

Because the intermediate file names that assemble the SBOM use the
project name as a key, and the project name would be the same for
qtwebengine, allow differentiating between the current project name
and the real qt repo project name.

The current project name is used for the file names, whereas the
real qt repo project name is used to extract the dependencies on
other repos, to ensure correct dependency build rules.

As a drive-by, improve the document dir path search list when an SBOM
document can't be found.

Pick-to: 6.8
Task-number: QTBUG-128893
Task-number: QTBUG-122899
Change-Id: I61b68098242e7c49b98420265c29af78303c3233
Reviewed-by: Joerg Bornemann <[email protected]>
  • Loading branch information
alcroito committed Dec 5, 2024
1 parent ffef516 commit 43e166b
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 10 deletions.
7 changes: 2 additions & 5 deletions cmake/QtBuildRepoHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,7 @@ macro(qt_build_repo_begin)
set_property(GLOBAL PROPERTY _qt_synced_modules ${QT_INTERNAL_SYNCED_MODULES})
endif()

_qt_internal_sbom_begin_project(
INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}"
QT_CPE
)
_qt_internal_sbom_auto_begin_qt_repo_project()
endmacro()

# Runs delayed actions on some of the Qt targets.
Expand Down Expand Up @@ -419,7 +416,7 @@ macro(qt_build_repo_end)
set(QT_INTERNAL_FRESH_REQUESTED "FALSE" CACHE INTERNAL "")
endif()

_qt_internal_sbom_end_project()
_qt_internal_sbom_auto_end_qt_repo_project()

if(NOT QT_SUPERBUILD)
qt_internal_qt_configure_end()
Expand Down
24 changes: 21 additions & 3 deletions cmake/QtPublicSbomGenerationHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,25 @@ function(qt_internal_sbom_set_default_option_value_and_error_if_empty option_nam
endif()
endfunction()

# Helper that returns the relative sbom build dir.
# To accommodate multiple projects within a qt repo (like qtwebengine), we need to choose separate
# build dirs for each project.
function(_qt_internal_get_current_project_sbom_relative_dir out_var)
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
_qt_internal_sbom_get_qt_repo_project_name_lower_case(real_qt_repo_project_name_lowercase)

if(repo_project_name_lowercase STREQUAL real_qt_repo_project_name_lowercase)
set(sbom_dir "qt_sbom")
else()
set(sbom_dir "qt_sbom/${repo_project_name_lowercase}")
endif()
set(${out_var} "${sbom_dir}" PARENT_SCOPE)
endfunction()

# Helper that returns the directory where the intermediate sbom files will be generated.
function(_qt_internal_get_current_project_sbom_dir out_var)
set(sbom_dir "${PROJECT_BINARY_DIR}/qt_sbom")
_qt_internal_get_current_project_sbom_relative_dir(relative_dir)
set(sbom_dir "${PROJECT_BINARY_DIR}/${relative_dir}")
set(${out_var} "${sbom_dir}" PARENT_SCOPE)
endfunction()

Expand Down Expand Up @@ -414,6 +430,7 @@ function(_qt_internal_sbom_end_project_generate)
endif()

_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
_qt_internal_sbom_get_qt_repo_project_name_lower_case(real_qt_repo_project_name_lowercase)

# Create a build target to create a build-time sbom (no verification codes or sha1s).
set(repo_sbom_target "sbom_${repo_project_name_lowercase}")
Expand All @@ -427,7 +444,7 @@ function(_qt_internal_sbom_end_project_generate)
USES_TERMINAL # To avoid running two configs of the command in parallel
)

get_cmake_property(qt_repo_deps _qt_repo_deps_${repo_project_name_lowercase})
get_cmake_property(qt_repo_deps _qt_repo_deps_${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}")
Expand Down Expand Up @@ -767,6 +784,7 @@ function(_qt_internal_sbom_generate_add_external_reference)
set(content "
set(relative_file_name \"${arg_FILENAME}\")
set(document_dir_paths ${install_prefixes})
list(JOIN document_dir_paths \"\\n\" document_dir_paths_per_line)
foreach(document_dir_path IN LISTS document_dir_paths)
set(document_file_path \"\${document_dir_path}/\${relative_file_name}\")
if(EXISTS \"\${document_file_path}\")
Expand All @@ -775,7 +793,7 @@ function(_qt_internal_sbom_generate_add_external_reference)
endforeach()
if(NOT EXISTS \"\${document_file_path}\")
message(FATAL_ERROR \"Could not find external SBOM document \${relative_file_name}\"
\" in any of the document dir paths: \${document_dir_paths} \"
\" in any of the document dir paths: \${document_dir_paths_per_line} \"
)
endif()
file(SHA1 \"\${document_file_path}\" ext_sha1)
Expand Down
100 changes: 98 additions & 2 deletions cmake/QtPublicSbomHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function(_qt_internal_sbom_begin_project)
DOCUMENT_NAMESPACE
VERSION
SBOM_PROJECT_NAME
QT_REPO_PROJECT_NAME
CPE
)
set(multi_args
Expand Down Expand Up @@ -69,6 +70,13 @@ function(_qt_internal_sbom_begin_project)
else()
_qt_internal_sbom_set_root_project_name("${PROJECT_NAME}")
endif()

if(arg_QT_REPO_PROJECT_NAME)
_qt_internal_sbom_set_qt_repo_project_name("${arg_QT_REPO_PROJECT_NAME}")
else()
_qt_internal_sbom_set_qt_repo_project_name("${PROJECT_NAME}")
endif()

_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)

Expand Down Expand Up @@ -376,6 +384,75 @@ function(_qt_internal_sbom_end_project)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${attribution_files}")
endfunction()

# Automatically begins sbom generation for a qt git repo unless QT_SKIP_SBOM_AUTO_PROJECT is TRUE.
function(_qt_internal_sbom_auto_begin_qt_repo_project)
# Allow skipping auto generation of sbom project, in case it needs to be manually adjusted with
# extra parameters.
if(QT_SKIP_SBOM_AUTO_PROJECT)
return()
endif()

_qt_internal_sbom_begin_qt_repo_project()
endfunction()

# Sets up sbom generation for a qt git repo or qt-git-repo-sub-project (e.g. qtpdf in qtwebengine).
#
# In the case of a qt-git-repo-sub-project, the function expects the following options:
# - SBOM_PROJECT_NAME (e.g. QtPdf)
# - QT_REPO_PROJECT_NAME (e.g. QtWebEngine)
#
# Expects the following variables to always be set before the function call:
# - QT_STAGING_PREFIX
# - INSTALL_SBOMDIR
function(_qt_internal_sbom_begin_qt_repo_project)
set(opt_args "")
set(single_args
SBOM_PROJECT_NAME
QT_REPO_PROJECT_NAME
)
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(sbom_project_args "")

_qt_internal_forward_function_args(
FORWARD_APPEND
FORWARD_PREFIX arg
FORWARD_OUT_VAR sbom_project_args
FORWARD_OPTIONS
${opt_args}
FORWARD_SINGLE
${single_args}
FORWARD_MULTI
${multi_args}
)

_qt_internal_sbom_begin_project(
INSTALL_SBOM_DIR "${INSTALL_SBOMDIR}"
QT_CPE
${sbom_project_args}
)
endfunction()

# Automatically ends sbom generation for a qt git repo unless QT_SKIP_SBOM_AUTO_PROJECT is TRUE.
function(_qt_internal_sbom_auto_end_qt_repo_project)
# Allow skipping auto generation of sbom project, in case it needs to be manually adjusted with
# extra parameters.
if(QT_SKIP_SBOM_AUTO_PROJECT)
return()
endif()

_qt_internal_sbom_end_qt_repo_project()
endfunction()

# Endssbom generation for a qt git repo or qt-git-repo-sub-project.

function(_qt_internal_sbom_end_qt_repo_project)
_qt_internal_sbom_end_project()
endfunction()

# Helper to get purl parsing options.
macro(_qt_internal_get_sbom_purl_parsing_options opt_args single_args multi_args)
set(${opt_args}
Expand Down Expand Up @@ -2608,19 +2685,25 @@ macro(_qt_internal_sbom_get_attribution_key json_key out_var out_prefix)
endif()
endmacro()

# Set sbom project name for the root project.
# Sets the sbom project name for the root project.
function(_qt_internal_sbom_set_root_project_name project_name)
set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_project_name "${project_name}")
endfunction()

# Sets the real qt repo project name for a given project (e.g. set QtWebEngine for project QtPdf).
# This is needed to be able to extract the qt repo dependencies in a top-level build.
function(_qt_internal_sbom_set_qt_repo_project_name project_name)
set_property(GLOBAL PROPERTY _qt_internal_sbom_qt_repo_project_name "${project_name}")
endfunction()

# Get repo project_name spdx id reference, needs to start with Package- to be NTIA compliant.
function(_qt_internal_sbom_get_root_project_name_for_spdx_id out_var)
_qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase)
set(sbom_repo_project_name "Package-${repo_project_name_lowercase}")
set(${out_var} "${sbom_repo_project_name}" PARENT_SCOPE)
endfunction()

# Just a lower case sbom project name.
# Returns the lower case sbom project name.
function(_qt_internal_sbom_get_root_project_name_lower_case out_var)
get_cmake_property(project_name _qt_internal_sbom_repo_project_name)

Expand All @@ -2632,6 +2715,19 @@ function(_qt_internal_sbom_get_root_project_name_lower_case out_var)
set(${out_var} "${repo_project_name_lowercase}" PARENT_SCOPE)
endfunction()

# Returns the lower case real qt repo project name (e.g. returns 'qtwebengine' when building the
# project qtpdf).
function(_qt_internal_sbom_get_qt_repo_project_name_lower_case out_var)
get_cmake_property(project_name _qt_internal_sbom_qt_repo_project_name)

if(NOT project_name)
message(FATAL_ERROR "No real Qt repo SBOM project name was set.")
endif()

string(TOLOWER "${project_name}" repo_project_name_lowercase)
set(${out_var} "${repo_project_name_lowercase}" PARENT_SCOPE)
endfunction()

# Get a spdx id to reference an external document.
function(_qt_internal_sbom_get_external_document_ref_spdx_id repo_name out_var)
set(${out_var} "DocumentRef-${repo_name}" PARENT_SCOPE)
Expand Down
9 changes: 9 additions & 0 deletions cmake/QtSbomHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,12 @@ endfunction()
function(qt_find_package_extend_sbom)
_qt_find_package_extend_sbom(${ARGN})
endfunction()

function(qt_internal_sbom_begin_qt_repo_project)
_qt_internal_sbom_begin_qt_repo_project(${ARGN})
endfunction()

function(qt_internal_sbom_end_qt_repo_project)
_qt_internal_sbom_end_qt_repo_project(${ARGN})
endfunction()

0 comments on commit 43e166b

Please sign in to comment.