blob: 32e3b6b832ce3f893d4e1e6e6108a7934b365359 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Walks a target's direct dependencies and assembles a list of relationships between the packages
# of the target dependencies.
# Currently handles various Qt targets and system libraries.
function(_qt_internal_sbom_handle_target_dependencies target)
set(opt_args "")
set(single_args
SPDX_ID
OUT_RELATIONSHIPS
)
set(multi_args
LIBRARIES
PUBLIC_LIBRARIES
)
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 "SPDX_ID must be set")
endif()
set(package_spdx_id "${arg_SPDX_ID}")
set(libraries "")
if(arg_LIBRARIES)
list(APPEND libraries "${arg_LIBRARIES}")
endif()
get_target_property(extend_libraries "${target}" _qt_extend_target_libraries)
if(extend_libraries)
list(APPEND libraries ${extend_libraries})
endif()
get_target_property(target_type ${target} TYPE)
set(valid_target_types
EXECUTABLE
SHARED_LIBRARY
MODULE_LIBRARY
STATIC_LIBRARY
OBJECT_LIBRARY
)
if(target_type IN_LIST valid_target_types)
get_target_property(link_libraries "${target}" LINK_LIBRARIES)
if(link_libraries)
list(APPEND libraries ${link_libraries})
endif()
endif()
set(public_libraries "")
if(arg_PUBLIC_LIBRARIES)
list(APPEND public_libraries "${arg_PUBLIC_LIBRARIES}")
endif()
get_target_property(extend_public_libraries "${target}" _qt_extend_target_public_libraries)
if(extend_public_libraries)
list(APPEND public_libraries ${extend_public_libraries})
endif()
set(sbom_dependencies "")
if(arg_SBOM_DEPENDENCIES)
list(APPEND sbom_dependencies "${arg_SBOM_DEPENDENCIES}")
endif()
get_target_property(extend_sbom_dependencies "${target}" _qt_extend_target_sbom_dependencies)
if(extend_sbom_dependencies)
list(APPEND sbom_dependencies ${extend_sbom_dependencies})
endif()
list(REMOVE_DUPLICATES libraries)
list(REMOVE_DUPLICATES public_libraries)
list(REMOVE_DUPLICATES sbom_dependencies)
set(all_direct_libraries ${libraries} ${public_libraries} ${sbom_dependencies})
list(REMOVE_DUPLICATES all_direct_libraries)
set(spdx_dependencies "")
set(external_spdx_dependencies "")
# Go through each direct linked lib.
foreach(direct_lib IN LISTS all_direct_libraries)
if(NOT TARGET "${direct_lib}")
continue()
endif()
# Check for Qt-specific system library targets. These are marked via qt_find_package calls.
get_target_property(is_system_library "${direct_lib}" _qt_internal_sbom_is_system_library)
if(is_system_library)
# We need to check if the dependency is a FindWrap dependency that points either to a
# system library or a vendored / bundled library. We need to depend on whichever one
# the FindWrap script points to.
__qt_internal_walk_libs(
"${direct_lib}"
lib_walked_targets
_discarded_out_var
"sbom_targets"
"collect_targets")
# Detect if we are dealing with a vendored / bundled lib.
set(bundled_targets_found FALSE)
if(lib_walked_targets)
foreach(lib_walked_target IN LISTS lib_walked_targets)
get_target_property(is_3rdparty_bundled_lib
"${lib_walked_target}" _qt_module_is_3rdparty_library)
_qt_internal_sbom_get_spdx_id_for_target("${lib_walked_target}" lib_spdx_id)
# Add a dependency on the vendored lib instead of the Wrap target.
if(is_3rdparty_bundled_lib AND lib_spdx_id)
list(APPEND spdx_dependencies "${lib_spdx_id}")
set(bundled_targets_found TRUE)
endif()
endforeach()
if(bundled_targets_found)
# If we handled a bundled target, we can move on to process the next direct_lib.
continue()
endif()
endif()
if(NOT bundled_targets_found)
# If we haven't found a bundled target, then it's a regular system library
# dependency. Make sure to mark the system library as consumed, so that we later
# generate an sbom for it.
# Also fall through to the code that actually adds the dependency on the target.
_qt_internal_append_to_cmake_property_without_duplicates(
_qt_internal_sbom_consumed_system_library_targets
"${direct_lib}"
)
endif()
endif()
# Get the spdx id of the dependency.
_qt_internal_sbom_get_spdx_id_for_target("${direct_lib}" lib_spdx_id)
if(NOT lib_spdx_id)
message(DEBUG "Could not add target dependency on target ${direct_lib} "
"because no spdx id for it could be found.")
continue()
endif()
# Check if the target sbom is defined in an external document.
_qt_internal_sbom_is_external_target_dependency("${direct_lib}"
OUT_VAR is_dependency_in_external_document
)
if(NOT is_dependency_in_external_document)
# If the target is not in the external document, it must be one built as part of the
# current project.
list(APPEND spdx_dependencies "${lib_spdx_id}")
else()
# Refer to the package in the external document. This can be the case
# in a top-level build, where a system library is reused across repos, or for any
# regular dependency that was built as part of a different project.
_qt_internal_sbom_add_external_target_dependency("${direct_lib}"
extra_spdx_dependencies
)
if(extra_spdx_dependencies)
list(APPEND external_spdx_dependencies ${extra_spdx_dependencies})
endif()
endif()
endforeach()
set(relationships "")
# Keep the external dependencies first, so they are neatly ordered.
foreach(dep_spdx_id IN LISTS external_spdx_dependencies spdx_dependencies)
set(relationship
"${package_spdx_id} DEPENDS_ON ${dep_spdx_id}"
)
list(APPEND relationships "${relationship}")
endforeach()
set(${arg_OUT_RELATIONSHIPS} "${relationships}" PARENT_SCOPE)
endfunction()
# Checks whether the current target will have its sbom generated into the current repo sbom
# document, or whether it is present in an external sbom document.
function(_qt_internal_sbom_is_external_target_dependency target)
set(opt_args
SYSTEM_LIBRARY
)
set(single_args
OUT_VAR
)
set(multi_args "")
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
_qt_internal_validate_all_args_are_parsed(arg)
get_target_property(is_imported "${target}" IMPORTED)
get_target_property(is_custom_sbom_target "${target}" _qt_sbom_is_custom_sbom_target)
_qt_internal_sbom_get_root_project_name_lower_case(current_repo_project_name)
get_property(target_repo_project_name TARGET ${target}
PROPERTY _qt_sbom_spdx_repo_project_name_lowercase)
if(NOT "${target_repo_project_name}" STREQUAL ""
AND NOT "${target_repo_project_name}" STREQUAL "${current_repo_project_name}")
set(part_of_other_repo TRUE)
else()
set(part_of_other_repo FALSE)
endif()
set(${arg_OUT_VAR} "${part_of_other_repo}" PARENT_SCOPE)
endfunction()
# Handles generating an external document reference SDPX element for each target package that is
# located in a different spdx document.
function(_qt_internal_sbom_add_external_target_dependency target out_spdx_dependencies)
_qt_internal_sbom_get_spdx_id_for_target("${target}" dep_spdx_id)
if(NOT dep_spdx_id)
message(DEBUG "Could not add external target dependency on ${target} "
"because no spdx id could be found")
set(${out_spdx_dependencies} "" PARENT_SCOPE)
return()
endif()
set(spdx_dependencies "")
# Get the external document path and the repo it belongs to for the given target.
get_property(relative_installed_repo_document_path TARGET ${target}
PROPERTY _qt_sbom_spdx_relative_installed_repo_document_path)
get_property(project_name_lowercase TARGET ${target}
PROPERTY _qt_sbom_spdx_repo_project_name_lowercase)
if(relative_installed_repo_document_path AND project_name_lowercase)
_qt_internal_sbom_get_external_document_ref_spdx_id(
"${project_name_lowercase}" external_document_ref)
get_cmake_property(known_external_document
_qt_known_external_documents_${external_document_ref})
set(dependency "${external_document_ref}:${dep_spdx_id}")
list(APPEND spdx_dependencies "${dependency}")
# Only add a reference to the external document package, if we haven't done so already.
if(NOT known_external_document)
set(install_prefixes "")
get_cmake_property(install_prefix _qt_internal_sbom_install_prefix)
list(APPEND install_prefixes "${install_prefix}")
set(external_document "${relative_installed_repo_document_path}")
_qt_internal_sbom_generate_add_external_reference(
EXTERNAL_DOCUMENT_FILE_PATH "${external_document}"
EXTERNAL_DOCUMENT_INSTALL_PREFIXES ${install_prefixes}
EXTERNAL_DOCUMENT_SPDX_ID "${external_document_ref}"
)
set_property(GLOBAL PROPERTY
_qt_known_external_documents_${external_document_ref} TRUE)
set_property(GLOBAL APPEND PROPERTY
_qt_known_external_documents "${external_document_ref}")
endif()
else()
message(AUTHOR_WARNING
"Missing spdx document path for external target dependency: ${target}")
endif()
set(${out_spdx_dependencies} "${spdx_dependencies}" PARENT_SCOPE)
endfunction()
|