blob: a76eb1d09c9aa3b56702d98c657bd13a3feaad58 [file] [log] [blame]
#-------------------------------------------------------------------------------
# Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
#[===[.rst:
Group utility file
------------------
Group is an unordered collection of interrelated :cmake:module:`map`\s.
The main purpose of this utility is to pack a set of coherent configuration data
description into one unit, which can be applied on a target in one step. This
means e.g. defines, compiler flags, include paths, etc.
Internally the utility uses global properties and maps. Global property
``GROUPS.<name of group>`` is defined to indicate that the group is defined, and
for each element in the :cmake:variable:`GROUPS_VALID_TYPES`:
* a map is created, using ``<name of group>.<type>`` as name,
* a global property ``GROUPS.<name of group>.<type>`` is defined to indicate
that the type is valid in the group.
.. todo:: Investigate alternatives to global properties (name collision possible).
.. todo:: Investigate if import/export group functions would be necessary.
#]===]
include_guard(DIRECTORY)
include(Common/Map)
include(Common/Utils)
#[===[.rst:
.. cmake:variable:: GROUPS_VALID_TYPES
List of configuration data types that can be stored in a group. The
implementation of :cmake:command:`group_new` creates a map for each of these
types automatically.
#]===]
set(GROUPS_VALID_TYPES "CONFIG;DEFINE;CFLAG;ASFLAG;LDFLAG;INCLUDE")
#[===[.rst:
.. cmake:command:: group_new
.. code-block:: cmake
group_new(NAME foo)
Create a new group.
Inputs:
``NAME``
Name of the new group, use |C identifier like string|. The name must be
unique within the global namespace, otherwise an error is generated.
#]===]
function(group_new)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS NAME)
set(_MULTI_VALUE_ARGS)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
check_args(group_new NAME)
group_is_defined(NAME ${_MY_PARAMS_NAME} RET _is_defined)
if(_is_defined)
message(FATAL_ERROR "group_new(): '${_MY_PARAMS_NAME}' is already defined.")
endif()
set(_null " ")
define_property(GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME} BRIEF_DOCS ${_null} FULL_DOCS ${_null})
foreach(_type IN LISTS GROUPS_VALID_TYPES)
define_property(GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME}.${_type} BRIEF_DOCS ${_null} FULL_DOCS ${_null})
map_new(NAME ${_MY_PARAMS_NAME}.${_type})
endforeach()
endfunction()
#[===[.rst:
.. cmake:command:: group_is_defined
.. code-block:: cmake
group_is_defined(NAME foo RET ret)
Helper function to check if a group has been defined.
Inputs:
``NAME``
Name of the group.
Outputs:
``RET``
Name of the variable in the parent scope, where the return value is written.
#]===]
function(group_is_defined)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS NAME RET)
set(_MULTI_VALUE_ARGS)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
check_args(group_is_defined NAME RET)
get_property(_is_defined GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME} DEFINED)
set(${_MY_PARAMS_RET} ${_is_defined} PARENT_SCOPE)
endfunction()
#[===[.rst:
.. cmake:command:: group_add
.. code-block:: cmake
group_add(NAME foo TYPE type KEY one VAL 1)
Add new key-value pair to the map called ``type`` within a group. Multiple
types can be defined in one function call, the key-value pair will be added to
each of those types.
Inputs:
``NAME``
Name of the group. Trying to add to a non-existing group generates an error.
``TYPE`` (multi)
Type can be one or more of the values defined in
:cmake:variable:`GROUPS_VALID_TYPES`.
``KEY``
New key to add. Same constraints apply as described in
:cmake:command:`map_add`.
``VAL`` (optional)
Value for new key. Same constraints apply as described in
:cmake:command:`map_add`.
#]===]
function(group_add)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS NAME KEY VAL)
set(_MULTI_VALUE_ARGS TYPE)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
check_args(group_add NAME TYPE KEY)
group_is_defined(NAME ${_MY_PARAMS_NAME} RET _is_group_defined)
if(NOT _is_group_defined)
message(FATAL_ERROR "group_add(): '${_MY_PARAMS_NAME}' group is not defined.")
endif()
if(DEFINED _MY_PARAMS_VAL)
if(DEFINED CFG_${_MY_PARAMS_KEY})
set(_val ${CFG_${_MY_PARAMS_KEY}})
message(STATUS "group_add(): '${_MY_PARAMS_KEY}' in group '${_MY_PARAMS_NAME}' is
overwritten by command line parameter.")
else()
set(_val ${_MY_PARAMS_VAL})
endif()
else()
set(_val " ")
endif()
foreach(_type IN LISTS _MY_PARAMS_TYPE)
get_property(_is_type_defined GLOBAL PROPERTY GROUPS.${_MY_PARAMS_NAME}.${_type} DEFINED)
if(NOT _is_type_defined)
message(FATAL_ERROR "group_add(): '${_type}' type is invalid.")
endif()
map_add(NAME ${_MY_PARAMS_NAME}.${_type} KEY ${_MY_PARAMS_KEY} VAL ${_val})
endforeach()
endfunction()
#[===[.rst:
.. cmake:command:: group_apply
.. code-block:: cmake
group_apply(NAME foo TARGETS target1 target2)
Apply a group onto the selected target(s). All settings contained in the group
will be added to the targets. Use this function only for the build targets
created with :cmake:command:`stgt_create`.
Inputs:
``NAME``
Name of the group.
``TARGETS`` (multi)
Name of the targets.
.. todo:: Move this to STGT?
.. todo:: Revise implementation for INCLUDE type.
#]===]
function(group_apply)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS NAME)
set(_MULTI_VALUE_ARGS TARGETS)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
check_args(group_apply NAME TARGETS)
group_is_defined(NAME ${_MY_PARAMS_NAME} RET _is_defined)
if(NOT _is_defined)
message(FATAL_ERROR "group_apply(): '${_MY_PARAMS_NAME}' group is not defined.")
endif()
foreach(_target IN LISTS _MY_PARAMS_TARGETS)
if(NOT TARGET ${_target})
message(FATAL_ERROR "group_apply(): target '${_target}' is not defined.")
endif()
map_read(NAME ${_MY_PARAMS_NAME}.CONFIG KEYS _keys VALS _vals)
if(_keys AND _vals)
list(LENGTH _keys _count)
math(EXPR _count "${_count}-1")
foreach(i RANGE ${_count})
list(GET _keys ${i} _key)
list(GET _vals ${i} _val)
set_property(TARGET ${_target} PROPERTY ${_key} ${_val})
endforeach()
endif()
map_read(NAME ${_MY_PARAMS_NAME}.DEFINE KEYS _keys VALS _vals)
if(_keys AND _vals)
map_to_list(KEYS ${_keys} VALS ${_vals} OUT _defines)
target_compile_definitions(${_target} PRIVATE ${_defines})
endif()
map_read(NAME ${_MY_PARAMS_NAME}.CFLAG KEYS _keys VALS _vals)
if(_keys AND _vals)
map_to_list(KEYS ${_keys} VALS ${_vals} OUT _cflags)
target_compile_options(${_target} PRIVATE ${_cflags})
endif()
map_read(NAME ${_MY_PARAMS_NAME}.ASFLAG KEYS _keys VALS _vals)
if(_keys AND _vals)
map_to_list(KEYS ${_keys} VALS ${_vals} OUT _asflags)
target_compile_options(${_target} PRIVATE $<$<COMPILE_LANGUAGE:ASM>:${_asflags}>)
endif()
map_read(NAME ${_MY_PARAMS_NAME}.LDFLAG KEYS _keys VALS _vals)
if(_keys AND _vals)
map_to_list(KEYS ${_keys} VALS ${_vals} OUT _ldflags)
target_link_options(${_target} PRIVATE ${_ldflags})
endif()
map_read(NAME ${_MY_PARAMS_NAME}.INCLUDE KEYS _keys VALS _vals)
if(_keys)
stgt_add_inc_param(NAME ${_target} KEY ARCH INC ${_keys})
endif()
endforeach()
endfunction()
#[===[.rst:
.. cmake:command:: group_print
.. code-block:: cmake
group_print(NAME foo)
Print contents of the group, for debug purposes.
Inputs:
``NAME``
Name of the group.
#]===]
function(group_print)
set(_OPTIONS_ARGS)
set(_ONE_VALUE_ARGS NAME)
set(_MULTI_VALUE_ARGS)
cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
if (NOT DEFINED _MY_PARAMS_NAME)
message(FATAL_ERROR "group_print(): mandatory parameter 'NAME' missing.")
endif()
message("\n====Group '${_MY_PARAMS_NAME}'====")
foreach(_type IN LISTS GROUPS_VALID_TYPES)
map_print(NAME ${_MY_PARAMS_NAME}.${_type})
endforeach()
message("====Group '${_MY_PARAMS_NAME}' end====\n")
endfunction()