Gyorgy Szing | 5e429cb | 2019-12-03 20:39:55 +0100 | [diff] [blame] | 1 | #------------------------------------------------------------------------------- |
| 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: |
| 9 | Group utility file |
| 10 | ------------------ |
| 11 | Group is an unordered collection of interrelated :cmake:module:`map`\s. |
| 12 | |
| 13 | The main purpose of this utility is to pack a set of coherent configuration data |
| 14 | description into one unit, which can be applied on a target in one step. This |
| 15 | means e.g. defines, compiler flags, include paths, etc. |
| 16 | |
| 17 | Internally the utility uses global properties and maps. Global property |
| 18 | ``GROUPS.<name of group>`` is defined to indicate that the group is defined, and |
| 19 | for 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 | |
| 30 | include_guard(DIRECTORY) |
| 31 | include(Common/Map) |
| 32 | include(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 | #]===] |
| 42 | set(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 | #]===] |
| 60 | function(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() |
| 80 | endfunction() |
| 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 | #]===] |
| 102 | function(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) |
| 112 | endfunction() |
| 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 | #]===] |
| 143 | function(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() |
| 176 | endfunction() |
| 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 | #]===] |
| 201 | function(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() |
| 260 | endfunction() |
| 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 | #]===] |
| 277 | function(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") |
| 292 | endfunction() |