blob: a76eb1d09c9aa3b56702d98c657bd13a3feaad58 [file] [log] [blame]
Gyorgy Szing5e429cb2019-12-03 20:39:55 +01001#-------------------------------------------------------------------------------
2# Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8#[===[.rst:
9Group utility file
10------------------
11Group is an unordered collection of interrelated :cmake:module:`map`\s.
12
13The main purpose of this utility is to pack a set of coherent configuration data
14description into one unit, which can be applied on a target in one step. This
15means e.g. defines, compiler flags, include paths, etc.
16
17Internally the utility uses global properties and maps. Global property
18``GROUPS.<name of group>`` is defined to indicate that the group is defined, and
19for each element in the :cmake:variable:`GROUPS_VALID_TYPES`:
20
21 * a map is created, using ``<name of group>.<type>`` as name,
22 * a global property ``GROUPS.<name of group>.<type>`` is defined to indicate
23 that the type is valid in the group.
24
25.. todo:: Investigate alternatives to global properties (name collision possible).
26.. todo:: Investigate if import/export group functions would be necessary.
27
28#]===]
29
30include_guard(DIRECTORY)
31include(Common/Map)
32include(Common/Utils)
33
34#[===[.rst:
35.. cmake:variable:: GROUPS_VALID_TYPES
36
37 List of configuration data types that can be stored in a group. The
38 implementation of :cmake:command:`group_new` creates a map for each of these
39 types automatically.
40
41#]===]
42set(GROUPS_VALID_TYPES "CONFIG;DEFINE;CFLAG;ASFLAG;LDFLAG;INCLUDE")
43
44#[===[.rst:
45.. cmake:command:: group_new
46
47 .. code-block:: cmake
48
49 group_new(NAME foo)
50
51 Create a new group.
52
53 Inputs:
54
55 ``NAME``
56 Name of the new group, use |C identifier like string|. The name must be
57 unique within the global namespace, otherwise an error is generated.
58
59#]===]
60function(group_new)
61 set(_OPTIONS_ARGS)
62 set(_ONE_VALUE_ARGS NAME)
63 set(_MULTI_VALUE_ARGS)
64 cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
65
66 check_args(group_new NAME)
67
68 group_is_defined(NAME ${_MY_PARAMS_NAME} RET _is_defined)
69 if(_is_defined)
70 message(FATAL_ERROR "group_new(): '${_MY_PARAMS_NAME}' is already defined.")
71 endif()
72
73 set(_null " ")
74 define_property(GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME} BRIEF_DOCS ${_null} FULL_DOCS ${_null})
75
76 foreach(_type IN LISTS GROUPS_VALID_TYPES)
77 define_property(GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME}.${_type} BRIEF_DOCS ${_null} FULL_DOCS ${_null})
78 map_new(NAME ${_MY_PARAMS_NAME}.${_type})
79 endforeach()
80endfunction()
81
82#[===[.rst:
83.. cmake:command:: group_is_defined
84
85 .. code-block:: cmake
86
87 group_is_defined(NAME foo RET ret)
88
89 Helper function to check if a group has been defined.
90
91 Inputs:
92
93 ``NAME``
94 Name of the group.
95
96 Outputs:
97
98 ``RET``
99 Name of the variable in the parent scope, where the return value is written.
100
101#]===]
102function(group_is_defined)
103 set(_OPTIONS_ARGS)
104 set(_ONE_VALUE_ARGS NAME RET)
105 set(_MULTI_VALUE_ARGS)
106 cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
107
108 check_args(group_is_defined NAME RET)
109
110 get_property(_is_defined GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME} DEFINED)
111 set(${_MY_PARAMS_RET} ${_is_defined} PARENT_SCOPE)
112endfunction()
113
114#[===[.rst:
115.. cmake:command:: group_add
116
117 .. code-block:: cmake
118
119 group_add(NAME foo TYPE type KEY one VAL 1)
120
121 Add new key-value pair to the map called ``type`` within a group. Multiple
122 types can be defined in one function call, the key-value pair will be added to
123 each of those types.
124
125 Inputs:
126
127 ``NAME``
128 Name of the group. Trying to add to a non-existing group generates an error.
129
130 ``TYPE`` (multi)
131 Type can be one or more of the values defined in
132 :cmake:variable:`GROUPS_VALID_TYPES`.
133
134 ``KEY``
135 New key to add. Same constraints apply as described in
136 :cmake:command:`map_add`.
137
138 ``VAL`` (optional)
139 Value for new key. Same constraints apply as described in
140 :cmake:command:`map_add`.
141
142#]===]
143function(group_add)
144 set(_OPTIONS_ARGS)
145 set(_ONE_VALUE_ARGS NAME KEY VAL)
146 set(_MULTI_VALUE_ARGS TYPE)
147 cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
148
149 check_args(group_add NAME TYPE KEY)
150
151 group_is_defined(NAME ${_MY_PARAMS_NAME} RET _is_group_defined)
152 if(NOT _is_group_defined)
153 message(FATAL_ERROR "group_add(): '${_MY_PARAMS_NAME}' group is not defined.")
154 endif()
155
156 if(DEFINED _MY_PARAMS_VAL)
157 if(DEFINED CFG_${_MY_PARAMS_KEY})
158 set(_val ${CFG_${_MY_PARAMS_KEY}})
159 message(STATUS "group_add(): '${_MY_PARAMS_KEY}' in group '${_MY_PARAMS_NAME}' is
160 overwritten by command line parameter.")
161 else()
162 set(_val ${_MY_PARAMS_VAL})
163 endif()
164 else()
165 set(_val " ")
166 endif()
167
168 foreach(_type IN LISTS _MY_PARAMS_TYPE)
169 get_property(_is_type_defined GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME}.${_type} DEFINED)
170 if(NOT _is_type_defined)
171 message(FATAL_ERROR "group_add(): '${_type}' type is invalid.")
172 endif()
173
174 map_add(NAME ${_MY_PARAMS_NAME}.${_type} KEY ${_MY_PARAMS_KEY} VAL ${_val})
175 endforeach()
176endfunction()
177
178#[===[.rst:
179.. cmake:command:: group_apply
180
181 .. code-block:: cmake
182
183 group_apply(NAME foo TARGETS target1 target2)
184
185 Apply a group onto the selected target(s). All settings contained in the group
186 will be added to the targets. Use this function only for the build targets
187 created with :cmake:command:`stgt_create`.
188
189 Inputs:
190
191 ``NAME``
192 Name of the group.
193
194 ``TARGETS`` (multi)
195 Name of the targets.
196
197 .. todo:: Move this to STGT?
198 .. todo:: Revise implementation for INCLUDE type.
199
200#]===]
201function(group_apply)
202 set(_OPTIONS_ARGS)
203 set(_ONE_VALUE_ARGS NAME)
204 set(_MULTI_VALUE_ARGS TARGETS)
205 cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
206
207 check_args(group_apply NAME TARGETS)
208
209 group_is_defined(NAME ${_MY_PARAMS_NAME} RET _is_defined)
210 if(NOT _is_defined)
211 message(FATAL_ERROR "group_apply(): '${_MY_PARAMS_NAME}' group is not defined.")
212 endif()
213
214 foreach(_target IN LISTS _MY_PARAMS_TARGETS)
215 if(NOT TARGET ${_target})
216 message(FATAL_ERROR "group_apply(): target '${_target}' is not defined.")
217 endif()
218
219 map_read(NAME ${_MY_PARAMS_NAME}.CONFIG KEYS _keys VALS _vals)
220 if(_keys AND _vals)
221 list(LENGTH _keys _count)
222 math(EXPR _count "${_count}-1")
223
224 foreach(i RANGE ${_count})
225 list(GET _keys ${i} _key)
226 list(GET _vals ${i} _val)
227 set_property(TARGET ${_target} PROPERTY ${_key} ${_val})
228 endforeach()
229 endif()
230
231 map_read(NAME ${_MY_PARAMS_NAME}.DEFINE KEYS _keys VALS _vals)
232 if(_keys AND _vals)
233 map_to_list(KEYS ${_keys} VALS ${_vals} OUT _defines)
234 target_compile_definitions(${_target} PRIVATE ${_defines})
235 endif()
236
237 map_read(NAME ${_MY_PARAMS_NAME}.CFLAG KEYS _keys VALS _vals)
238 if(_keys AND _vals)
239 map_to_list(KEYS ${_keys} VALS ${_vals} OUT _cflags)
240 target_compile_options(${_target} PRIVATE ${_cflags})
241 endif()
242
243 map_read(NAME ${_MY_PARAMS_NAME}.ASFLAG KEYS _keys VALS _vals)
244 if(_keys AND _vals)
245 map_to_list(KEYS ${_keys} VALS ${_vals} OUT _asflags)
246 target_compile_options(${_target} PRIVATE $<$<COMPILE_LANGUAGE:ASM>:${_asflags}>)
247 endif()
248
249 map_read(NAME ${_MY_PARAMS_NAME}.LDFLAG KEYS _keys VALS _vals)
250 if(_keys AND _vals)
251 map_to_list(KEYS ${_keys} VALS ${_vals} OUT _ldflags)
252 target_link_options(${_target} PRIVATE ${_ldflags})
253 endif()
254
255 map_read(NAME ${_MY_PARAMS_NAME}.INCLUDE KEYS _keys VALS _vals)
256 if(_keys)
257 stgt_add_inc_param(NAME ${_target} KEY ARCH INC ${_keys})
258 endif()
259 endforeach()
260endfunction()
261
262#[===[.rst:
263.. cmake:command:: group_print
264
265 .. code-block:: cmake
266
267 group_print(NAME foo)
268
269 Print contents of the group, for debug purposes.
270
271 Inputs:
272
273 ``NAME``
274 Name of the group.
275
276#]===]
277function(group_print)
278 set(_OPTIONS_ARGS)
279 set(_ONE_VALUE_ARGS NAME)
280 set(_MULTI_VALUE_ARGS)
281 cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
282
283 if (NOT DEFINED _MY_PARAMS_NAME)
284 message(FATAL_ERROR "group_print(): mandatory parameter 'NAME' missing.")
285 endif()
286
287 message("\n====Group '${_MY_PARAMS_NAME}'====")
288 foreach(_type IN LISTS GROUPS_VALID_TYPES)
289 map_print(NAME ${_MY_PARAMS_NAME}.${_type})
290 endforeach()
291 message("====Group '${_MY_PARAMS_NAME}' end====\n")
292endfunction()