cmake: Add gcc support

This commit adds the option to cmake to build TF-M with GCC.

Change-Id: I7a5e3c915efa61620f1f0d34ed42cba5c174c562
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/CommonConfig.cmake b/CommonConfig.cmake
index 37368e3..b3074be 100755
--- a/CommonConfig.cmake
+++ b/CommonConfig.cmake
@@ -31,18 +31,45 @@
 	include(${PLATFORM_CMAKE_FILE})
 endif()
 
+if(NOT DEFINED COMPILER)
+	message(FATAL_ERROR "ERROR: COMPILER is not set in command line")
+elseif(${COMPILER} STREQUAL "ARMCLANG")
+	#Use any ARMCLANG version found on PATH. Note: Only versions supported by the
+	#build system will work. A file cmake/Common/CompilerArmClangXY.cmake
+	#must be present with a matching version.
+	include("Common/FindArmClang")
+	include("Common/${ARMCLANG_MODULE}")
 
-#Use any ARMCLANG version found on PATH. Note: Only versions supported by the
-#build system will work. A file cmake/Common/CompilerArmClangXY.cmake
-#must be present with a matching version.
-include("Common/FindArmClang")
-include("Common/${ARMCLANG_MODULE}")
+	set (COMMON_COMPILE_FLAGS -fshort-enums -fshort-wchar -funsigned-char -mfpu=none -mcmse)
+	##Shared compiler and linker settings.
+	function(config_setting_shared_flags tgt)
+		embedded_set_target_compile_flags(TARGET ${tgt} LANGUAGE C FLAGS -xc -std=c99 ${COMMON_COMPILE_FLAGS} -Wall -Werror)
+		embedded_set_target_link_flags(TARGET ${tgt} FLAGS --strict --map --symbols --xref --entry=Reset_Handler --info=summarysizes,sizes,totals,unused,veneers)
+	endfunction()
+elseif(${COMPILER} STREQUAL "GNUARM")
+	#Use any GNUARM version found on PATH. Note: Only versions supported by the
+	#build system will work. A file cmake/Common/CompilerGNUARMXY.cmake
+	#must be present with a matching version.
+	include("Common/FindGNUARM")
+	include("Common/${GNUARM_MODULE}")
 
-##Shared compiler and linker settings.
-function(config_setting_shared_flags tgt)
-	embedded_set_target_compile_flags(TARGET ${tgt} LANGUAGE C FLAGS -xc -std=c99 -fshort-enums -mfpu=none -fshort-wchar -funsigned-char -mcmse -Wall -Werror)
-	embedded_set_target_link_flags(TARGET ${tgt} FLAGS --strict --map --symbols --xref --entry=Reset_Handler --info=summarysizes,sizes,totals,unused,veneers)
-endfunction()
+	set (COMMON_COMPILE_FLAGS -fshort-enums -fshort-wchar -funsigned-char -msoft-float -mcmse)
+	##Shared compiler and linker settings.
+	function(config_setting_shared_flags tgt)
+		embedded_set_target_compile_flags(TARGET ${tgt} LANGUAGE C FLAGS -xc -std=c99 ${COMMON_COMPILE_FLAGS} -Wall -Werror -Wno-format -Wno-return-type -Wno-unused-but-set-variable)
+		#--no-wchar-size-warning flag is added because TF-M sources are compiled
+		#with short wchars, however the standard library is compiled with normal
+		#wchar, and this generates linker time warnings. TF-M code does not use
+		#wchar, so the warning can be suppressed.
+		embedded_set_target_link_flags(TARGET ${tgt} FLAGS -Xlinker -check-sections -Xlinker -fatal-warnings --entry=Reset_Handler -Wl,--no-wchar-size-warning)
+	endfunction()
+else()
+	message(FATAL_ERROR "ERROR: Compiler \"${COMPILER}\" is not supported.")
+endif()
+
+#Create a string from the compile flags list, so that it can be used later
+#in this file to set mbedtls and BL2 flags
+string(REPLACE ";" " " COMMON_COMPILE_FLAGS_STR "${COMMON_COMPILE_FLAGS}")
 
 #Settings which shall be set for all projects the same way based
 # on the variables above.
@@ -128,7 +155,7 @@
 
 ##TF-M storage
 config_setting_shared_flags(tfm_storage)
-set(MBEDTLS_C_FLAGS "-D__ARM_FEATURE_CMSE=3 -D__thumb2__ -fshort-enums -mfpu=none -fshort-wchar -funsigned-char -mcmse  -DMBEDTLS_CONFIG_FILE=\\\\\\\"mbedtls_config.h\\\\\\\" -I${CMAKE_CURRENT_LIST_DIR}/platform/ext/common")
+set(MBEDTLS_C_FLAGS "-D__ARM_FEATURE_CMSE=3 -D__thumb2__ ${COMMON_COMPILE_FLAGS_STR} -DMBEDTLS_CONFIG_FILE=\\\\\\\"mbedtls_config.h\\\\\\\" -I${CMAKE_CURRENT_LIST_DIR}/platform/ext/common")
 
 set (SST_ENCRYPTION ON)
 set (SST_RAM_FS ON)
@@ -142,4 +169,4 @@
 
 ##BL2
 config_setting_shared_flags(mcuboot)
-set(MBEDTLS_C_FLAGS_BL2 "-D__ARM_FEATURE_CMSE=3 -D__thumb2__ -fshort-enums -mfpu=none -fshort-wchar -funsigned-char -mcmse  -DMBEDTLS_CONFIG_FILE=\\\\\\\"config-boot.h\\\\\\\" -I${CMAKE_CURRENT_LIST_DIR}/bl2/ext/mcuboot/include")
+set(MBEDTLS_C_FLAGS_BL2 "-D__ARM_FEATURE_CMSE=3 -D__thumb2__ ${COMMON_COMPILE_FLAGS_STR} -DMBEDTLS_CONFIG_FILE=\\\\\\\"config-boot.h\\\\\\\" -I${CMAKE_CURRENT_LIST_DIR}/bl2/ext/mcuboot/include")
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 681eab8..c657276 100755
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -136,20 +136,20 @@
 if (NOT DEFINED TFM_PARTITION_TEST_CORE)
 	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_CORE is undefined. ")
 elseif (TFM_PARTITION_TEST_CORE)
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DTFM_PARTITION_TEST_CORE\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_PARTITION_TEST_CORE")
 endif()
 
 if (NOT DEFINED TFM_PARTITION_TEST_SST)
 	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_SST is undefined. ")
 elseif (TFM_PARTITION_TEST_SST)
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DTFM_PARTITION_TEST_SST\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_PARTITION_TEST_SST")
 endif()
 
 #Set BL2 specific settings.
 if (NOT DEFINED BL2)
 	message(FATAL_ERROR "Incomplete build configuration: BL2 is undefined. ")
 elseif (BL2)
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DBL2\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "BL2")
 endif()
 
 
diff --git a/bl2/ext/mcuboot/CMakeLists.txt b/bl2/ext/mcuboot/CMakeLists.txt
index dcc63e5..744e83c 100644
--- a/bl2/ext/mcuboot/CMakeLists.txt
+++ b/bl2/ext/mcuboot/CMakeLists.txt
@@ -106,7 +106,7 @@
 add_executable(${PROJECT_NAME} ${ALL_SRC_ASM_BL2} ${ALL_SRC_C} ${ALL_SRC_CXX})
 
 #Add BL2 define to linker to resolve symbols in region_defs.h
-set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DBL2\"")
+embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "BL2")
 
 #Link mbedcrypto library to project
 target_link_libraries(${PROJECT_NAME} "${MBEDTLS_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX_C}mbedcrypto${CMAKE_STATIC_LIBRARY_SUFFIX_C}")
diff --git a/cmake/Common/BuildSys.cmake b/cmake/Common/BuildSys.cmake
index 43e1b90..81c204d 100644
--- a/cmake/Common/BuildSys.cmake
+++ b/cmake/Common/BuildSys.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2017, Arm Limited. All rights reserved.
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -47,9 +47,9 @@
 	endif()
 
 	set( _OPTIONS_ARGS )					#No option (on/off) arguments
-    set( _ONE_VALUE_ARGS CONFIG)	#Single option arguments (e.g. PROJ_NAME "bubu_project")
-    set( _MULTI_VALUE_ARGS )		#One list argument (e.g. LANGUAGES C ASM CXX)
-    cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+	set( _ONE_VALUE_ARGS CONFIG)	#Single option arguments (e.g. PROJ_NAME "bubu_project")
+	set( _MULTI_VALUE_ARGS )		#One list argument (e.g. LANGUAGES C ASM CXX)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
 
 	#Cehck passed parameters
 	if(NOT _MY_PARAMS_CONFIG)
@@ -583,15 +583,15 @@
 # See: _embedded_apply_linker_cmd_file_setting()
 #
 #Examples:
-#  embedded_set_target_linker_file(my_app "foo/my_linker_cmd.sct")
+#  embedded_set_target_linker_file(TARGET my_app PATH "foo/my_linker_cmd.sct")
 #
 #INPUTS:
-#   TARGET  - (mandatory) - The target to apply settings to.
-#	PATH - (mandatory)	  - Path to linker script.
+#  TARGET  - (mandatory) - The target to apply settings to.
+#  PATH - (mandatory)    - Path to linker script.
 #
 #OUTPUTS
-#	Directory property EMBEDDED_LINKER_CMD_FILE_TTT is set, where TTT is the
-#	target name.
+#  Directory property EMBEDDED_LINKER_CMD_FILE_TTT is set, where TTT is the
+#  target name.
 #
 function(embedded_set_target_linker_file)
 	set( _OPTIONS_ARGS )				#Option (on/off) arguments (e.g. IGNORE_CASE)
@@ -610,29 +610,103 @@
 	set_property(GLOBAL PROPERTY EMBEDDED_LINKER_CMD_FILE_${_MY_PARAMS_TARGET} ${_MY_PARAMS_PATH})
 endfunction()
 
+#Set pre-processor defines for the linker command file.
+#
+# Store preprocessor defines for the linker command file of the specified target
+# in a global property.
+#
+# See: _embedded_apply_linker_cmd_file_setting()
+#
+#Examples:
+#  embedded_set_target_link_defines(my_app "BL2=1" "USE_TLS=1")
+#
+#INPUTS:
+#   TARGET  - (mandatory) - The target to apply settings to.
+#   DEFINES - (mandatory) - List of macro value definitions.
+#
+#OUTPUTS
+#   Directory property EMBEDDED_LINKER_DEFINES_TTT is set, where TTT is the
+#   target name.
+#
+function(embedded_set_target_link_defines)
+	set( _OPTIONS_ARGS )				#Option (on/off) arguments (e.g. IGNORE_CASE)
+	set( _ONE_VALUE_ARGS  TARGET DEFINES)	#Single option arguments (e.g. PATH "./foo/bar")
+	set( _MULTI_VALUE_ARGS )			#List arguments (e.g. LANGUAGES C ASM CXX)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+
+	if (NOT DEFINED _MY_PARAMS_TARGET)
+		message(FATAL_ERROR "embedded_set_target_link_defines(): mandatory parameter 'TARGET' missing.")
+	endif()
+
+	if (NOT DEFINED _MY_PARAMS_DEFINES)
+		message(FATAL_ERROR "embedded_set_target_link_defines(): mandatory parameter 'DEFINES' missing.")
+	endif()
+
+	set_property(GLOBAL APPEND PROPERTY EMBEDDED_LINKER_DEFINES_${_MY_PARAMS_TARGET} ${_MY_PARAMS_DEFINES})
+endfunction()
+
+
+#Set pre-processor include paths for the linker command file.
+#
+# Store preprocessor include paths for the linker command file of the specified
+# target in a global property.
+#
+# See: _embedded_apply_linker_cmd_file_setting()
+#
+#Examples:
+#  embedded_set_target_link_includes(my_app "c:/foo" "../bar")
+#
+#INPUTS:
+#   TARGET  - (mandatory)  - The target to apply settings to.
+#   INCLUDES - (mandatory) - List of include paths.
+#
+#OUTPUTS
+#   Directory property EMBEDDED_LINKER_INCLUDES_TTT is set, where TTT is the
+#   target name.
+#
+function(embedded_set_target_link_includes)
+	set( _OPTIONS_ARGS )				#Option (on/off) arguments (e.g. IGNORE_CASE)
+	set( _ONE_VALUE_ARGS  TARGET INCLUDES)	#Single option arguments (e.g. PATH "./foo/bar")
+	set( _MULTI_VALUE_ARGS )			#List arguments (e.g. LANGUAGES C ASM CXX)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+
+	if (NOT DEFINED _MY_PARAMS_TARGET)
+		message(FATAL_ERROR "embedded_set_target_link_includes(): mandatory parameter 'TARGET' missing.")
+	endif()
+
+	if (NOT DEFINED _MY_PARAMS_DEFINES)
+		message(FATAL_ERROR "embedded_set_target_link_includes(): mandatory parameter 'DEFINES' missing.")
+	endif()
+
+	set_property(GLOBAL APPEND PROPERTY EMBEDDED_LINKER_INCLUDES_${_MY_PARAMS_TARGET} ${_MY_PARAMS_DEFINES})
+endfunction()
+
+
 #Apply linker linker command file setting for the specified target.
 #
-# Path to linker command file stored in a global property is applied.
+# Path to linker command file, macro definitions and include paths stored in
+# global properties are applied.
 #
 # Note:
-#	- Directory property name must follow a specific scheme.
-#	- This is an internal function.
+#  - Directory property names must follow a specific scheme.
+#  - This is an internal function.
 #
-# See: embedded_set_target_linker_file()
+# See: embedded_set_target_linker_file(), embedded_set_target_link_includes()
+#      embedded_set_target_link_defines()
 #
 #Examples:
 #  _embedded_apply_linker_cmd_file_setting(my_app)
 #
 #INPUTS:
-#   TARGET  - (mandatory) 			- The target to apply settings to.
-#	Directory property - (optional) - Flags to apply.
+#   TARGET  - (mandatory) - The target to apply settings to.
+#   Directory properties
 #
 #OUTPUTS
 #    n/a
 #
 function(_embedded_apply_linker_cmd_file_setting TARGET)
 	#Check if the parameter is a target.
-  	if(NOT TARGET ${TARGET})
+	if(NOT TARGET ${TARGET})
 		message(FATAL_ERROR "_embedded_apply_linker_cmd_file_setting(): target '${TARGET}' is not defined.")
 	endif()
 	#Check if target is an executable.
@@ -648,6 +722,9 @@
 	endif()
 	#Get the path to the linker command file.
 	get_property(_LINKER_CMD_FILE GLOBAL PROPERTY EMBEDDED_LINKER_CMD_FILE_${TARGET})
-	#Set the path
-	compiler_set_linkercmdfile(${TARGET} ${_LINKER_CMD_FILE})
+
+	#Get macro defines and include paths set for the target.
+	get_property(_LINKER_DEFINES GLOBAL PROPERTY EMBEDDED_LINKER_DEFINES_${TARGET})
+	get_property(_LINKER_INCLUDES GLOBAL PROPERTY EMBEDDED_LINKER_INCLUDES_${TARGET})
+	compiler_set_linkercmdfile(TARGET ${TARGET} PATH ${_LINKER_CMD_FILE} DEFINES ${_LINKER_DEFINES} INCLUDES ${_LINKER_INCLUDES})
 endfunction()
diff --git a/cmake/Common/CompilerArmClangCommon.cmake b/cmake/Common/CompilerArmClangCommon.cmake
index bf8bc29..87565f3 100644
--- a/cmake/Common/CompilerArmClangCommon.cmake
+++ b/cmake/Common/CompilerArmClangCommon.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2017, Arm Limited. All rights reserved.
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -61,12 +61,44 @@
 	include(Compiler/ARMClang-ASM)
 endif()
 
-function(compiler_set_linkercmdfile TARGET FILE_PATH)
+function(compiler_set_linkercmdfile)
+	set( _OPTIONS_ARGS )							#Option (on/off) arguments.
+	set( _ONE_VALUE_ARGS TARGET PATH)				#Single option arguments.
+	set( _MULTI_VALUE_ARGS DEFINES INCLUDES)		#List arguments
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+
+	#Check passed parameters
+	if(NOT _MY_PARAMS_TARGET)
+		message(FATAL_ERROR "compiler_set_linkercmdfile: mandatory parameter 'TARGET' is missing.")
+	endif()
+	if (NOT TARGET ${_MY_PARAMS_TARGET})
+		message(FATAL_ERROR "compiler_set_linkercmdfile: value of parameter 'TARGET' is invalid.")
+	endif()
+
+	if(NOT _MY_PARAMS_PATH)
+		message(FATAL_ERROR "compiler_set_linkercmdfile: mandatory parameter 'PATH' is missing.")
+	endif()
+	set(_FILE_PATH ${_MY_PARAMS_PATH})
+
+	#Compose additional command line switches from macro definitions.
+	set(_FLAGS "")
+	if (_MY_PARAMS_DEFINES)
+		foreach(_DEFINE IN LISTS _MY_PARAMS_DEFINES)
+			string(APPEND _FLAGS " --predefine=\"-D${_DEFINE}\"")
+		endforeach()
+	endif()
+	#Compose additional command line switches from include paths.
+	if (_MY_PARAMS_INCLUDES)
+		foreach(_INCLUDE_P IN LISTS _MY_PARAMS_INCLUDES)
+			string(APPEND _FLAGS " -I ${_INCLUDE_P}")
+		endforeach()
+	endif()
+
 	#Note: the space before the option is important!
-	set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " --scatter=${FILE_PATH}")
-	set_property(TARGET ${TARGET} APPEND PROPERTY LINK_DEPENDS ${FILE_PATH})
+	set_property(TARGET ${_MY_PARAMS_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " ${_FLAGS} --scatter=${_FILE_PATH}")
+	set_property(TARGET ${_MY_PARAMS_TARGET} APPEND PROPERTY LINK_DEPENDS ${_FILE_PATH})
 	#Tell cmake .map files shall be removed when project is cleaned (make clean)
-	get_filename_component(_TARGET_BASE_NAME ${TARGET} NAME_WE)
+	get_filename_component(_TARGET_BASE_NAME ${_MY_PARAMS_TARGET} NAME_WE)
 	get_directory_property(_ADDITIONAL_MAKE_CLEAN_FILES DIRECTORY "./" ADDITIONAL_MAKE_CLEAN_FILES)
 	set_directory_properties(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_ADDITIONAL_MAKE_CLEAN_FILES} ${_TARGET_BASE_NAME}.map")
 endfunction()
diff --git a/cmake/Common/CompilerDetermineC.cmake b/cmake/Common/CompilerDetermineC.cmake
index 0f6000f..a429120 100644
--- a/cmake/Common/CompilerDetermineC.cmake
+++ b/cmake/Common/CompilerDetermineC.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2017, Arm Limited. All rights reserved.
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -25,8 +25,8 @@
 	set(CMAKE_C_COMPILER_ID "ARMCLANG" CACHE INTERNAL "C compiler ID" FORCE)
 	set(ARM_TOOLCHAIN_FILE "Compiler/ARMClang-C")
 elseif (_C_COMPILER_NAME MATCHES "^.*gcc(\\.exe)?$")
-	set(CMAKE_C_COMPILER_ID "GNU" CACHE INTERNAL "C compiler ID" FORCE)
-	set(ARM_TOOLCHAIN_FILE "Compiler/GNU-C")
+	set(CMAKE_C_COMPILER_ID "GNUARM" CACHE INTERNAL "C compiler ID" FORCE)
+	set(ARM_TOOLCHAIN_FILE "Compiler/GNUARM-C")
 elseif (_C_COMPILER_NAME MATCHES "^.*iccarm(\\.exe)?$")
 	set(CMAKE_C_COMPILER_ID "IAR" CACHE INTERNAL "C compiler ID" FORCE)
 	set(ARM_TOOLCHAIN_FILE "Compiler/IAR-C")
diff --git a/cmake/Common/CompilerDetermineCXX.cmake b/cmake/Common/CompilerDetermineCXX.cmake
index d6461c1..6d1f142 100644
--- a/cmake/Common/CompilerDetermineCXX.cmake
+++ b/cmake/Common/CompilerDetermineCXX.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2017, Arm Limited. All rights reserved.
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -24,8 +24,8 @@
 	set(CMAKE_CXX_COMPILER_ID "ARMCLANG" CACHE INTERNAL "C++ compiler ID" FORCE)
 	set(ARM_TOOLCHAIN_FILE "Compiler/ARMClang-CXX")
 elseif (_CXX_COMPILER_NAME MATCHES "^.*gcc(\\.exe)?$")
-	set(CMAKE_CXX_COMPILER_ID "GNU" CACHE INTERNAL "C++ compiler ID" FORCE)
-	set(ARM_TOOLCHAIN_FILE "Compiler/GNU-CXX")
+	set(CMAKE_CXX_COMPILER_ID "GNUARM" CACHE INTERNAL "C++ compiler ID" FORCE)
+	set(ARM_TOOLCHAIN_FILE "Compiler/GNUARM-CXX")
 elseif (_CXX_COMPILER_NAME MATCHES "^.*iccarm(\\.exe)?$")
 	set(CMAKE_CXX_COMPILER_ID "IAR" CACHE INTERNAL "C++ compiler ID" FORCE)
 	set(ARM_TOOLCHAIN_FILE "Compiler/IAR-CXX")
diff --git a/cmake/Common/CompilerGNUARM63.cmake b/cmake/Common/CompilerGNUARM63.cmake
new file mode 100644
index 0000000..81c25bc
--- /dev/null
+++ b/cmake/Common/CompilerGNUARM63.cmake
@@ -0,0 +1,63 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#This file contains settings to specify how GCC shall be used
+
+#Include some dependencies
+Include(Common/CompilerGNUARMCommon)
+Include(Common/Utils)
+
+check_gnuarm_input_vars("6.3")
+
+if(NOT DEFINED ARM_CPU_ARHITECTURE)
+	set(_NO_ARM_CPU_ARHITECTURE true)
+elseif (${ARM_CPU_ARHITECTURE} STREQUAL "ARM8-M-BASE")
+	string_append_unique_item(STRING CMAKE_C_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.base")
+	string_append_unique_item(STRING CMAKE_CXX_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.base")
+	string_append_unique_item(STRING CMAKE_ASM_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.base")
+	string_append_unique_item(STRING CMAKE_LINK_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.base")
+elseif(${ARM_CPU_ARHITECTURE} STREQUAL "ARM8-M-MAIN")
+	string_append_unique_item(STRING CMAKE_C_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.main")
+	string_append_unique_item(STRING CMAKE_CXX_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.main")
+	string_append_unique_item(STRING CMAKE_ASM_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.main")
+	string_append_unique_item(STRING CMAKE_LINK_FLAGS_CPU KEY "-march=" VAL "-march=armv8-m.main")
+elseif(${ARM_CPU_ARHITECTURE} STREQUAL "V7-M")
+	string_append_unique_item(STRING CMAKE_C_FLAGS_CPU KEY "-march=" VAL "-march=armv7-m")
+	string_append_unique_item(STRING CMAKE_CXX_FLAGS_CPU KEY "-march=" VAL "-march=armv7-m")
+	string_append_unique_item(STRING CMAKE_ASM_FLAGS_CPU KEY "-march=" VAL "-march=armv7-m")
+	string_append_unique_item(STRING CMAKE_LINK_FLAGS_CPU KEY "-march=" VAL "-march=armv7-m")
+else()
+	message(FATAL_ERROR "Unknown or unsupported ARM cpu architecture setting.")
+endif()
+
+#Prefer arhitecture definition over cpu type.
+if(NOT DEFINED ARM_CPU_ARHITECTURE)
+	if(NOT DEFINED ARM_CPU_TYPE)
+		string_append_unique_item(_NO_ARM_CPU_TYPE true)
+	elseif(${ARM_CPU_TYPE} STREQUAL "Cortex-M3")
+		string_append_unique_item (CMAKE_C_FLAGS_CPU "-mcpu=cortex-m3")
+		string_append_unique_item (CMAKE_CXX_FLAGS_CPU "-mcpu=cortex-m3")
+		string_append_unique_item (CMAKE_ASM_FLAGS_CPU "--cpu=Cortex-M3")
+		string_append_unique_item (CMAKE_LINK_FLAGS_CPU "--cpu=Cortex-M3")
+	elseif(${ARM_CPU_TYPE} STREQUAL "Cortex-M33")
+		string_append_unique_item (CMAKE_C_FLAGS_CPU "-mcpu=cortex-m33")
+		string_append_unique_item (CMAKE_CXX_FLAGS_CPU "-mcpu=cortex-m33")
+		string_append_unique_item (CMAKE_ASM_FLAGS_CPU "--cpu=Cortex-M33")
+		string_append_unique_item (CMAKE_LINK_FLAGS_CPU "--cpu=Cortex-M33")
+	elseif(${ARM_CPU_TYPE} STREQUAL "Cortex-M23")
+		string_append_unique_item (CMAKE_C_FLAGS_CPU "-mcpu=cortex-m23")
+		string_append_unique_item (CMAKE_CXX_FLAGS_CPU "-mcpu=cortex-m23")
+		string_append_unique_item (CMAKE_ASM_FLAGS_CPU "--cpu=Cortex-M23")
+		string_append_unique_item (CMAKE_LINK_FLAGS_CPU "--cpu=Cortex-M23")
+	else()
+		message(FATAL_ERROR "Unknown ARM cpu setting.")
+	endif()
+endif()
+
+if (_NO_ARM_CPU_TYPE AND _NO_ARM_CPU_ARHITECTURE)
+	message(FATAL_ERROR "Cannot set CPU specific compiler flags: neither the ARM CPU type nor the architecture is set.")
+endif()
diff --git a/cmake/Common/CompilerGNUARMCommon.cmake b/cmake/Common/CompilerGNUARMCommon.cmake
new file mode 100644
index 0000000..c4be8ba
--- /dev/null
+++ b/cmake/Common/CompilerGNUARMCommon.cmake
@@ -0,0 +1,172 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#This file contains settings to specify how GNUARM shall be used
+
+function(check_gnuarm_input_vars MY_VERSION)
+	#Specify where gnuarm is
+	if (NOT DEFINED GNUARM_PATH)
+		message(FATAL_ERROR "Please set GNUARM_PATH to the root directory of the gnuarm installation. e.g. set(GNUARM_PATH \"C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/\"")
+	endif()
+
+	STRING(REGEX REPLACE "([0-9]+).([0-9]+).*" "\\1.\\2" _MY_MAJOR_MINOR "${MY_VERSION}")
+	STRING(REGEX REPLACE "([0-9]+).([0-9]+).*" "\\1.\\2" _GNUARM_MAJOR_MINOR "${GNUARM_VER}")
+
+	#Check gnuarm version.
+	if (NOT "${_MY_MAJOR_MINOR}" VERSION_EQUAL "${_GNUARM_MAJOR_MINOR}")
+		message(FATAL_ERROR "GNUARM version (GNUARM_VER=${GNUARM_VER}) does not match ${MY_VERSION}")
+	endif()
+
+	if (NOT DEFINED ARM_CPU_ARHITECTURE AND NOT DEFINED ARM_CPU_TYPE)
+		message(FATAL_ERROR "ARM_CPU_TYPE and ARM_CPU_ARHITECTURE is not defined! Please include the CPU specific config file before this one.")
+	endif()
+
+endfunction()
+
+message(STATUS "Using gcc compiler package v${GNUARM_VER} from ${GNUARM_PATH}")
+
+
+#Tell cmake which compiler we use
+if (EXISTS "c:/")
+	set (CMAKE_C_COMPILER "${GNUARM_PATH}/bin/arm-none-eabi-gcc.exe")
+	set (CMAKE_CXX_COMPILER "${GNUARM_PATH}/bin/arm-none-eabi-g++.exe")
+	set (CMAKE_ASM_COMPILER "${GNUARM_PATH}/bin/arm-none-eabi-gcc.exe")
+else()
+	set (CMAKE_C_COMPILER "${GNUARM_PATH}/bin/arm-none-eabi-gcc")
+	set (CMAKE_CXX_COMPILER "${GNUARM_PATH}/bin/arm-none-eabi-g++")
+	set (CMAKE_ASM_COMPILER "${GNUARM_PATH}/bin/arm-none-eabi-gcc")
+endif()
+
+if("CXX" IN_LIST languages)
+	set(CMAKE_CXX_COMPILER_ID "GNUARM" CACHE INTERNAL "CXX compiler ID" FORCE)
+	include(Compiler/GNUARM-CXX)
+endif()
+
+if("C" IN_LIST languages)
+	set(CMAKE_C_COMPILER_ID "GNUARM" CACHE INTERNAL "C compiler ID" FORCE)
+	include(Compiler/GNUARM-C)
+endif()
+
+if("ASM" IN_LIST languages)
+	set(CMAKE_C_COMPILER_ID "GNUARM" CACHE INTERNAL "ASM compiler ID" FORCE)
+	include(Compiler/GNUARM-ASM)
+endif()
+
+function(compiler_set_linkercmdfile)
+	set( _OPTIONS_ARGS )							#Option (on/off) arguments.
+	set( _ONE_VALUE_ARGS TARGET PATH)				#Single option arguments.
+	set( _MULTI_VALUE_ARGS DEFINES INCLUDES)		#List arguments
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+
+	#Check passed parameters
+	if(NOT _MY_PARAMS_TARGET)
+		message(FATAL_ERROR "compiler_set_linkercmdfile: mandatory parameter 'TARGET' is missing.")
+	endif()
+	if (NOT TARGET ${_MY_PARAMS_TARGET})
+		message(FATAL_ERROR "compiler_set_linkercmdfile: value of parameter 'TARGET' is invalid.")
+	endif()
+
+	if(NOT _MY_PARAMS_PATH)
+		message(FATAL_ERROR "compiler_set_linkercmdfile: mandatory parameter 'PATH' is missing.")
+	endif()
+	set(_FILE_PATH ${_MY_PARAMS_PATH})
+
+	#Compose additional command line switches from macro definitions.
+	set(_FLAGS "")
+	if (_MY_PARAMS_DEFINES)
+		foreach(_DEFINE IN LISTS _MY_PARAMS_DEFINES)
+			list(APPEND _FLAGS "-D ${_DEFINE}")
+		endforeach()
+	endif()
+	#Compose additional command line switches from include paths.
+	if (_MY_PARAMS_INCLUDES)
+		foreach(_INCLUDE_P IN LISTS _MY_PARAMS_INCLUDES)
+			list(APPEND _FLAGS "-I ${_INCLUDE_P}")
+		endforeach()
+	endif()
+
+	#Create additional target if linker script needs to be pre-processed.
+	if (_MY_PARAMS_DEFINES OR _MY_PARAMS_INCLUDES)
+		#Name of pre-processed linker script file.
+		get_filename_component(FINAL_LD_FILE_NAME ${_MY_PARAMS_PATH} NAME)
+		set(FINAL_LD_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${FINAL_LD_FILE_NAME}.i")
+		#Name of the target doing the pre-processing
+		set(LD_PP_TARGET_NAME "${_MY_PARAMS_TARGET}_ldpp")
+		#The target definition.
+		add_custom_target(${LD_PP_TARGET_NAME}
+			COMMENT "Pre-processing linker command file ${_MY_PARAMS_PATH}..."
+			COMMAND ${CMAKE_C_COMPILER} -E -P -xc ${_FLAGS} -o ${FINAL_LD_FILE_NAME} ${_MY_PARAMS_PATH}
+			DEPENDS ${_MY_PARAMS_PATH}
+			BYPRODUCTS ${FINAL_LD_FILE_NAME}
+		)
+		#Make the original target depend on the new one.
+		add_dependencies(${_MY_PARAMS_TARGET} ${LD_PP_TARGET_NAME})
+		#Tell cmake to delete the intermediate linker script when the clean rule
+		#is executed.
+		get_directory_property(_ADDITIONAL_MAKE_CLEAN_FILES DIRECTORY "./" ADDITIONAL_MAKE_CLEAN_FILES)
+		set_directory_properties(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_ADDITIONAL_MAKE_CLEAN_FILES} ${FINAL_LD_FILE_NAME}")
+		#Set the path to linker script point to the intermediate file.
+		set(_FILE_PATH ${FINAL_LD_FILE_NAME})
+	endif()
+
+	#Note: the space before the option is important!
+	set_property(TARGET ${_MY_PARAMS_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -T${_FILE_PATH}")
+	set_property(TARGET ${_MY_PARAMS_TARGET} APPEND PROPERTY LINK_DEPENDS ${_FILE_PATH})
+	#Tell cmake .map files shall be removed when project is cleaned (make clean)
+	get_filename_component(_TARGET_BASE_NAME ${_MY_PARAMS_TARGET} NAME_WE)
+	get_directory_property(_ADDITIONAL_MAKE_CLEAN_FILES DIRECTORY "./" ADDITIONAL_MAKE_CLEAN_FILES)
+	set_directory_properties(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_ADDITIONAL_MAKE_CLEAN_FILES} ${_TARGET_BASE_NAME}.map")
+endfunction()
+
+function(compiler_set_cmse_output TARGET FILE_PATH)
+	#Note: the space before the option is important!
+	set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--cmse-implib,--out-implib=${FILE_PATH}")
+	#Tell cmake cmse output is a generated object file.
+	SET_SOURCE_FILES_PROPERTIES("${FILE_PATH}" PROPERTIES EXTERNAL_OBJECT true GENERATED true)
+	#Tell cmake cmse output shall be removed by clean target.
+	get_directory_property(_ADDITIONAL_MAKE_CLEAN_FILES DIRECTORY "./" ADDITIONAL_MAKE_CLEAN_FILES)
+	set_directory_properties(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_ADDITIONAL_MAKE_CLEAN_FILES} ${FILE_PATH}")
+endfunction()
+
+function(compiler_merge_library)
+	set( _OPTIONS_ARGS )			#Option (on/off) arguments.
+	set( _ONE_VALUE_ARGS DEST)		#Single option arguments.
+	set( _MULTI_VALUE_ARGS LIBS)	#List arguments
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+
+	#Check passed parameters
+	if(NOT _MY_PARAMS_DEST)
+		message(FATAL_ERROR "compiler_merge_library: no destination target specified. Please see the DEST parameter.")
+	endif()
+	#Check if destination is a library
+	get_target_property(_tmp ${_MY_PARAMS_DEST} TYPE)
+	if(NOT "${_tmp}" STREQUAL "STATIC_LIBRARY")
+		message(FATAL_ERROR "compiler_merge_library: parameter DEST must be a static library target.")
+	endif()
+	set(_DEST ${_MY_PARAMS_DEST})
+
+	if(NOT _MY_PARAMS_LIBS)
+		message(FATAL_ERROR "compiler_merge_library: no source libraries specified. Please see the LIBS parameter.")
+	endif()
+	set(_LIBS ${_MY_PARAMS_LIBS})
+
+	##Find the cmake script doing the merge.
+	find_file(_MERGE_SCRIPT "GNUArMerge.cmake" PATHS ${CMAKE_MODULE_PATH} PATH_SUFFIXES Common NO_DEFAULT_PATH)
+
+ 	#Now add a custom command for each source library to our custom target to
+ 	#merge into the destination.
+	foreach(SRC_LIB ${_LIBS})
+		get_filename_component(_SRC_LIB_NAME "${SRC_LIB}"  NAME)
+		add_custom_command(TARGET ${_DEST} POST_BUILD
+			COMMAND ${CMAKE_COMMAND} -DCMAKE_AR=${CMAKE_AR} -DSOURCE=${SRC_LIB} -DDESTINATION=$<TARGET_FILE:${_DEST}> -P ${_MERGE_SCRIPT}
+			COMMENT "\t\tmerging objects from ${_SRC_LIB_NAME}")
+	endforeach()
+endfunction()
+
+function(compiler_generate_binary_output TARGET)
+	add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_GNUARM_OBJCOPY} ARGS -O binary $<TARGET_FILE:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.bin)
+endfunction()
diff --git a/cmake/Common/FindGNUARM.cmake b/cmake/Common/FindGNUARM.cmake
new file mode 100644
index 0000000..274bbc1
--- /dev/null
+++ b/cmake/Common/FindGNUARM.cmake
@@ -0,0 +1,152 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#Find the location of the GNUARM C/C++ compiler.
+#
+# Find gnuarm on the specified location or on the PATH and optionally validate
+# its version.
+#
+#Inputs:
+#  GNUARM_PATH - (optional)- install path of GNUARM compiler to use. If not set
+#                the compiler on the PATH is used.
+#  GNUARM_VER  - (optional)- version number. If set the module will validate
+#                the compiler version.
+#
+#outputs:
+#  GNUARM_PATH   - will be set to the root directory of the compiler. Only set
+#                  if undefined.
+#  GNUARM_VER    - will be set to the version number found. Only set if
+#                  undefined.
+#  GNUARM_MODULE - set to the name of the cmake module to be included for this
+#                  GNUARM version.
+#
+
+#Include some dependencies
+Include(Common/Utils)
+
+set(_GCC_BINARY_NAME "arm-none-eabi-gcc")
+
+#Get the version of armgcc.
+#
+# Execute gcc and extract the version number for its output.
+#
+#Examples:
+#  Get the version reported by gcc at location c:/foo/bin/ to
+#  variable VER get_armgcc_version(GCC "c:/foo/bin/arm-none-eabi-gcc" RES VER)
+#
+#INPUTS:
+#  GCC  - (mandatory) - gcc executable
+#  RES  - (mandatory) - variable name to put result to
+#
+#OUTPUTS
+#    The variable named after "RES" will be set to the version number
+#
+function(get_armgcc_version)
+	###Parse our arguments
+	#No option (on/off) arguments (e.g. IGNORE_CASE)
+	set( _OPTIONS_ARGS )
+	#Single option arguments (e.g. PATH "./foo/bar")
+	set( _ONE_VALUE_ARGS GCC RES)
+	#List arguments (e.g. LANGUAGES C ASM CXX)
+	set( _MULTI_VALUE_ARGS )
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}"
+									"${_ONE_VALUE_ARGS}"
+									 "${_MULTI_VALUE_ARGS}"
+									  ${ARGN} )
+
+	#Check mandatory parameters
+	if(NOT _MY_PARAMS_RES)
+		message (FATAL_ERROR "get_armgcc_version(): Missing result parameter!")
+	endif()
+	set (_RES ${_MY_PARAMS_RES})
+
+	if(NOT _MY_PARAMS_GCC)
+		message (FATAL_ERROR "get_armgcc_version(): Missing GCC parameter!")
+	endif()
+	set (_GCC ${_MY_PARAMS_GCC})
+
+	#Call specified executable
+	execute_process(COMMAND "${_GCC}" -v
+					OUTPUT_VARIABLE _OUTPUT
+					ERROR_VARIABLE _OUTPUT
+					)
+	#Cut off version number. Just the numbers ignore anything after.
+	STRING(REGEX REPLACE  ".*gcc version ([0-9.]+) .*" "\\1" _VER "${_OUTPUT}")
+
+	if (NOT _VER)
+		string(CONCAT _msg "get_armgcc_version(): Failed to extract version"
+							" number from ${_GCC_BINARY_NAME} output.")
+		message (FATAL_ERROR "${_msg}")
+	endif()
+
+	set(${_RES} ${_VER} PARENT_SCOPE)
+endfunction()
+
+#Check if the executable is present
+if(NOT DEFINED GNUARM_PATH)
+	#If the location is not set, try to find executable on PATH.
+	#Set GNUARM_PATH to default value.
+	set (GNUARM_PATH "GNUARM_PATH-NOTFOUND")
+
+	#First check if gcc is on the PATH
+	#find_program puts() its output to the cmake cache. We don't want that, so
+	# we use a local variable, which is unset later.
+	find_program (
+	  _GNUARM_PATH
+	  ${_GCC_BINARY_NAME}
+	  PATHS env PATH
+	  DOC "GNUARM compiler location."
+	)
+else()
+	#Check executable is available on the specified path.
+	#find_program puts() its output to the cmake cache. We don't want that, so
+	# we use a local variable, which is unset later.
+	find_program (
+	  _GNUARM_PATH
+	  ${_GCC_BINARY_NAME}
+	  PATHS ${GNUARM_PATH}
+	  DOC "GNUARM compiler location."
+	)
+endif()
+
+#Is executable present?
+if(_GNUARM_PATH STREQUAL "_GNUARM_PATH-NOTFOUND")
+	string(CONCAT _msg "${_GCC_BINARY_NAME} can not be found. Either put"
+						" ${_GCC_BINARY_NAME} on the PATH or set GNUARM_PATH"
+						" properly.")
+	message (FATAL_ERROR ${_msg})
+endif()
+
+#Cut off executable and directory name to get install location.
+STRING(REGEX REPLACE "(.*)/bin/${_GCC_BINARY_NAME}.*"
+						"\\1" GNUARM_PATH "${_GNUARM_PATH}")
+
+#Remove unwanted junk from CMake cache.
+unset(_GNUARM_PATH CACHE)
+
+get_armgcc_version(GCC "${GNUARM_PATH}/bin/${_GCC_BINARY_NAME}" RES _VER)
+
+#Check the version if needed
+if(NOT DEFINED GNUARM_VER)
+	set(GNUARM_VER ${_VER})
+endif()
+
+if(NOT "${GNUARM_VER}" VERSION_EQUAL "${_VER}")
+	string(CONCAT _msg "FindGNUARM.cmake: ${_GCC_BINARY_NAME} compiler version"
+						" ${_VER} does not match ${GNUARM_VER}.")
+	message (FATAL_ERROR "${_msg}")
+endif()
+
+
+STRING(REGEX REPLACE "([0-9]+)\.([0-9]+)(\.[0-9]+)*.*" "CompilerGNUARM\\1\\2"
+						 GNUARM_MODULE "${GNUARM_VER}")
+
+if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${GNUARM_MODULE}.cmake")
+	string(CONCAT _msg "ERROR: Unsupported GNUARM compiler version found on"
+						" PATH.")
+	message(FATAL_ERROR "${_msg}")
+endif()
diff --git a/cmake/Common/GNUArMerge.cmake b/cmake/Common/GNUArMerge.cmake
new file mode 100644
index 0000000..8631e6c
--- /dev/null
+++ b/cmake/Common/GNUArMerge.cmake
@@ -0,0 +1,120 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#A cmake script to merge two archives using GNU AR.
+#
+# The script will first run AR to get the list of files in the source archive.
+# Then each file is:
+#   -extracted
+#   -added to the target archive
+#   -deleted
+#
+# The loop is needed to avoid losing files with matching name in the source
+# archive.
+# The destination archive is updated in a way not to overwrite existing files
+# with matching names.
+#
+#Examples:
+#  cmake -DCMAKE_AR=arm-none-eabi-ar -DDESTINATION=new_lib.a -DSOURCE=/foo/bar/old_lib.a -P ./GNUArMerge.cmake
+#
+#Parameters:
+#  SOURCE      - archive file to copy all members from
+#  DESTINATION - archive file to copy members to. If file exists, then new
+#                members are added without overwriting existing ones.
+#  CMAKE_AR    - GNU AR executable
+#
+
+#Execute AR and capture its output
+#
+# Script execution will stop with a fatal error if AR execution fails.
+#
+#Examples:
+#  List content of archive:
+#    run_ar(RESULT t /foo/bar/my_lib.a)
+#  Add object file to archive
+#    run_ar(RESULT q /foo/bar/my_lib.a new_obj.o)
+#
+#INPUTS:
+#    RESULT - (mandatory) - name of variable to put result in
+#    All remaining parameters will be command line options to AR
+#
+#OUTPUTS
+#    RESULT - text output of AR command
+#
+function(run_ar OUTPUT )
+	execute_process(COMMAND ${CMAKE_AR} ${ARGN}
+					TIMEOUT 120
+					OUTPUT_VARIABLE _RES
+					RESULT_VARIABLE _STATUS_CODE
+					OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+	if (STATUS_CODE GREATER 0)
+		message(FATAL_ERROR "ERROR: Failed to execute \"${CMAKE_AR} ${ARGN}\".")
+	endif()
+	set(${OUTPUT} ${_RES} PARENT_SCOPE)
+endfunction()
+
+#Delete a file
+#
+# Function to delete a file. No error will be reported if file is missing.
+# Script execution will stop with a fatal error if AR execution fails.
+#
+#Examples:
+#  rm(/foo/bar/my_lib.a)
+#
+#INPUTS:
+#    FILE - path to file to delete
+#
+#OUTPUTS
+#    N/A
+#
+function(rm FILE)
+	execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${FILE}
+					RESULT_VARIABLE _STATUS_CODE
+					TIMEOUT 120)
+	if (STATUS_CODE GREATER 0)
+		message(FATAL_ERROR "ERROR: Failed to execute \"${CMAKE_COMMAND} -E remove ${FILE}\".")
+	endif()
+endfunction()
+
+
+#############################################################################
+# Entry point
+#############################################################################
+#Verify input variables.
+
+if(NOT DEFINED SOURCE)
+	message(FATAL_ERROR "GNUArMerge.cmake: Variable SOURCE is not defined.")
+endif()
+
+if(NOT DEFINED DESTINATION)
+	message(FATAL_ERROR "GNUArMerge.cmake: Variable DESTINATION is not defined.")
+endif()
+
+if(NOT DEFINED CMAKE_AR)
+	message(FATAL_ERROR "GNUArMerge.cmake: Variable CMAKE_AR is not defined.")
+endif()
+
+
+#Get list of archive members
+run_ar("OBJ_LIST" t ${SOURCE})
+
+#Convert AR output to cmake list
+string(REPLACE "\n" ";" OBJ_LIST ${OBJ_LIST})
+
+#Iterate over member list.
+foreach(OBJ ${OBJ_LIST})
+	#Extract member
+	run_ar("_DUMMY" x ${SOURCE} ${OBJ})
+	#Add member to destination archive
+	run_ar("_DUMMY" q ${DESTINATION} ${OBJ})
+	#Remove extracted member
+	rm("${OBJ}")
+endforeach()
+
+#Update the symbol table
+run_ar("_DUMMY" s ${DESTINATION})
diff --git a/cmake/Compiler/GNUARM-ASM.cmake b/cmake/Compiler/GNUARM-ASM.cmake
new file mode 100644
index 0000000..b0261d9
--- /dev/null
+++ b/cmake/Compiler/GNUARM-ASM.cmake
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+include(Compiler/GNUARM)
+set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S;asm)
+__compiler_gnuarm(ASM)
diff --git a/cmake/Compiler/GNUARM-C.cmake b/cmake/Compiler/GNUARM-C.cmake
new file mode 100644
index 0000000..8d692d0
--- /dev/null
+++ b/cmake/Compiler/GNUARM-C.cmake
@@ -0,0 +1,9 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+include(Compiler/GNUARM)
+__compiler_gnuarm(C)
diff --git a/cmake/Compiler/GNUARM-CXX.cmake b/cmake/Compiler/GNUARM-CXX.cmake
new file mode 100644
index 0000000..93ec32f
--- /dev/null
+++ b/cmake/Compiler/GNUARM-CXX.cmake
@@ -0,0 +1,9 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+include(Compiler/GNUARM)
+__compiler_gnuarm(CXX)
diff --git a/cmake/Compiler/GNUARM.cmake b/cmake/Compiler/GNUARM.cmake
new file mode 100644
index 0000000..6305436
--- /dev/null
+++ b/cmake/Compiler/GNUARM.cmake
@@ -0,0 +1,48 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+if(_GNUARM_CMAKE_LOADED)
+  return()
+endif()
+set(_GNUARM_CMAKE_LOADED TRUE)
+
+get_filename_component(_CMAKE_C_TOOLCHAIN_LOCATION "${CMAKE_C_COMPILER}" PATH)
+get_filename_component(_CMAKE_CXX_TOOLCHAIN_LOCATION "${CMAKE_CXX_COMPILER}" PATH)
+
+set(CMAKE_EXECUTABLE_SUFFIX ".axf")
+
+find_program(CMAKE_GNUARM_LINKER  arm-none-eabi-gcc     HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+find_program(CMAKE_GNUARM_AR      arm-none-eabi-ar      HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+find_program(CMAKE_GNUARM_OBJCOPY arm-none-eabi-objcopy HINTS "${_CMAKE_C_TOOLCHAIN_LOCATION}" "${_CMAKE_CXX_TOOLCHAIN_LOCATION}" )
+
+set(CMAKE_LINKER "${CMAKE_GNUARM_LINKER}" CACHE FILEPATH "The GNUARM linker" FORCE)
+mark_as_advanced(CMAKE_GNUARM_LINKER)
+set(CMAKE_AR "${CMAKE_GNUARM_AR}" CACHE FILEPATH "The GNUARM archiver" FORCE)
+mark_as_advanced(CMAKE_GNUARM_AR)
+
+macro(__compiler_gnuarm lang)
+  if(NOT CMAKE_${lang}_FLAGS_SET)
+    set(CMAKE_${lang}_FLAGS_SET TRUE)
+    string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+    string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -O0")
+    string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG")
+    string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+    string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O3 -g")
+
+    set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
+    set(CMAKE_${lang}_OUTPUT_EXTENSION_REPLACE 1)
+    set(CMAKE_STATIC_LIBRARY_PREFIX_${lang} "")
+    set(CMAKE_STATIC_LIBRARY_SUFFIX_${lang} ".a")
+
+    set(CMAKE_${lang}_LINK_EXECUTABLE      "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> -o <TARGET> -Xlinker -Map=<TARGET_BASE>.map")
+    set(CMAKE_${lang}_CREATE_STATIC_LIBRARY  "<CMAKE_AR> rsc <TARGET> <LINK_FLAGS> <OBJECTS>")
+    set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+    set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+    set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEPFILE> --depend_single_line --no_depend_system_headers")
+  endif()
+endmacro()
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index 68beb5d..4edda4f 100755
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -13,15 +13,28 @@
 set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR})
 
 #Specify the location of platform specific build dependencies.
-set (BL2_SCATTER_FILE_NAME "${PLATFORM_DIR}/target/mps2/an521/armclang/mps2_an521_bl2.sct")
-set (S_SCATTER_FILE_NAME   "${PLATFORM_DIR}/target/mps2/an521/armclang/mps2_an521_s.sct")
-set (NS_SCATTER_FILE_NAME  "${PLATFORM_DIR}/target/mps2/an521/armclang/mps2_an521_ns.sct")
+#FIXME use CMAKE_C_COMPILER_ID here instead?
+if(COMPILER STREQUAL "ARMCLANG")
+    set (BL2_SCATTER_FILE_NAME "${PLATFORM_DIR}/target/mps2/an521/armclang/mps2_an521_bl2.sct")
+    set (S_SCATTER_FILE_NAME   "${PLATFORM_DIR}/target/mps2/an521/armclang/mps2_an521_s.sct")
+    set (NS_SCATTER_FILE_NAME  "${PLATFORM_DIR}/target/mps2/an521/armclang/mps2_an521_ns.sct")
+    if (DEFINED CMSIS_5_DIR)
+      # not all project defines CMSIS_5_DIR, only the ones that use it.
+      set (RTX_LIB_PATH "${CMSIS_5_DIR}/CMSIS/RTOS2/RTX/Library/ARM/RTX_V8MMN.lib")
+    endif()
+elseif(COMPILER STREQUAL "GNUARM")
+    set (BL2_SCATTER_FILE_NAME "${PLATFORM_DIR}/target/mps2/an521/gcc/mps2_an521_bl2.ld")
+    set (S_SCATTER_FILE_NAME   "${PLATFORM_DIR}/target/mps2/an521/gcc/mps2_an521_s.ld")
+    set (NS_SCATTER_FILE_NAME  "${PLATFORM_DIR}/target/mps2/an521/gcc/mps2_an521_ns.ld")
+    if (DEFINED CMSIS_5_DIR)
+      # not all project defines CMSIS_5_DIR, only the ones that use it.
+      set (RTX_LIB_PATH "${CMSIS_5_DIR}/CMSIS/RTOS2/RTX/Library/GCC/libRTX_V8MMN.a")
+    endif()
+else()
+    message(FATAL_ERROR "No startup file is available for compiler '${CMAKE_C_COMPILER_ID}'.")
+endif()
 set (FLASH_LAYOUT          "${PLATFORM_DIR}/target/mps2/an521/partition/flash_layout.h")
 set (SIGN_BIN_SIZE         0x100000)
-if (DEFINED CMSIS_5_DIR)
-  # not all project defines CMSIS_5_DIR, only the ones that use it.
-  set (RTX_LIB_PATH "${CMSIS_5_DIR}/CMSIS/RTOS2/RTX/Library/ARM/RTX_V8MMN.lib")
-endif()
 
 if (BL2)
   set (BL2_LINKER_CONFIG ${BL2_SCATTER_FILE_NAME})
@@ -81,6 +94,10 @@
     list(APPEND ALL_SRC_ASM_S "${PLATFORM_DIR}/target/mps2/an521/armclang/startup_cmsdk_mps2_an521_s.s")
     list(APPEND ALL_SRC_ASM_NS "${PLATFORM_DIR}/target/mps2/an521/armclang/startup_cmsdk_mps2_an521_ns.s")
     list(APPEND ALL_SRC_ASM_BL2 "${PLATFORM_DIR}/target/mps2/an521/armclang/startup_cmsdk_mps2_an521_bl2.s")
+  elseif(CMAKE_C_COMPILER_ID STREQUAL "GNUARM")
+    list(APPEND ALL_SRC_ASM_S "${PLATFORM_DIR}/target/mps2/an521/gcc/startup_cmsdk_mps2_an521_s.S")
+    list(APPEND ALL_SRC_ASM_NS "${PLATFORM_DIR}/target/mps2/an521/gcc/startup_cmsdk_mps2_an521_ns.S")
+    list(APPEND ALL_SRC_ASM_BL2 "${PLATFORM_DIR}/target/mps2/an521/gcc/startup_cmsdk_mps2_an521_bl2.S")
   else()
     message(FATAL_ERROR "No startup file is available for compiler '${CMAKE_C_COMPILER_ID}'.")
   endif()
diff --git a/secure_fw/CMakeLists.txt b/secure_fw/CMakeLists.txt
index a45b4c7..0e6fc23 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -76,36 +76,42 @@
 if (REGRESSION OR CORE_TEST)
 	#The test service veneers may not be referenced in the secure binary so the
 	#veneer objects are explicitly loaded from the secure tests library.
-	target_link_libraries(${PROJECT_NAME} tfm_storage $<TARGET_LINKER_FILE:tfm_secure_tests>\(*veneers.o\) tfm_secure_tests)
+	if(${COMPILER} STREQUAL "ARMCLANG")
+		target_link_libraries(${PROJECT_NAME} tfm_storage $<TARGET_LINKER_FILE:tfm_secure_tests>\(*veneers.o\) tfm_secure_tests)
+	elseif(${COMPILER} STREQUAL "GNUARM")
+		target_link_libraries(${PROJECT_NAME} -Wl,--whole-archive tfm_secure_tests -Wl,--no-whole-archive tfm_storage)
+	else()
+		message(FATAL_ERROR "unknown compiler" )
+	endif()
 else()
 	target_link_libraries(${PROJECT_NAME} tfm_storage)
 endif()
 
-set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS " --predefine=\"-DTFM_LVL=${TFM_LVL}\"")
+embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_LVL=${TFM_LVL}")
 
 if (NOT DEFINED TFM_PARTITION_TEST_CORE)
 	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_CORE is undefined. ")
 elseif (TFM_PARTITION_TEST_CORE)
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DTFM_PARTITION_TEST_CORE\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_PARTITION_TEST_CORE")
 endif()
 
 if (NOT DEFINED TFM_PARTITION_TEST_SST)
 	message(FATAL_ERROR "Incomplete build configuration: TFM_PARTITION_TEST_SST is undefined. ")
 elseif (TFM_PARTITION_TEST_SST)
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DTFM_PARTITION_TEST_SST\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_PARTITION_TEST_SST")
 endif()
 
 if (NOT DEFINED BL2)
 	message(FATAL_ERROR "Incomplete build configuration: BL2 is undefined. ")
 elseif (BL2)
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DBL2\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "BL2")
 endif()
 
 if(CORE_TEST)
 	embedded_set_target_compile_defines(TARGET ${PROJECT_NAME} LANGUAGE C DEFINES TFM_CORE_DEBUG TFM_PARTITION_TEST_CORE APPEND)
 	set(SECURE_AXF_DIR_PREFIX "${CMAKE_BINARY_DIR}/unit_test/")
 	set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SECURE_AXF_DIR_PREFIX})
-	set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS " --predefine=\"-DTFM_PARTITION_TEST_CORE\"")
+	embedded_set_target_link_defines(TARGET ${PROJECT_NAME} DEFINES "TFM_PARTITION_TEST_CORE")
 endif()
 
 #Generate binary file from axf