Add first version of CMake framework code

This commit adds the core elements of the framework and documentation:
 - Map utility: store key-value pairs.
 - Group utility: store build configuration options.
 - STGT API: describe the targets.
 - Compiler abstraction functions for GCC.
 - Other helper functions.
 - New CMake system type called "Embedded", using correct output file
   prefixes and extensions.
 - Sphinx based documentation which includes:
    - licensing information
    - version numbering policy
    - documentation on how-to build the documentation

In addition the following utility files are added:
  - .editorconfig
  - .gitignore

Change-Id: If19a171ef066775d3544fba82f1cc70a5fb0e7d7
Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Co-authored-by: Gyorgy Szing <gyorgy.szing@arm.com>
Co-authored-by: Bence Szépkúti <bence.szepkuti@arm.com>
diff --git a/Common/Map.cmake b/Common/Map.cmake
new file mode 100644
index 0000000..710f9b3
--- /dev/null
+++ b/Common/Map.cmake
@@ -0,0 +1,306 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#[===[.rst:
+Map utility file
+----------------
+Map is a key-value pair storage (also known as associative array)
+implementation. It can hold multiple key-value pairs, the keys have to be unique
+in a map. Trying to add a new pair whose key already exists in the map will
+cause an error. Keys and values have a one-to-one relation, i.e. a key has
+exactly one value associated to it, which cannot be empty. If an empty/null
+value is needed, use a single space character instead. The value associated to a
+key cannot be overwritten, however it is possible to remove a key-value pair
+from the map then add the same key again with a new value.
+
+The main purpose of this utility is to store configuration data for the project,
+i.e. build options, compiler flags, etc.
+
+Internally the utility uses global properties to store the data. The global
+property ``MAPS.<name of map>`` is created as an indicator that the map is
+defined, while global properties ``MAPS.<name of map>.KEYS`` and ``MAPS.<name of
+map>.VALS`` hold the corresponding data as lists. A value for a key is
+identified by having the same index in the VALS lists, as the key has in the
+KEYS list.
+
+.. todo:: Investigate alternatives to global properties (name collision possible).
+
+#]===]
+
+include_guard(DIRECTORY)
+include(Common/Utils)
+
+#[===[.rst:
+.. cmake:command:: map_new
+
+  .. code-block:: cmake
+
+    map_new(NAME foo)
+
+  Create a new named set of key-value pairs.
+
+  Inputs:
+
+  ``NAME``
+    Name of the new map, use |C identifier like string|. The name must be unique
+    within the global namespace, otherwise an error is generated.
+
+#]===]
+function(map_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(map_new NAME)
+
+	get_property(is_defined GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME} DEFINED)
+	if(is_defined)
+		message(FATAL_ERROR "map_new(): '${_MY_PARAMS_NAME}' is already defined.")
+	endif()
+
+	set(_null " ")
+	define_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME} BRIEF_DOCS ${_null} FULL_DOCS ${_null})
+	define_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.KEYS BRIEF_DOCS ${_null} FULL_DOCS ${_null})
+	define_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.VALS BRIEF_DOCS ${_null} FULL_DOCS ${_null})
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: map_add
+
+  .. code-block:: cmake
+
+    map_add(NAME foo KEY one VAL 1)
+
+  Add new key-value pair to a map.
+
+  ``KEY`` and ``VAL`` are stored as CMake properties (string list) which permit
+  a broad, but not clearly defined set of characters. Semicolons must be escaped
+  as ``\;`` in all cases. To minimize the amount of possible bugs, both ``KEY``
+  and ``VAL`` should use |C identifier like string|. Exceptions are e.g. when a
+  path is stored as the value.
+
+  Inputs:
+
+  ``NAME``
+    Name of the map. Trying to add to a non-existing map generates an error.
+
+  ``KEY``
+    New key to add. Key must be unique, trying to add a new pair whose key
+    already exists in the map will cause an error.
+
+  ``VAL``
+    Value for new key.
+
+#]===]
+function(map_add)
+	set(_OPTIONS_ARGS)
+	set(_ONE_VALUE_ARGS NAME KEY VAL)
+	set(_MULTI_VALUE_ARGS)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+	check_args(map_add NAME KEY VAL)
+
+	get_property(_is_defined GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME} DEFINED)
+	if(NOT _is_defined)
+		message(FATAL_ERROR "map_add(): '${_MY_PARAMS_NAME}' is not defined.")
+	endif()
+
+	get_property(_keys GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.KEYS)
+	get_property(_vals GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.VALS)
+
+	if(${_MY_PARAMS_KEY} IN_LIST _keys)
+		message(FATAL_ERROR "map_add(): key '${_MY_PARAMS_KEY}' is already defined.")
+	else()
+		list(APPEND _keys ${_MY_PARAMS_KEY})
+		list(APPEND _vals ${_MY_PARAMS_VAL})
+
+		set_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.KEYS ${_keys})
+		set_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.VALS ${_vals})
+	endif()
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: map_remove
+
+  .. code-block:: cmake
+
+    map_remove(NAME foo KEY one)
+
+  Remove existing key-value pair from a map.
+
+  Inputs:
+
+  ``NAME``
+    Name of the map. Trying to remove from a non-existing map generates an
+    error.
+
+  ``KEY``
+    Key to remove. Trying to remove a non-existing key generates an error.
+
+#]===]
+function(map_remove)
+	set(_OPTIONS_ARGS)
+	set(_ONE_VALUE_ARGS NAME KEY)
+	set(_MULTI_VALUE_ARGS)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+	check_args(map_remove NAME KEY)
+
+	get_property(_is_defined GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME} DEFINED)
+	if(NOT _is_defined)
+		message(FATAL_ERROR "map_remove(): '${_MY_PARAMS_NAME}' is not defined.")
+	endif()
+
+	get_property(_keys GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.KEYS)
+	get_property(_vals GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.VALS)
+
+	list(FIND _keys ${_MY_PARAMS_KEY} _index)
+	if(_index EQUAL -1)
+		message(FATAL_ERROR "map_remove(): key '${_MY_PARAMS_KEY}' does not exist.")
+	endif()
+
+	list(REMOVE_AT _keys ${_index})
+	list(REMOVE_AT _vals ${_index})
+
+	set_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.KEYS ${_keys})
+	set_property(GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.VALS ${_vals})
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: map_read
+
+  .. code-block:: cmake
+
+    map_read(NAME foo KEYS _keys VALS _vals)
+
+  Read the keys and the values of the map into two separate lists in the parent
+  scope.
+
+  Inputs:
+
+  ``NAME``
+    Name of the map. Trying to read a non-existing map generates an error.
+
+  Outputs:
+
+  ``KEYS``
+    Read the keys list of the map into this variable of the parent scope.
+
+  ``VALS``
+    Read the values list of the map into this variable of the parent scope.
+
+#]===]
+function(map_read)
+	set(_OPTIONS_ARGS)
+	set(_ONE_VALUE_ARGS NAME KEYS VALS)
+	set(_MULTI_VALUE_ARGS)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+	check_args(map_read NAME KEYS VALS)
+
+	get_property(_is_defined GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME} DEFINED)
+	if(NOT _is_defined)
+		message(FATAL_ERROR "map_read(): '${_MY_PARAMS_NAME}' is not defined.")
+	endif()
+
+	get_property(_keys GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.KEYS)
+	get_property(_vals GLOBAL PROPERTY MAPS.${_MY_PARAMS_NAME}.VALS)
+
+	set(${_MY_PARAMS_KEYS} ${_keys} PARENT_SCOPE)
+	set(${_MY_PARAMS_VALS} ${_vals} PARENT_SCOPE)
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: map_to_list
+
+  .. code-block:: cmake
+
+    map_to_list(KEYS ${_keys} VALS ${_vals} OUT _combined)
+
+  Combine the keys and values list of a map (provided by
+  :cmake:command:`map_read` function) into a single list in the parent scope.
+
+  * If a key 'FOO' has the value 'BAR', in the combined list it will be
+    'FOO=BAR'.
+  * If a key 'FOO' has a single space character value, in the combined list it
+    will be 'FOO'.
+
+  Inputs:
+
+  ``KEYS``
+    Keys list of a map.
+
+  ``VALS``
+    Values list of a map.
+
+  Outputs:
+
+  ``OUT``
+    Write the combined list of key-value pairs into this variable of the parent
+    scope.
+
+#]===]
+function(map_to_list)
+	set(_OPTIONS_ARGS)
+	set(_ONE_VALUE_ARGS OUT)
+	set(_MULTI_VALUE_ARGS KEYS VALS)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN})
+
+	check_args(map_to_list KEYS VALS OUT)
+
+	list(LENGTH _MY_PARAMS_KEYS _count)
+	math(EXPR _count "${_count}-1")
+	foreach(i RANGE ${_count})
+		list(GET _MY_PARAMS_KEYS ${i} _key)
+		list(GET _MY_PARAMS_VALS ${i} _val)
+
+		if(${_val} STREQUAL " ")
+			list(APPEND _out "${_key}")
+		else()
+			list(APPEND _out "${_key}=${_val}")
+		endif()
+	endforeach()
+
+	set(${_MY_PARAMS_OUT} ${_out} PARENT_SCOPE)
+endfunction()
+
+#[===[.rst:
+.. cmake:command:: map_print
+
+  .. code-block:: cmake
+
+    map_print(NAME foo)
+
+  Print each key-value pair in a map, for debug purposes.
+
+  Inputs:
+
+  ``NAME``
+    Name of the map to print.
+
+#]===]
+function(map_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})
+
+	check_args(map_print NAME)
+
+	map_read(NAME ${_MY_PARAMS_NAME} KEYS _keys VALS _vals)
+
+	message("====Map '${_MY_PARAMS_NAME}'====")
+	list(LENGTH _keys _count)
+	math(EXPR _count "${_count}-1")
+	foreach(i RANGE ${_count})
+		list(GET _keys ${i} _key)
+		list(GET _vals ${i} _val)
+		message("[${_key}]: ${_val}")
+	endforeach()
+	message("====Map '${_MY_PARAMS_NAME}' end====\n")
+endfunction()
\ No newline at end of file