forked from nrfconnect/sdk-nrf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextensions.cmake
478 lines (421 loc) · 16.9 KB
/
extensions.cmake
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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
#
# Copyright (c) 2020 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
#
# Helper macro for verifying that at least one of the required arguments has
# been provided by the caller.
#
# As FATAL_ERROR will be raised if not one of the required arguments has been
# passed by the caller.
#
# Usage:
# check_arguments_required(<function_name> <prefix> <arg1> [<arg2> ...])
#
macro(check_arguments_required function prefix)
set(required_found FALSE)
foreach(required ${ARGN})
if(DEFINED ${prefix}_${required})
set(required_found TRUE)
endif()
endforeach()
if(NOT required_found)
message(FATAL_ERROR "${function}(...) missing a required argument: ${ARGN}")
endif()
endmacro()
#
# Helper macro for verifying that all the required arguments has # been
# provided by the caller.
#
# As FATAL_ERROR will be raised if one of the required arguments is missing.
#
# Usage:
# check_arguments_required_all(<function_name> <prefix> <arg1> [<arg2> ...])
#
macro(check_arguments_required_all function prefix)
foreach(required ${ARGN})
if(NOT DEFINED ${prefix}_${required})
message(FATAL_ERROR "${function}(...) missing a required argument: ${required}")
endif()
endforeach()
endmacro()
#
# Helper macro for verifying that none of the mutual exclusive arguments are
# provided together with the first argument.
#
# As FATAL_ERROR will be raised if first argument is given together with one
# of the following mutual exclusive arguments.
#
# Usage:
# check_arguments_exclusive(<function_name> <prefix> <arg1> <exlude-arg1> [<exclude-arg2> ...])
#
macro(check_arguments_exclusive function prefix argument)
foreach(prohibited ${ARGN})
if(DEFINED ${prefix}_${argument} AND ${prefix}_${prohibited})
message(FATAL_ERROR "set_shared(${argument} ...) cannot be used with "
"argument: ${prohibited}"
)
endif()
endforeach()
endmacro()
function(get_board_without_ns_suffix board_in board_out)
string(REGEX REPLACE "((_|/)?ns)$" "" board_in_without_suffix ${board_in})
if(NOT "${board_in}" STREQUAL "${board_in_without_suffix}")
if (NOT CONFIG_ARM_NONSECURE_FIRMWARE)
message(FATAL_ERROR "${board_in} is not a valid name for a board without "
"'CONFIG_ARM_NONSECURE_FIRMWARE' set. This because the 'ns'/'_ns' ending "
"indicates that the board is the non-secure variant in a TrustZone "
"enabled system.")
endif()
set(${board_out} ${board_in_without_suffix} PARENT_SCOPE)
message("Changed board to secure ${board_in_without_suffix} (NOT NS)")
else()
set(${board_out} ${board_in} PARENT_SCOPE)
endif()
endfunction()
# Add an overlay file to a child image.
# This can be used by a parent image to set overlay of Kconfig configuration or devicetree
# in its child images. This function must be called before 'add_child_image(image)'
# to have effect.
#
# Parameters:
# 'image' - child image name
# 'overlay_file' - overlay to be added to child image
# 'overlay_type' - 'OVERLAY_CONFIG' or 'DTC_OVERLAY_FILE'
function(add_overlay image overlay_file overlay_type)
set(old_overlays ${${image}_${overlay_type}})
string(FIND "${old_overlays}" "${overlay_file}" found)
if (${found} EQUAL -1)
set(${image}_${overlay_type} "${old_overlays};${overlay_file}" CACHE STRING
"Extra config fragments for ${image} child image" FORCE
)
endif()
endfunction()
# Convenience macro to add configuration overlays to child image.
macro(add_overlay_config image overlay_file)
add_overlay(${image} ${overlay_file} EXTRA_CONF_FILE)
endmacro()
# Convenience macro to add device tree overlays to child image.
macro(add_overlay_dts image overlay_file)
add_overlay(${image} ${overlay_file} EXTRA_DTC_OVERLAY_FILE)
endmacro()
# Add a partition manager configuration file to the build.
# Note that is only one image is included in the build,
# you must set CONFIG_PM_SINGLE_IMAGE=y for the partition manager
# configuration to take effect.
function(ncs_add_partition_manager_config config_file)
get_filename_component(pm_path ${config_file} REALPATH)
get_filename_component(pm_filename ${config_file} NAME)
if (NOT EXISTS ${pm_path})
message(FATAL_ERROR
"Could not find specified partition manager configuration file "
"${config_file} at ${pm_path}"
)
endif()
set_property(GLOBAL APPEND PROPERTY
PM_SUBSYS_PATHS
${pm_path}
)
set_property(GLOBAL APPEND PROPERTY
PM_SUBSYS_OUTPUT_PATHS
${CMAKE_CURRENT_BINARY_DIR}/${pm_filename}
)
endfunction()
# Usage:
# ncs_file(<mode> <arg> ...)
#
# NCS file function extension.
# This function extends the zephyr_file(CONF_FILES <arg>) function to support
# switching BOARD for child images.
#
# It also supports lookup of static partition manager files for based on
# the board name, revision, and the current build type.
# The order at which files are considers is from the most specific to the least specific:
# - first, file name with board name, board revision and build type identifiers,
# - second, file name with board name and build type identifiers,
# - third, file with only build type identifier,
# - finally, the file with no identifiers is looked up.
# During each pass, if domain is defined, the file with additional domain identifier has precedence.
#
# This function currently support the following <modes>.
#
# BOARD <board>: Board name to use when searching for board specific Kconfig
# fragments.
#
# CONF_FILES <path>: Find all configuration files in path and return them in a
# list. Configuration files will be:
# - DTS: Overlay files (.overlay)
# - Kconfig: Config fragments (.conf)
# The conf file search will return existing configuration
# files for BOARD or the current board if BOARD argument is
# not given.
# CONF_FILES takes the following additional arguments:
# BOARD <board>: Find configuration files for specified board.
# BOARD_REVISION <revision>: Find configuration files for specified board
# revision. Requires BOARD to be specified.
#
# If no board is given the current BOARD and
# BOARD_REVISION will be used.
#
# DTS <list>: List to populate with DTS overlay files
# KCONF <list>: List to populate with Kconfig fragment files
# PM <list>: List to populate with board / build / domain specific
# static partition manager files
# BUILD <type>: Build type to include for search.
# For example:
# BUILD debug, will look for <board>_debug.conf
# and <board>_debug.overlay, instead of <board>.conf
# DOMAIN <domain>: Domain to use. This argument is only effective
# for partition manager configuration files.
#
function(ncs_file)
set(file_options CONF_FILES)
if((ARGC EQUAL 0) OR (NOT (ARGV0 IN_LIST file_options)))
message(FATAL_ERROR "No <mode> given to `ncs_file(<mode> <args>...)` function,\n \
Please provide one of following: CONF_FILES")
endif()
set(single_args CONF_FILES PM DOMAIN)
set(zephyr_conf_single_args BOARD BOARD_REVISION BUILD DTS KCONF SUFFIX)
cmake_parse_arguments(PREPROCESS_ARGS "" "${single_args};${zephyr_conf_single_args}" "" ${ARGN})
# Remove any argument that is missing value to ensure proper behavior in situations like:
# ncs_file(CONF_FILES <path> PM <list> DOMAIN BUILD <type>)
# where value of DOMAIN could wrongly become BUILD which is another keyword.
if(DEFINED PREPROCESS_ARGS_KEYWORDS_MISSING_VALUES)
list(REMOVE_ITEM ARGN ${PREPROCESS_ARGS_KEYWORDS_MISSING_VALUES})
endif()
cmake_parse_arguments(NCS_FILE "" "${single_args};BOARD" "" ${ARGN})
cmake_parse_arguments(ZEPHYR_FILE "" "${zephyr_conf_single_args}" "" ${ARGN})
if(ZEPHYR_FILE_KCONF)
if(ZEPHYR_FILE_SUFFIX AND EXISTS ${NCS_FILE_CONF_FILES}/prj_${ZEPHYR_FILE_SUFFIX}.conf)
set(${ZEPHYR_FILE_KCONF} ${NCS_FILE_CONF_FILES}/prj_${ZEPHYR_FILE_SUFFIX}.conf)
elseif(ZEPHYR_FILE_BUILD AND EXISTS ${NCS_FILE_CONF_FILES}/prj_${ZEPHYR_FILE_BUILD}.conf)
set(${ZEPHYR_FILE_KCONF} ${NCS_FILE_CONF_FILES}/prj_${ZEPHYR_FILE_BUILD}.conf)
elseif(NOT ZEPHYR_FILE_BUILD AND EXISTS ${NCS_FILE_CONF_FILES}/prj.conf)
set(${ZEPHYR_FILE_KCONF} ${NCS_FILE_CONF_FILES}/prj.conf)
endif()
endif()
set(additional_append)
if(DEFINED PREPROCESS_ARGS_BOARD)
parse_board_components(PREPROCESS_ARGS_BOARD board_name board_revision board_qualifiers)
set(additional_append BOARD ${board_name} BOARD_REVISION ${board_revision} BOARD_QUALIFIERS ${board_qualifiers})
endif()
zephyr_file(CONF_FILES ${NCS_FILE_CONF_FILES}/boards ${additional_append} ${NCS_FILE_UNPARSED_ARGUMENTS})
if(ZEPHYR_FILE_KCONF)
set(${ZEPHYR_FILE_KCONF} ${${ZEPHYR_FILE_KCONF}} PARENT_SCOPE)
endif()
if(ZEPHYR_FILE_DTS)
set(${ZEPHYR_FILE_DTS} ${${ZEPHYR_FILE_DTS}} PARENT_SCOPE)
endif()
if(NOT DEFINED PREPROCESS_ARGS_BOARD)
# Defaulting to system wide settings when BOARD is not given as argument
set(board_combined ${BOARD})
if(DEFINED BOARD_REVISION)
set(board_combined ${board_combined}@${BOARD_REVISION})
endif()
set(board_combined ${board_combined}${BOARD_QUALIFIERS})
parse_board_components(board_combined board_name board_revision board_qualifiers)
endif()
if(NCS_FILE_PM)
set(PM_FILE_PREFIX pm_static)
if(DEFINED FILE_SUFFIX)
# Prepare search for pm_static_board@ver_suffix.yml
zephyr_build_string(filename
BOARD ${board_name}
BOARD_REVISION ${board_revision}
BOARD_QUALIFIERS ${board_qualifiers}
)
set(filename_list ${PM_FILE_PREFIX}_${filename})
# Prepare search for pm_static_board_suffix.yml
zephyr_build_string(filename
BOARD ${board_name}
BOARD_QUALIFIERS ${board_qualifiers}
)
list(APPEND filename_list ${PM_FILE_PREFIX}_${filename})
list(APPEND filename_list ${PM_FILE_PREFIX})
else()
# Prepare search for pm_static_board@ver_build.yml
zephyr_build_string(filename
BOARD ${board_name}
BOARD_REVISION ${board_revision}
BOARD_QUALIFIERS ${board_qualifiers}
BUILD ${ZEPHYR_FILE_BUILD}
)
set(filename_list ${PM_FILE_PREFIX}_${filename})
# Prepare search for pm_static_board_build.yml
zephyr_build_string(filename
BOARD ${board_name}
BOARD_QUALIFIERS ${board_qualifiers}
BUILD ${ZEPHYR_FILE_BUILD}
)
list(APPEND filename_list ${PM_FILE_PREFIX}_${filename})
if(DEFINED ZEPHYR_FILE_BUILD)
# Prepare search for pm_static_build.yml
# Note that BOARD argument is used to position suffix accordingly
zephyr_build_string(filename
BOARD ${ZEPHYR_FILE_BUILD}
)
list(APPEND filename_list ${PM_FILE_PREFIX}_${filename})
endif()
# Prepare search for pm_static.yml
list(APPEND filename_list ${PM_FILE_PREFIX})
endif()
list(REMOVE_DUPLICATES filename_list)
foreach(filename ${filename_list})
if(DEFINED NCS_FILE_DOMAIN)
if(DEFINED FILE_SUFFIX)
set(filename_check ${NCS_FILE_CONF_FILES}/${filename}_${NCS_FILE_DOMAIN}.yml)
zephyr_file_suffix(filename_check SUFFIX ${FILE_SUFFIX})
if(EXISTS ${filename_check})
set(${NCS_FILE_PM} ${filename_check} PARENT_SCOPE)
break()
endif()
else()
if(EXISTS ${NCS_FILE_CONF_FILES}/${filename}_${NCS_FILE_DOMAIN}.yml)
set(${NCS_FILE_PM} ${NCS_FILE_CONF_FILES}/${filename}_${NCS_FILE_DOMAIN}.yml PARENT_SCOPE)
break()
endif()
endif()
endif()
if(DEFINED FILE_SUFFIX)
set(filename_check ${NCS_FILE_CONF_FILES}/${filename}.yml)
zephyr_file_suffix(filename_check SUFFIX ${FILE_SUFFIX})
if(EXISTS ${filename_check})
set(${NCS_FILE_PM} ${filename_check} PARENT_SCOPE)
break()
endif()
else()
if(EXISTS ${NCS_FILE_CONF_FILES}/${filename}.yml)
set(${NCS_FILE_PM} ${NCS_FILE_CONF_FILES}/${filename}.yml PARENT_SCOPE)
break()
endif()
endif()
endforeach()
endif()
endfunction()
#
# Usage
# set_shared(IMAGE <img> [APPEND] PROPERTY <property> <value>)
#
# Shares a property from child to parent.
# The property is shared through an intermediate shared_vars.cmake file which
# will be parsed by the parent image at CMake configure time.
#
# Example usage 'set_shared(IMAGE child PROPERTY visible_in_parent "I AM YOUR CHILD")'
#
# Usage
# set_shared(FILE <file>)
#
# Shares all properties in file to parent.
# This function can be used to re-share properties from a child to its
# grand parent.
#
function(set_shared)
set(flags "APPEND")
set(single_args "FILE;IMAGE")
set(multi_args "PROPERTY")
cmake_parse_arguments(SHARE "${flags}" "${single_args}" "${multi_args}" ${ARGN})
if(SYSBUILD)
# Sysbuild can read the cache directly, no reason for an extra share file.
list(POP_FRONT SHARE_PROPERTY listname)
if(SHARE_APPEND)
list(APPEND ${listname} ${SHARE_PROPERTY})
list(REMOVE_DUPLICATES ${listname})
set(SHARE_PROPERTY ${${listname}})
endif()
set(${listname} "${SHARE_PROPERTY}" CACHE INTERNAL "shared var")
return()
endif()
check_arguments_required("set_shared" SHARE IMAGE FILE)
check_arguments_exclusive("set_shared" SHARE FILE IMAGE PROPERTY APPEND)
check_arguments_exclusive("set_shared" SHARE IMAGE FILE)
set(prop_target ${IMAGE_NAME}_shared_property_target)
if(NOT TARGET ${prop_target})
add_custom_target(${prop_target})
endif()
if(DEFINED SHARE_IMAGE)
# When using IMAGE, then PROPERTY is also required.
check_arguments_required("set_shared" SHARE PROPERTY)
set(share_prop_target ${SHARE_IMAGE}_shared_property_target)
if(SHARE_APPEND)
set(SHARE_APPEND APPEND)
else()
set(SHARE_APPEND)
endif()
get_property(string_targets TARGET ${prop_target} PROPERTY image_targets)
if(NOT "add_custom_target(${share_prop_target})" IN_LIST string_targets)
set_property(
TARGET ${prop_target} APPEND PROPERTY
image_targets "add_custom_target(${share_prop_target})"
)
endif()
set_property(TARGET ${prop_target} APPEND_STRING PROPERTY shared_vars
"set_property(TARGET ${share_prop_target} ${SHARE_APPEND} PROPERTY ${SHARE_PROPERTY})\n"
)
endif()
if(DEFINED SHARE_FILE)
set_property(TARGET ${prop_target} APPEND_STRING PROPERTY shared_vars
"include(${SHARE_FILE})\n"
)
endif()
endfunction()
# generate_shared(IMAGE <img> FILE <file>)
function(generate_shared)
set(single_args "IMAGE;FILE")
cmake_parse_arguments(SHARE "" "${single_args}" "" ${ARGN})
check_arguments_required_all("generate_shared" SHARE IMAGE FILE)
set(prop_target ${IMAGE_NAME}_shared_property_target)
file(GENERATE OUTPUT ${SHARE_FILE}
CONTENT
"$<JOIN:$<TARGET_PROPERTY:${prop_target},image_targets>,\n>
$<TARGET_PROPERTY:${prop_target},shared_vars>"
)
endfunction()
#
# Usage
# get_shared(<var> IMAGE <img> PROPERTY <property>)
#
# Get a property value defined by the child image or domain <img> if it exists.
# The property value will be returned in the variable referenced by <var>.
#
# Example usage 'get_shared(prop_value IMAGE child PROPERTY property_in_child)'
#
function(get_shared var)
set(single_args "IMAGE")
set(multi_args "PROPERTY")
cmake_parse_arguments(SHARE "" "${single_args}" "${multi_args}" ${ARGN})
check_arguments_required_all("get_shared" SHARE IMAGE PROPERTY)
if(TARGET ${SHARE_IMAGE}_shared_property_target)
get_property(
${var}
TARGET ${SHARE_IMAGE}_shared_property_target
PROPERTY ${SHARE_PROPERTY}
)
set(${var} ${${var}} PARENT_SCOPE)
endif()
endfunction()
#
# Usage
# import_pm_config(<dotconf_file> <keys>)
#
# Import variables from a partition manager output .config file
# (usually pm.config or pm_<DOMAIN>.config) into the CMake namespace.
#
# <dotconf_file>: Absolute path to the file.
# <keys_out>: Output variable, which will be populated with a list
# of variable names loaded from <dotconf_file>.
#
function(import_pm_config dotconf_file keys_out)
file(STRINGS ${dotconf_file} DOTCONF_LIST ENCODING "UTF-8")
foreach(LINE ${DOTCONF_LIST})
# Parse `key=value` assignments, where every key is prefixed with `PM_`.
if("${LINE}" MATCHES "(^PM_[^=]+)=(.*$)")
set(key "${CMAKE_MATCH_1}")
# If the value is surrounded by quotation marks, strip them out.
string(REGEX REPLACE "\"(.*)\"" "\\1" value "${CMAKE_MATCH_2}")
list(APPEND keys "${key}")
set("${key}" "${value}" PARENT_SCOPE)
endif()
endforeach()
set("${keys_out}" "${keys}" PARENT_SCOPE)
endfunction()