Clone of official tools

Files at this revision

API Documentation at this revision

Comitter:
Screamer@Y5070-M.virtuoso
Date:
Tue Jun 14 11:07:30 2016 +0100
Parent:
8:a8ac6ed29081
Child:
11:a1a7d92ae8f1
Commit message:
Updated tools based on latest live tools code

Changed in this revision

build.py Show annotated file Show diff for this revision Revisions of this file
build_api.py Show annotated file Show diff for this revision Revisions of this file
get_config.py Show annotated file Show diff for this revision Revisions of this file
make.py Show annotated file Show diff for this revision Revisions of this file
memap.py Show annotated file Show diff for this revision Revisions of this file
targets.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/config_test.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test01/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test01/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test02/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test02/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test03/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test03/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test04/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test04/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test05/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test05/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test06/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test06/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test06/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test06/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test07/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test07/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test07/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test07/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test08/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test08/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test08/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test08/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test09/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test09/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test09/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test09/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test10/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test10/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test10/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test10/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test11/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test11/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test11/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test12/lib1/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test12/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test12/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test12/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test13/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test13/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test13/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test14/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test14/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test15/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test15/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test16/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test16/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test16/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test16/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test17/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test17/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test17/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test17/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test18/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test18/lib2/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test18/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test18/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test19/mbed_app.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test19/test_data.py Show annotated file Show diff for this revision Revisions of this file
test/config_test/test20/lib1/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
test/config_test/test20/test_data.py Show annotated file Show diff for this revision Revisions of this file
toolchains/__init__.py Show annotated file Show diff for this revision Revisions of this file
--- a/build.py	Tue Jun 07 11:35:02 2016 +0100
+++ b/build.py	Tue Jun 14 11:07:30 2016 +0100
@@ -116,17 +116,17 @@
                       default=False,
                       help="Displays supported matrix of MCUs and toolchains")
 
+    parser.add_option('-f', '--filter',
+                      dest='general_filter_regex',
+                      default=None,
+                      help='For some commands you can use filter to filter out results')
+
     parser.add_option("", "--cppcheck",
                       action="store_true",
                       dest="cppcheck_validation",
                       default=False,
                       help="Forces 'cppcheck' static code analysis")
 
-    parser.add_option('-f', '--filter',
-                      dest='general_filter_regex',
-                      default=None,
-                      help='For some commands you can use filter to filter out results')
-
     parser.add_option("-j", "--jobs", type="int", dest="jobs",
                       default=0, help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)")
 
@@ -192,7 +192,7 @@
     if options.usb_host:
         libraries.append("usb_host")
     if options.dsp:
-        libraries.extend(["cmsis_dsp", "dsp"])
+        libraries.extend(["dsp"])
     if options.fat:
         libraries.extend(["fat"])
     if options.ublox:
@@ -233,7 +233,8 @@
                 tt_id = "%s::%s" % (toolchain, target)
                 try:
                     mcu = TARGET_MAP[target]
-                    lib_build_res = build_library(options.source_dir, options.build_dir, mcu, toolchain,
+                    if options.source_dir:
+                        lib_build_res = build_library(options.source_dir, options.build_dir, mcu, toolchain,
                                                     options=options.options,
                                                     extra_verbose=options.extra_verbose_notify,
                                                     verbose=options.verbose,
@@ -242,6 +243,16 @@
                                                     clean=options.clean,
                                                     archive=(not options.no_archive),
                                                     macros=options.macros)
+                    else:
+                        lib_build_res = build_mbed_libs(mcu, toolchain,
+                                                    options=options.options,
+                                                    extra_verbose=options.extra_verbose_notify,
+                                                    verbose=options.verbose,
+                                                    silent=options.silent,
+                                                    jobs=options.jobs,
+                                                    clean=options.clean,
+                                                    macros=options.macros)
+
                     for lib_id in libraries:
                         build_lib(lib_id, mcu, toolchain,
                                   options=options.options,
--- a/build_api.py	Tue Jun 07 11:35:02 2016 +0100
+++ b/build_api.py	Tue Jun 14 11:07:30 2016 +0100
@@ -19,13 +19,13 @@
 import tempfile
 import colorama
 
-
+from copy import copy
 from types import ListType
 from shutil import rmtree
 from os.path import join, exists, basename, abspath, normpath
 from os import getcwd, walk
 from time import time
-from copy import copy
+import fnmatch
 
 from tools.utils import mkdir, run_cmd, run_cmd_ext, NotSupportedException, ToolException
 from tools.paths import MBED_TARGETS_PATH, MBED_LIBRARIES, MBED_API, MBED_HAL, MBED_COMMON
@@ -128,7 +128,7 @@
 
     for path in src_paths:
         profile = get_build_profile(path)
-
+ 
     # If the configuration object was not yet created, create it now
     config = config or Config(target, src_paths)
 
@@ -210,9 +210,9 @@
             resources.objects.extend(objects)
 
         # Link Program
-        res, needed_update = toolchain.link_program(resources, build_path, name)
+        res, _ = toolchain.link_program(resources, build_path, name)
 
-        if report != None and needed_update:
+        if report != None:
             end = time()
             cur_result["elapsed_time"] = end - start
             cur_result["output"] = toolchain.get_output()
@@ -237,8 +237,6 @@
             if toolchain_output:
                 cur_result["output"] += toolchain_output
 
-            cur_result["output"] += str(e)
-
             add_result_to_report(report, cur_result)
 
         # Let Exception propagate
@@ -307,26 +305,43 @@
         toolchain.info("Building library %s (%s, %s)" % (name, target.name, toolchain_name))
 
         # Scan Resources
-        resources = []
-        for src_path in src_paths:
-            resources.append(toolchain.scan_resources(src_path))
+        resources = None
+        for path in src_paths:
+            # Scan resources
+            resource = toolchain.scan_resources(path)
+            
+            # Copy headers, objects and static libraries - all files needed for static lib
+            toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path)
+            toolchain.copy_files(resource.objects, build_path, rel_path=resource.base_path)
+            toolchain.copy_files(resource.libraries, build_path, rel_path=resource.base_path)
+            if resource.linker_script:
+                toolchain.copy_files(resource.linker_script, build_path, rel_path=resource.base_path)
+
+            # Extend resources collection
+            if not resources:
+                resources = resource
+            else:
+                resources.add(resource)
+
+        # We need to add if necessary additional include directories
+        if inc_dirs:
+            if type(inc_dirs) == ListType:
+                resources.inc_dirs.extend(inc_dirs)
+            else:
+                resources.inc_dirs.append(inc_dirs)
 
         # Add extra include directories / files which are required by library
         # This files usually are not in the same directory as source files so
         # previous scan will not include them
         if inc_dirs_ext is not None:
             for inc_ext in inc_dirs_ext:
-                resources.append(toolchain.scan_resources(inc_ext))
+                resources.add(toolchain.scan_resources(inc_ext))
 
         # Dependencies Include Paths
-        dependencies_include_dir = []
         if dependencies_paths is not None:
             for path in dependencies_paths:
                 lib_resources = toolchain.scan_resources(path)
-                dependencies_include_dir.extend(lib_resources.inc_dirs)
-
-        if inc_dirs:
-            dependencies_include_dir.extend(inc_dirs)
+                resources.inc_dirs.extend(lib_resources.inc_dirs)
 
         if archive:
             # Use temp path when building archive
@@ -337,29 +352,21 @@
 
         # Handle configuration
         config = Config(target)
-
-        # Copy headers, objects and static libraries
-        for resource in resources:
-            toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path)
-            toolchain.copy_files(resource.objects, build_path, rel_path=resource.base_path)
-            toolchain.copy_files(resource.libraries, build_path, rel_path=resource.base_path)
-            if resource.linker_script:
-                toolchain.copy_files(resource.linker_script, build_path, rel_path=resource.base_path)
-            config.add_config_files(resource.json_files)
-
+        # Update the configuration with any .json files found while scanning
+        config.add_config_files(resources.json_files)
+        # And add the configuration macros to the toolchain
         toolchain.add_macros(config.get_config_data_macros())
 
         # Compile Sources
-        objects = []
-        for resource in resources:
-            objects.extend(toolchain.compile_sources(resource, abspath(tmp_path), dependencies_include_dir))
+        for path in src_paths:
+            src = toolchain.scan_resources(path)
+            objects = toolchain.compile_sources(src, abspath(tmp_path), resources.inc_dirs)
+            resources.objects.extend(objects)
 
         if archive:
-            needed_update = toolchain.build_library(objects, build_path, name)
-        else:
-            needed_update = True
+            toolchain.build_library(objects, build_path, name)
 
-        if report != None and needed_update:
+        if report != None:
             end = time()
             cur_result["elapsed_time"] = end - start
             cur_result["output"] = toolchain.get_output()
@@ -382,6 +389,144 @@
             if toolchain_output:
                 cur_result["output"] += toolchain_output
 
+            add_result_to_report(report, cur_result)
+
+        # Let Exception propagate
+        raise e
+
+######################
+### Legacy methods ###
+######################
+
+def build_lib(lib_id, target, toolchain_name, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False):
+    """ Legacy method for building mbed libraries
+        Function builds library in proper directory using all dependencies and macros defined by user.
+    """
+    lib = Library(lib_id)
+    if not lib.is_supported(target, toolchain_name):
+        print 'Library "%s" is not yet supported on target %s with toolchain %s' % (lib_id, target.name, toolchain)
+        return False
+    
+    # We need to combine macros from parameter list with macros from library definition
+    MACROS = lib.macros if lib.macros else []
+    if macros:
+        macros.extend(MACROS)
+    else:
+        macros = MACROS
+
+    src_paths = lib.source_dir
+    build_path = lib.build_dir
+    dependencies_paths = lib.dependencies
+    inc_dirs = lib.inc_dirs
+    inc_dirs_ext = lib.inc_dirs_ext
+    
+    """ src_path: the path of the source directory
+    build_path: the path of the build directory
+    target: ['LPC1768', 'LPC11U24', 'LPC2368']
+    toolchain: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR']
+    library_paths: List of paths to additional libraries
+    clean: Rebuild everything if True
+    notify: Notify function for logs
+    verbose: Write the actual tools command lines if True
+    inc_dirs: additional include directories which should be included in build
+    inc_dirs_ext: additional include directories which should be copied to library directory
+    """
+    if type(src_paths) != ListType:
+        src_paths = [src_paths]
+
+    # The first path will give the name to the library
+    name = basename(src_paths[0])
+
+    if report != None:
+        start = time()
+        id_name = name.upper()
+        description = name
+        vendor_label = target.extra_labels[0]
+        cur_result = None
+        prep_report(report, target.name, toolchain_name, id_name)
+        cur_result = create_result(target.name, toolchain_name, id_name, description)
+
+        if properties != None:
+            prep_properties(properties, target.name, toolchain_name, vendor_label)
+
+    for src_path in src_paths:
+        if not exists(src_path):
+            error_msg = "The library source folder does not exist: %s", src_path
+
+            if report != None:
+                cur_result["output"] = error_msg
+                cur_result["result"] = "FAIL"
+                add_result_to_report(report, cur_result)
+
+            raise Exception(error_msg)
+
+    try:
+        # Toolchain instance
+        toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent, extra_verbose=extra_verbose, profile=profile)
+        toolchain.VERBOSE = verbose
+        toolchain.jobs = jobs
+        toolchain.build_all = clean
+
+        toolchain.info("Building library %s (%s, %s)" % (name.upper(), target.name, toolchain_name))
+
+        # Scan Resources
+        resources = []
+        for src_path in src_paths:
+            resources.append(toolchain.scan_resources(src_path))
+
+        # Add extra include directories / files which are required by library
+        # This files usually are not in the same directory as source files so
+        # previous scan will not include them
+        if inc_dirs_ext is not None:
+            for inc_ext in inc_dirs_ext:
+                resources.append(toolchain.scan_resources(inc_ext))
+
+        # Dependencies Include Paths
+        dependencies_include_dir = []
+        if dependencies_paths is not None:
+            for path in dependencies_paths:
+                lib_resources = toolchain.scan_resources(path)
+                dependencies_include_dir.extend(lib_resources.inc_dirs)
+
+        if inc_dirs:
+            dependencies_include_dir.extend(inc_dirs)
+
+        # Create the desired build directory structure
+        bin_path = join(build_path, toolchain.obj_path)
+        mkdir(bin_path)
+        tmp_path = join(build_path, '.temp', toolchain.obj_path)
+        mkdir(tmp_path)
+
+        # Copy Headers
+        for resource in resources:
+            toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path)
+        dependencies_include_dir.extend(toolchain.scan_resources(build_path).inc_dirs)
+
+        # Compile Sources
+        objects = []
+        for resource in resources:
+            objects.extend(toolchain.compile_sources(resource, tmp_path, dependencies_include_dir))
+
+        needed_update = toolchain.build_library(objects, bin_path, name)
+
+        if report != None and needed_update:
+            end = time()
+            cur_result["elapsed_time"] = end - start
+            cur_result["output"] = toolchain.get_output()
+            cur_result["result"] = "OK"
+
+            add_result_to_report(report, cur_result)
+
+    except Exception, e:
+        if report != None:
+            end = time()
+            cur_result["result"] = "FAIL"
+            cur_result["elapsed_time"] = end - start
+
+            toolchain_output = toolchain.get_output()
+            if toolchain_output:
+                cur_result["output"] += toolchain_output
+
             cur_result["output"] += str(e)
 
             add_result_to_report(report, cur_result)
@@ -389,34 +534,6 @@
         # Let Exception propagate
         raise e
 
-def build_lib(lib_id, target, toolchain, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False):
-    """ Wrapper for build_library function.
-        Function builds library in proper directory using all dependencies and macros defined by user.
-    """
-    lib = Library(lib_id)
-    if lib.is_supported(target, toolchain):
-        # We need to combine macros from parameter list with macros from library definition
-        MACROS = lib.macros if lib.macros else []
-        if macros:
-            MACROS.extend(macros)
-
-        return build_library(lib.source_dir, lib.build_dir, target, toolchain, lib.dependencies, options,
-                      verbose=verbose,
-                      silent=silent,
-                      clean=clean,
-                      macros=MACROS,
-                      notify=notify,
-                      inc_dirs=lib.inc_dirs,
-                      inc_dirs_ext=lib.inc_dirs_ext,
-                      jobs=jobs,
-                      report=report,
-                      properties=properties,
-                      extra_verbose=extra_verbose)
-    else:
-        print 'Library "%s" is not yet supported on target %s with toolchain %s' % (lib_id, target.name, toolchain)
-        return False
-
-
 # We do have unique legacy conventions about how we build and package the mbed library
 def build_mbed_libs(target, toolchain_name, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False):
     """ Function returns True is library was built and false if building was skipped """
@@ -445,6 +562,9 @@
 
         return False
 
+    for path in src_paths:
+        profile = get_build_profile(path)
+
     try:
         # Toolchain
         toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent, extra_verbose=extra_verbose)
@@ -506,12 +626,12 @@
         for o in separate_objects:
             objects.remove(o)
 
-        needed_update = toolchain.build_library(objects, BUILD_TOOLCHAIN, "mbed")
+        toolchain.build_library(objects, BUILD_TOOLCHAIN, "mbed")
 
         for o in separate_objects:
             toolchain.copy_files(o, BUILD_TOOLCHAIN)
 
-        if report != None and needed_update:
+        if report != None:
             end = time()
             cur_result["elapsed_time"] = end - start
             cur_result["output"] = toolchain.get_output()
@@ -538,6 +658,7 @@
         # Let Exception propagate
         raise e
 
+
 def get_unique_supported_toolchains():
     """ Get list of all unique toolchains supported by targets """
     unique_supported_toolchains = []
@@ -554,12 +675,12 @@
     from prettytable import PrettyTable # Only use it in this function so building works without extra modules
 
     # All tests status table print
-    columns = ["Platform"] + unique_supported_toolchains
-    pt = PrettyTable(["Platform"] + unique_supported_toolchains)
+    columns = ["Target"] + unique_supported_toolchains
+    pt = PrettyTable(["Target"] + unique_supported_toolchains)
     # Align table
     for col in columns:
         pt.align[col] = "c"
-    pt.align["Platform"] = "l"
+    pt.align["Target"] = "l"
 
     perm_counter = 0
     target_counter = 0
@@ -571,25 +692,21 @@
         target_counter += 1
 
         row = [target]  # First column is platform name
-        default_toolchain = TARGET_MAP[target].default_toolchain
         for unique_toolchain in unique_supported_toolchains:
-            text = "-"
-            if default_toolchain == unique_toolchain:
-                text = "Default"
-                perm_counter += 1
-            elif unique_toolchain in TARGET_MAP[target].supported_toolchains:
+            if unique_toolchain in TARGET_MAP[target].supported_toolchains:
                 text = "Supported"
                 perm_counter += 1
+            else:
+                text = "-"
+            
             row.append(text)
         pt.add_row(row)
 
     result = pt.get_html_string() if verbose_html else pt.get_string()
     result += "\n"
-    result += "*Default - default on-line compiler\n"
-    result += "*Supported - supported off-line compiler\n"
-    result += "\n"
-    result += "Total platforms: %d\n"% (target_counter)
-    result += "Total permutations: %d"% (perm_counter)
+    result += "Supported targets: %d\n"% (target_counter)
+    if target_counter == 1:
+        result += "Supported toolchains: %d"% (perm_counter)
     return result
 
 
@@ -824,6 +941,66 @@
     with open(filename, 'w+') as f:
         f.write(template.render(failing_builds=build_report_failing, passing_builds=build_report_passing))
 
+
+def scan_for_source_paths(path, exclude_paths=None):
+    ignorepatterns = []
+    paths = []
+    
+    def is_ignored(file_path):
+        for pattern in ignorepatterns:
+            if fnmatch.fnmatch(file_path, pattern):
+                return True
+        return False
+    
+    
+    """ os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])
+    When topdown is True, the caller can modify the dirnames list in-place
+    (perhaps using del or slice assignment), and walk() will only recurse into
+    the subdirectories whose names remain in dirnames; this can be used to prune
+    the search, impose a specific order of visiting, or even to inform walk()
+    about directories the caller creates or renames before it resumes walk()
+    again. Modifying dirnames when topdown is False is ineffective, because in
+    bottom-up mode the directories in dirnames are generated before dirpath
+    itself is generated.
+    """
+    for root, dirs, files in walk(path, followlinks=True):
+        # Remove ignored directories
+        # Check if folder contains .mbedignore
+        if ".mbedignore" in files :
+            with open (join(root,".mbedignore"), "r") as f:
+                lines=f.readlines()
+                lines = [l.strip() for l in lines] # Strip whitespaces
+                lines = [l for l in lines if l != ""] # Strip empty lines
+                lines = [l for l in lines if not re.match("^#",l)] # Strip comment lines
+                # Append root path to glob patterns
+                # and append patterns to ignorepatterns
+                ignorepatterns.extend([join(root,line.strip()) for line in lines])
+
+        for d in copy(dirs):
+            dir_path = join(root, d)
+
+            # Always ignore hidden directories
+            if d.startswith('.'):
+                dirs.remove(d)
+
+            # Remove dirs that already match the ignorepatterns
+            # to avoid travelling into them and to prevent them
+            # on appearing in include path.
+            if is_ignored(join(dir_path,"")):
+                dirs.remove(d)
+
+            if exclude_paths:
+                for exclude_path in exclude_paths:
+                    rel_path = relpath(dir_path, exclude_path)
+                    if not (rel_path.startswith('..')):
+                        dirs.remove(d)
+                        break
+
+        # Add root to include paths
+        paths.append(root)
+
+    return paths
+
 def get_build_profile(path):
     profile = None
     builds = get_build_ids(path)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/get_config.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,94 @@
+#! /usr/bin/env python2
+"""
+mbed SDK
+Copyright (c) 2011-2013 ARM Limited
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+import sys
+from os.path import isdir, abspath, dirname, join
+from os import _exit
+
+# Be sure that the tools directory is in the search path
+ROOT = abspath(join(dirname(__file__), ".."))
+sys.path.insert(0, ROOT)
+
+from tools.utils import args_error
+from tools.options import get_default_options_parser
+from tools.build_api import get_config
+from config import Config
+try:
+    import tools.private_settings as ps
+except:
+    ps = object()
+
+if __name__ == '__main__':
+    # Parse Options
+    parser = get_default_options_parser(add_clean=False, add_options=False)
+    parser.add_option("--source", dest="source_dir",
+                      default=None, help="The source (input) directory", action="append")
+    parser.add_option("--prefix", dest="prefix", action="append",
+                      default=None, help="Restrict listing to parameters that have this prefix")
+    parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+                      default=False, help="Verbose diagnostic output")
+
+    (options, args) = parser.parse_args()
+
+    for path in options.source_dir :
+        if not isdir(path) :
+            args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist".
+                       format(path))
+    # Target
+    if options.mcu is None :
+        args_error(parser, "[ERROR] You should specify an MCU")
+    target = options.mcu
+
+    # Toolchain
+    if options.tool is None:
+        args_error(parser, "[ERROR] You should specify a TOOLCHAIN")
+    toolchain = options.tool
+
+    options.prefix = options.prefix or [""]
+
+    try:
+        params, macros = get_config(options.source_dir, target, toolchain)
+        if not params and not macros:
+            print "No configuration data available."
+            _exit(0)
+        if params:
+            print "Configuration parameters"
+            print "------------------------"
+            for p in params:
+                for s in options.prefix:
+                    if p.startswith(s):
+                        print(str(params[p]) if not options.verbose else params[p].get_verbose_description())
+                        break
+            print ""
+
+        print "Macros"
+        print "------"
+        if macros:
+            print 'Defined with "macros":', macros
+        print "Generated from configuration parameters:", Config.parameters_to_macros(params)
+
+    except KeyboardInterrupt, e:
+        print "\n[CTRL+c] exit"
+    except Exception,e:
+        if options.verbose:
+            import traceback
+            traceback.print_exc(file=sys.stdout)
+        else:
+            print "[ERROR] %s" % str(e)
+
+        sys.exit(1)
--- a/make.py	Tue Jun 07 11:35:02 2016 +0100
+++ b/make.py	Tue Jun 14 11:07:30 2016 +0100
@@ -21,7 +21,7 @@
 import sys
 from time import sleep
 from shutil import copy
-from os.path import join, abspath, dirname
+from os.path import join, abspath, dirname, isfile, isdir
 
 # Be sure that the tools directory is in the search path
 ROOT = abspath(join(dirname(__file__), ".."))
@@ -41,12 +41,12 @@
 from tools.targets import TARGET_MAP
 from tools.options import get_default_options_parser
 from tools.build_api import build_project
+from tools.build_api import mcu_toolchain_matrix
 try:
     import tools.private_settings as ps
 except:
     ps = object()
 
-
 if __name__ == '__main__':
     # Parse Options
     parser = get_default_options_parser()
@@ -82,6 +82,17 @@
                       dest="macros",
                       help="Add a macro definition")
 
+    parser.add_option("-S", "--supported-toolchains",
+                      action="store_true",
+                      dest="supported_toolchains",
+                      default=False,
+                      help="Displays supported matrix of MCUs and toolchains")
+
+    parser.add_option('-f', '--filter',
+                      dest='general_filter_regex',
+                      default=None,
+                      help='For some commands you can use filter to filter out results')
+
     # Local run
     parser.add_option("--automated", action="store_true", dest="automated",
                       default=False, help="Automated test")
@@ -167,6 +178,17 @@
 
     (options, args) = parser.parse_args()
 
+    # Only prints matrix of supported toolchains
+    if options.supported_toolchains:
+        print mcu_toolchain_matrix(platform_filter=options.general_filter_regex)
+        exit(0)
+
+    if options.source_dir:
+        for path in options.source_dir :
+            if not isfile(path) and not isdir(path) :
+                args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist".
+                           format(path))
+
     # Print available tests in order and exit
     if options.list_tests is True:
         print '\n'.join(map(str, sorted(TEST_MAP.values())))
@@ -243,13 +265,7 @@
             build_dir = options.build_dir
 
         try:
-            target = TARGET_MAP[mcu]
-        except KeyError:
-            print "[ERROR] Target %s not supported" % mcu
-            sys.exit(1)
-
-        try:
-            bin_file = build_project(test.source_dir, build_dir, target, toolchain, test.dependencies, options.options,
+            bin_file = build_project(test.source_dir, build_dir, mcu, toolchain, test.dependencies, options.options,
                                      linker_script=options.linker_script,
                                      clean=options.clean,
                                      verbose=options.verbose,
@@ -267,7 +283,7 @@
                 # Import pyserial: https://pypi.python.org/pypi/pyserial
                 from serial import Serial
 
-                sleep(target.program_cycle_s())
+                sleep(TARGET_MAP[mcu].program_cycle_s())
 
                 serial = Serial(options.serial, timeout = 1)
                 if options.baud:
--- a/memap.py	Tue Jun 07 11:35:02 2016 +0100
+++ b/memap.py	Tue Jun 14 11:07:30 2016 +0100
@@ -1,21 +1,20 @@
-#! /usr/bin/env python
+#!/usr/bin/env python
+# pylint: disable=too-many-arguments, too-many-locals, too-many-branches, too-many-lines, line-too-long, too-many-nested-blocks, too-many-public-methods, too-many-instance-attributes
+# pylint: disable=invalid-name, missing-docstring
 
 # Memory Map File Analyser for ARM mbed OS
 
-import argparse
 import sys
-import string
 import os
 import re
+import csv
 import json
-import time
-import string
-import StringIO 
+import argparse
 from prettytable import PrettyTable
 
 debug = False
 
-class MemmapParser(object):
+class MemapParser(object):
 
     def __init__(self):
         """
@@ -27,92 +26,22 @@
 
         self.misc_flash_sections = ('.interrupts', '.flash_config')
 
-        self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab', '.ARM.exidx', '.ARM.attributes', \
-                 '.eh_frame', '.init_array', '.fini_array', '.jcr', '.stab', '.stabstr', \
-                 '.ARM.exidx','.ARM' )
+        self.other_sections = ('.interrupts_ram', '.init', '.ARM.extab', \
+                               '.ARM.exidx', '.ARM.attributes', '.eh_frame', \
+                               '.init_array', '.fini_array', '.jcr', '.stab', \
+                               '.stabstr', '.ARM.exidx', '.ARM')
 
         # sections to print info (generic for all toolchains)
-        self.sections = ('.text', '.data', '.bss', '.heap', '.stack',) 
+        self.sections = ('.text', '.data', '.bss', '.heap', '.stack')
 
-        # need to have sections merged in this order ()
+        # sections must be defined in this order to take irrelevant out
         self.all_sections = self.sections + self.other_sections + \
                             self.misc_flash_sections + ('unknown', 'OUTPUT')
 
         self.print_sections = ('.text', '.data', '.bss')
 
         # list of all object files and mappting to module names
-        self.object_to_module = dict() 
-
-
-    def generate_output(self, file, json_mode):
-        """
-        Generates summary of memory map data
-
-        Parameters
-            file: descriptor (either stdout or file)
-            json_mode: generates output in json formal (True/False)
-        """
-
-        buf = StringIO.StringIO()
-
-        # Calculate misc flash sections
-        misc_flash_mem = 0
-        for i in self.modules:
-            for k in self.misc_flash_sections:
-                if self.modules[i][k]:
-                    misc_flash_mem += self.modules[i][k]
-
-        # Create table
-        colums = ['Module']
-        for i in list(self.print_sections):
-            colums.append(i) 
-
-        table = PrettyTable(colums)
-        table.align["Module"] = "l"
-
-        subtotal = dict()
-        for k in self.sections:
-            subtotal[k] = 0
-
-        json_obj = []
-        for i in sorted(self.modules):
-            
-            row = []
-            row.append(i)
-
-            for k in self.sections: 
-                subtotal[k] += self.modules[i][k]
-
-            for k in self.print_sections:
-                row.append(self.modules[i][k])
-            
-            json_obj.append({ "module":i, "size":{k:self.modules[i][k] for k in self.print_sections}})
-            table.add_row(row)
-
-        subtotal_row = ['Subtotals']
-        for k in self.print_sections:
-            subtotal_row.append(subtotal[k]) 
-
-        table.add_row(subtotal_row)
-
-        if json_mode:
-            json_obj.append({ "summary":{'static_ram':(subtotal['.data']+subtotal['.bss']),
-                                               'heap':(subtotal['.heap']),
-                                              'stack':(subtotal['.stack']),
-                                          'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),
-                                        'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),}})
-
-            file.write(json.dumps(json_obj, indent=4))
-            file.write('\n')
-        else:
-            file.write(table.get_string())
-            file.write('\n')
-            file.write("Static RAM memory (data + bss): %s\n" % (str(subtotal['.data']+subtotal['.bss'])))
-            file.write("Heap: %s\n" % str(subtotal['.heap']))
-            file.write("Stack: %s\n" % str(subtotal['.stack']))
-            file.write("Total RAM memory (data + bss + heap + stack): %s\n" % (str(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack'])))
-            file.write("Total Flash memory (text + data + misc): %s\n" % (str(subtotal['.text']+subtotal['.data']+misc_flash_mem)))
-        return
+        self.object_to_module = dict()
 
     def module_add(self, module_name, size, section):
         """
@@ -120,42 +49,15 @@
         """
 
         if module_name in self.modules:
-                self.modules[module_name][section] += size
+            self.modules[module_name][section] += size
         else:
             temp_dic = dict()
-            for x in self.all_sections:
-                temp_dic[x] = 0
+            for section_idx in self.all_sections:
+                temp_dic[section_idx] = 0
             temp_dic[section] = size
             self.modules[module_name] = temp_dic
 
-    def find_start_gcc(self,line):
-        """
-        Checks location of gcc map file to start parsing map file
-        """
-        if line.startswith('Linker script and memory map'):
-            return True
-        else:
-            return False
-
-    def find_start_armcc(self,line):
-        """
-        Checks location of armcc map file to start parsing map file
-        """
-        if line.startswith('    Base Addr    Size'):
-            return True
-        else:
-            return False
-
-    def find_start_iar(self,line):
-        """
-        Checks location of armcc map file to start parsing map file
-        """
-        if line.startswith('  Section  '):
-            return True
-        else:
-            return False
-
-    def check_new_section_gcc(self,line):
+    def check_new_section_gcc(self, line):
         """
         Check whether a new section in a map file has been detected (only applies to gcc)
         """
@@ -169,15 +71,15 @@
         else:
             return False         # everything else, means no change in section
 
-    def path_object_to_module_name(self,txt):
+    def path_object_to_module_name(self, txt):
         """
-        Parses path to object file and extracts module / object data 
+        Parses path to object file and extracts module / object data
         """
 
-        txt = txt.replace('\\','/')
+        txt = txt.replace('\\', '/')
         rex_mbed_os_name = r'^.+mbed-os\/(.+)\/(.+\.o)$'
-        test_rex_mbed_os_name = re.match(rex_mbed_os_name,txt)
- 
+        test_rex_mbed_os_name = re.match(rex_mbed_os_name, txt)
+
         if test_rex_mbed_os_name:
 
             object_name = test_rex_mbed_os_name.group(2)
@@ -192,9 +94,9 @@
             return [module_name, object_name]
         else:
             return ['Misc', ""]
-               
+
 
-    def parse_section_gcc(self,line):
+    def parse_section_gcc(self, line):
         """
         Parse data from a section of gcc map file
         """
@@ -203,45 +105,45 @@
         #  .text          0x00000608      0x198 ./.build/K64F/GCC_ARM/mbed-os/core/mbed-rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/HAL_CM4.o
         rex_address_len_name = r'^\s+.*0x(\w{8,16})\s+0x(\w+)\s(.+)$'
 
-        test_address_len_name = re.match(rex_address_len_name,line)
+        test_address_len_name = re.match(rex_address_len_name, line)
 
         if test_address_len_name:
 
-            if int(test_address_len_name.group(2),16) == 0: # size == 0
-                return ["",0] # no valid entry
+            if int(test_address_len_name.group(2), 16) == 0: # size == 0
+                return ["", 0] # no valid entry
             else:
                 m_name, m_object = self.path_object_to_module_name(test_address_len_name.group(3))
-                m_size = int(test_address_len_name.group(2),16) 
-                return [m_name,m_size]
+                m_size = int(test_address_len_name.group(2), 16)
+                return [m_name, m_size]
 
-        else: # special cortner case for *fill* sections
+        else: # special corner case for *fill* sections
             #  example
             # *fill*         0x0000abe4        0x4
             rex_address_len = r'^\s+\*fill\*\s+0x(\w{8,16})\s+0x(\w+).*$'
-            test_address_len = re.match(rex_address_len,line)
+            test_address_len = re.match(rex_address_len, line)
 
             if test_address_len:
-                if int(test_address_len.group(2),16) == 0: # size == 0
-                    return ["",0] # no valid entry
+                if int(test_address_len.group(2), 16) == 0: # size == 0
+                    return ["", 0] # no valid entry
                 else:
-                    m_name = 'Misc'
-                    m_size = int(test_address_len.group(2),16)
-                    return [m_name,m_size]
+                    m_name = 'Fill'
+                    m_size = int(test_address_len.group(2), 16)
+                    return [m_name, m_size]
             else:
-                return ["",0] # no valid entry
+                return ["", 0] # no valid entry
 
-    def parse_map_file_gcc(self, file):
+    def parse_map_file_gcc(self, file_desc):
         """
         Main logic to decode gcc map files
         """
 
         current_section = 'unknown'
 
-        with file as infile:
+        with file_desc as infile:
 
             # Search area to parse
             for line in infile:
-                if self.find_start_gcc(line) == True:
+                if line.startswith('Linker script and memory map'):
                     current_section = "unknown"
                     break
 
@@ -252,7 +154,7 @@
 
                 if change_section == "OUTPUT": # finish parsing file: exit
                     break
-                elif change_section != False:  
+                elif change_section != False:
                     current_section = change_section
 
                 [module_name, module_size] = self.parse_section_gcc(line)
@@ -264,10 +166,10 @@
 
                 if debug:
                     print "Line: %s" % line,
-                    print "Module: %s\tSection: %s\tSize: %s" % (module_name,current_section,module_size)
+                    print "Module: %s\tSection: %s\tSize: %s" % (module_name, current_section, module_size)
                     raw_input("----------")
 
-    def parse_section_armcc(self,line):
+    def parse_section_armcc(self, line):
         """
         Parse data from an armcc map file
         """
@@ -277,11 +179,11 @@
         #     0x00000410   0x00000008   Code   RO        49364  * !!!main             c_w.l(__main.o)
         rex_armcc = r'^\s+0x(\w{8})\s+0x(\w{8})\s+(\w+)\s+(\w+)\s+(\d+)\s+[*]?.+\s+(.+)$'
 
-        test_rex_armcc = re.match(rex_armcc,line)
+        test_rex_armcc = re.match(rex_armcc, line)
 
         if test_rex_armcc:
 
-            size = int(test_rex_armcc.group(2),16)
+            size = int(test_rex_armcc.group(2), 16)
 
             if test_rex_armcc.group(4) == 'RO':
                 section = '.text'
@@ -301,12 +203,12 @@
             else:
                 module_name = 'Misc'
 
-            return [module_name,size,section]
+            return [module_name, size, section]
 
         else:
-            return ["",0,""] # no valid entry
+            return ["", 0, ""] # no valid entry
 
-    def parse_section_iar(self,line):
+    def parse_section_iar(self, line):
         """
         Parse data from an IAR map file
         """
@@ -322,16 +224,15 @@
         #    HEAP              uninit   0x20001650  0x10000  <Block tail>
         rex_iar = r'^\s+(.+)\s+(zero|const|ro code|inited|uninit)\s+0x(\w{8})\s+0x(\w+)\s+(.+)\s.+$'
 
-        test_rex_iar = re.match(rex_iar,line)
+        test_rex_iar = re.match(rex_iar, line)
 
         if test_rex_iar:
 
-            size = int(test_rex_iar.group(4),16)
+            size = int(test_rex_iar.group(4), 16)
 
             if test_rex_iar.group(2) == 'const' or test_rex_iar.group(2) == 'ro code':
                 section = '.text'
             elif test_rex_iar.group(2) == 'zero' or test_rex_iar.group(2) == 'uninit':
-               
                 if test_rex_iar.group(1)[0:4] == 'HEAP':
                     section = '.heap'
                 elif test_rex_iar.group(1)[0:6] == 'CSTACK':
@@ -352,21 +253,21 @@
             else:
                 module_name = 'Misc'
 
-            return [module_name,size,section]
+            return [module_name, size, section]
 
         else:
-            return ["",0,""] # no valid entry
+            return ["", 0, ""] # no valid entry
 
-    def parse_map_file_armcc(self, file):
+    def parse_map_file_armcc(self, file_desc):
         """
         Main logic to decode armcc map files
         """
 
-        with file as infile:
+        with file_desc as infile:
 
             # Search area to parse
             for line in infile:
-                if self.find_start_armcc(line) == True:
+                if line.startswith('    Base Addr    Size'):
                     break
 
             # Start decoding the map file
@@ -379,16 +280,16 @@
                 else:
                     self.module_add(name, size, section)
 
-    def parse_map_file_iar(self, file):
+    def parse_map_file_iar(self, file_desc):
         """
         Main logic to decode armcc map files
         """
 
-        with file as infile:
+        with file_desc as infile:
 
             # Search area to parse
             for line in infile:
-                if self.find_start_iar(line) == True:
+                if line.startswith('  Section  '):
                     break
 
             # Start decoding the map file
@@ -401,18 +302,18 @@
                 else:
                     self.module_add(name, size, section)
 
-    def search_objects(self,path,toolchain):
+    def search_objects(self, path, toolchain):
         """
         Check whether the specified map file matches with the toolchain.
         Searches for object files and creates mapping: object --> module
         """
 
-        path = path.replace('\\','/')
+        path = path.replace('\\', '/')
 
         # check location of map file
         rex = r'^(.+\/)' + re.escape(toolchain) + r'\/(.+\.map)$'
-        test_rex = re.match(rex,path)
-        
+        test_rex = re.match(rex, path)
+
         if test_rex:
             search_path = test_rex.group(1) + toolchain + '/mbed-os/'
         else:
@@ -421,37 +322,177 @@
             print "Warning: specified toolchain doesn't match with path to the memory map file."
             return
 
-        for root, dirs, files in os.walk(search_path):
-            for file in files:
-                if file.endswith(".o"):
-                    module_name, object_name = self.path_object_to_module_name(os.path.join(root, file))
+        for root, dir, obj_files in os.walk(search_path):
+            for obj_file in obj_files:
+                if obj_file.endswith(".o"):
+                    module_name, object_name = self.path_object_to_module_name(os.path.join(root, obj_file))
 
                     if object_name in self.object_to_module:
-                        print "WARNING: multiple usages of object file: %s" % object_name
-                        print "    Current: %s" % self.object_to_module[object_name]
-                        print "    New:     %s" % module_name
-                        print " "
-                        
+                        if debug:
+                            print "WARNING: multiple usages of object file: %s" % object_name
+                            print "    Current: %s" % self.object_to_module[object_name]
+                            print "    New:     %s" % module_name
+                            print " "
                     else:
                         self.object_to_module.update({object_name:module_name})
 
+    def generate_output(self, export_format, file_output=None):
+        """
+        Generates summary of memory map data
+
+        Parameters
+            json_mode: generates output in json formal (True/False)
+            file_desc: descriptor (either stdout or file)
+        """
+
+        try:
+            if file_output:
+                file_desc = open(file_output, 'wb')
+            else:
+                file_desc = sys.stdout
+        except IOError as error:
+            print "I/O error({0}): {1}".format(error.errno, error.strerror)
+            return False
+
+        # Calculate misc flash sections
+        misc_flash_mem = 0
+        for i in self.modules:
+            for k in self.misc_flash_sections:
+                if self.modules[i][k]:
+                    misc_flash_mem += self.modules[i][k]
+
+        # Create table
+        columns = ['Module']
+        for i in list(self.print_sections):
+            columns.append(i)
+
+        table = PrettyTable(columns)
+        table.align["Module"] = "l"
+
+        subtotal = dict()
+        for k in self.sections:
+            subtotal[k] = 0
+
+        json_obj = []
+        for i in sorted(self.modules):
+
+            row = []
+            row.append(i)
+
+            for k in self.sections:
+                subtotal[k] += self.modules[i][k]
+
+            for k in self.print_sections:
+                row.append(self.modules[i][k])
+
+            json_obj.append({"module":i, "size":{\
+                k:self.modules[i][k] for k in self.print_sections}})
+
+            table.add_row(row)
+
+        subtotal_row = ['Subtotals']
+        for k in self.print_sections:
+            subtotal_row.append(subtotal[k])
+
+        table.add_row(subtotal_row)
+
+        if export_format == 'json':
+            json_obj.append({\
+                  'summary':{\
+                  'static_ram':(subtotal['.data']+subtotal['.bss']),\
+                  'heap':(subtotal['.heap']),\
+                  'stack':(subtotal['.stack']),\
+                  'total_ram':(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']),\
+                  'total_flash':(subtotal['.text']+subtotal['.data']+misc_flash_mem),}})
+
+            file_desc.write(json.dumps(json_obj, indent=4))
+            file_desc.write('\n')
+
+        elif export_format == 'csv-ci': # CSV format for the CI system
+
+            csv_writer = csv.writer(file_desc, delimiter=',', quoting=csv.QUOTE_NONE)
+
+            csv_module_section = []
+            csv_sizes = []
+            for i in sorted(self.modules):
+                for k in self.print_sections:
+                    csv_module_section += [i+k]
+                    csv_sizes += [self.modules[i][k]]
+
+            csv_module_section += ['static_ram']
+            csv_sizes += [subtotal['.data']+subtotal['.bss']]
+
+            csv_module_section += ['heap']
+            csv_sizes += [subtotal['.heap']]
+
+            csv_module_section += ['stack']
+            csv_sizes += [subtotal['.stack']]
+
+            csv_module_section += ['total_ram']
+            csv_sizes += [subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack']]
+
+            csv_module_section += ['total_flash']
+            csv_sizes += [subtotal['.text']+subtotal['.data']+misc_flash_mem]
+
+            csv_writer.writerow(csv_module_section)
+            csv_writer.writerow(csv_sizes)
+
+        else: # default format is 'table'
+            file_desc.write(table.get_string())
+            file_desc.write('\n')
+            file_desc.write("Static RAM memory (data + bss): %s\n" % (str(subtotal['.data']+subtotal['.bss'])))
+            file_desc.write("Heap: %s\n" % str(subtotal['.heap']))
+            file_desc.write("Stack: %s\n" % str(subtotal['.stack']))
+            file_desc.write("Total RAM memory (data + bss + heap + stack): %s\n" % (str(subtotal['.data']+subtotal['.bss']+subtotal['.heap']+subtotal['.stack'])))
+            file_desc.write("Total Flash memory (text + data + misc): %s\n" % (str(subtotal['.text']+subtotal['.data']+misc_flash_mem)))
+
+        if file_desc is not sys.stdout:
+            file_desc.close()
+
+        return True
+
+    def parse(self, mapfile, toolchain):
+        """
+        Parse and decode map file depending on the toolchain
+        """
+
+        try:
+            file_input = open(mapfile, 'rt')
+        except IOError as error:
+            print "I/O error({0}): {1}".format(error.errno, error.strerror)
+            return False
+
+        if toolchain == "ARM" or toolchain == "ARM_STD" or toolchain == "ARM_MICRO":
+            self.search_objects(os.path.abspath(mapfile), "ARM")
+            self.parse_map_file_armcc(file_input)
+        elif toolchain == "GCC_ARM":
+            self.parse_map_file_gcc(file_input)
+        elif toolchain == "IAR":
+            self.search_objects(os.path.abspath(mapfile), toolchain)
+            self.parse_map_file_iar(file_input)
+        else:
+            return False
+
+        file_input.close()
+
+        return True
+
 def main():
 
-    version = '0.3.7'
-    time_start = time.clock()
+    version = '0.3.10'
 
     # Parser handling
     parser = argparse.ArgumentParser(description="Memory Map File Analyser for ARM mbed OS\nversion %s" % version)
 
     parser.add_argument('file', help='memory map file')
 
-    parser.add_argument('-t','--toolchain', dest='toolchain', help='select a toolchain that corresponds to the memory map file (ARM, GCC_ARM, IAR)',
+    parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (ARM, GCC_ARM, IAR)',\
                         required=True)
 
-    parser.add_argument('-o','--output',help='output file name', required=False)
+    parser.add_argument('-o', '--output', help='output file name', required=False)
 
-    parser.add_argument('-j', '--json', dest='json', required=False, action="store_true",
-                      help='output in JSON formatted list')
+    parser.add_argument('-e', '--export', dest='export', required=False,\
+                        help="export format (examples: 'json', 'csv-ci', 'table': default)")
 
     parser.add_argument('-v', '--version', action='version', version=version)
 
@@ -460,49 +501,29 @@
         parser.print_help()
         sys.exit(1)
 
+
     args, remainder = parser.parse_known_args()
 
-    try:
-        file_input = open(args.file,'rt')
-    except IOError as e:
-        print "I/O error({0}): {1}".format(e.errno, e.strerror)
-        sys.exit(0)
+    # Create memap object
+    memap = MemapParser()
 
-    # Creates parser object
-    t = MemmapParser()
-  
-    # Decode map file depending on the toolchain
-    if args.toolchain == "ARM":
-        t.search_objects(os.path.abspath(args.file),args.toolchain)
-        t.parse_map_file_armcc(file_input)
-    elif args.toolchain == "GCC_ARM":
-        t.parse_map_file_gcc(file_input)
-    elif args.toolchain == "IAR":
-        print "WARNING: IAR Compiler not fully supported (yet)"
-        print " "
-        t.search_objects(os.path.abspath(args.file),args.toolchain)
-        t.parse_map_file_iar(file_input)
-    else:
-        print "Invalid toolchain. Options are: ARM, GCC_ARM, IAR"
-        sys.exit(0)
+    # Parse and decode a map file
+    if args.file and args.toolchain:
+        if memap.parse(args.file, args.toolchain) is False:
+            print "Unknown toolchain for memory statistics %s" %  args.toolchain
+            sys.exit(0)
+
+    # default export format is table
+    if not args.export:
+        args.export = 'table'
 
     # Write output in file
     if args.output != None:
-        try:
-            file_output = open(args.output,'w')
-            t.generate_output(file_output,args.json)
-            file_output.close()
-        except IOError as e:
-            print "I/O error({0}): {1}".format(e.errno, e.strerror)
-            sys.exit(0)
+        memap.generate_output(args.export, args.output)
     else: # Write output in screen
-        t.generate_output(sys.stdout,args.json)
-    
-    file_input.close()
+        memap.generate_output(args.export)
 
-    print "Elapsed time: %smS" %int(round((time.clock()-time_start)*1000))
-    
     sys.exit(0)
 
 if __name__ == "__main__":
-    main()
\ No newline at end of file
+    main()
--- a/targets.json	Tue Jun 07 11:35:02 2016 +0100
+++ b/targets.json	Tue Jun 14 11:07:30 2016 +0100
@@ -6,16 +6,19 @@
         "extra_labels": [],
         "is_disk_virtual": false,
         "macros": [],
+        "device_has": [],
         "features": [],
         "detect_code": [],
-        "public": false
+        "public": false,
+        "default_build": "standard"
     },
     "CM4_UARM": {
         "inherits": ["Target"],
         "core": "Cortex-M4",
         "default_toolchain": "uARM",
         "public": false,
-        "supported_toolchains": ["uARM"]
+        "supported_toolchains": ["uARM"],
+        "default_build": "small"
     },
     "CM4_ARM": {
         "inherits": ["Target"],
@@ -28,7 +31,8 @@
         "core": "Cortex-M4F",
         "default_toolchain": "uARM",
         "public": false,
-        "supported_toolchains": ["uARM"]
+        "supported_toolchains": ["uARM"],
+        "default_build": "small"
     },
     "CM4F_ARM": {
         "inherits": ["Target"],
@@ -47,7 +51,7 @@
         "progen": {"target": "lpc11c24_301"},
         "extra_labels": ["NXP", "LPC11XX_11CXX", "LPC11CXX"],
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"],
-        "features": ["ANALOGIN", "CAN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "CAN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC1114": {
         "inherits": ["LPCTarget"],
@@ -61,7 +65,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "LPC11U24": {
         "inherits": ["LPCTarget"],
@@ -76,7 +81,8 @@
             }
         },
         "detect_code": ["1040"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "OC_MBUINO": {
         "inherits": ["LPC11U24"],
@@ -88,14 +94,14 @@
             }
         },
         "extra_labels": ["NXP", "LPC11UXX"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC11U24_301": {
         "inherits": ["LPCTarget"],
         "core": "Cortex-M0",
         "extra_labels": ["NXP", "LPC11UXX"],
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC11U34_421": {
         "inherits": ["LPCTarget"],
@@ -103,7 +109,8 @@
         "default_toolchain": "uARM",
         "extra_labels": ["NXP", "LPC11UXX"],
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "MICRONFCBOARD": {
         "inherits": ["LPC11U34_421"],
@@ -122,7 +129,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC11U35_501": {
         "inherits": ["LPCTarget"],
@@ -136,7 +144,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC11U35_501_IBDAP": {
         "inherits": ["LPCTarget"],
@@ -150,7 +159,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "XADOW_M0": {
         "inherits": ["LPCTarget"],
@@ -164,7 +174,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC11U35_Y5_MBUG": {
         "inherits": ["LPCTarget"],
@@ -178,7 +189,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC11U37_501": {
         "inherits": ["LPCTarget"],
@@ -191,7 +203,8 @@
             "uvision": {
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
-        }
+        },
+        "default_build": "small"
     },
     "LPCCAPPUCCINO": {
         "inherits": ["LPC11U37_501"],
@@ -201,7 +214,7 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "ARCH_GPRS": {
         "supported_form_factors": ["ARDUINO"],
@@ -216,7 +229,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC11U68": {
         "supported_form_factors": ["ARDUINO"],
@@ -232,7 +246,8 @@
             }
         },
         "detect_code": ["1168"],
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI"],
+        "default_build": "small"
     },
     "LPC1347": {
         "inherits": ["LPCTarget"],
@@ -240,7 +255,7 @@
         "progen": {"target": "lpc1347"},
         "extra_labels": ["NXP", "LPC13XX"],
         "supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC1549": {
         "supported_form_factors": ["ARDUINO"],
@@ -256,7 +271,8 @@
             }
         },
         "detect_code": ["1549"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "INTERRUPTIN", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "INTERRUPTIN", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC1768": {
         "inherits": ["LPCTarget"],
@@ -265,7 +281,7 @@
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "GCC_CR", "IAR"],
         "progen": {"target": "mbed-lpc1768"},
         "detect_code": ["1010"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "ARCH_PRO": {
         "supported_form_factors": ["ARDUINO"],
@@ -275,7 +291,7 @@
         "macros": ["TARGET_LPC1768"],
         "inherits": ["LPCTarget"],
         "progen": {"target": "arch-pro"},
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "UBLOX_C027": {
         "supported_form_factors": ["ARDUINO"],
@@ -285,7 +301,7 @@
         "macros": ["TARGET_LPC1768"],
         "inherits": ["LPCTarget"],
         "progen": {"target": "ublox-c027"},
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_RED", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_RED", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "XBED_LPC1768": {
         "inherits": ["LPCTarget"],
@@ -295,7 +311,7 @@
         "macros": ["TARGET_LPC1768"],
         "progen": {"target": "lpc1768"},
         "detect_code": ["1010"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC2368": {
         "inherits": ["LPCTarget"],
@@ -303,7 +319,7 @@
         "progen": {"target": "lpc2368"},
         "extra_labels": ["NXP", "LPC23XX"],
         "supported_toolchains": ["ARM", "GCC_ARM", "GCC_CR"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC2460": {
         "inherits": ["LPCTarget"],
@@ -311,7 +327,7 @@
         "progen": {"target": "lpc2460"},
         "extra_labels": ["NXP", "LPC2460"],
         "supported_toolchains": ["GCC_ARM"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC810": {
         "inherits": ["LPCTarget"],
@@ -326,7 +342,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC812": {
         "supported_form_factors": ["ARDUINO"],
@@ -343,7 +360,8 @@
             }
         },
         "detect_code": ["1050"],
-        "features": ["ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC824": {
         "supported_form_factors": ["ARDUINO"],
@@ -359,7 +377,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "SSCI824": {
         "inherits": ["LPCTarget"],
@@ -374,7 +393,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "LPC4088": {
         "inherits": ["LPCTarget"],
@@ -387,7 +407,7 @@
             "toolchains": ["ARM_STD", "ARM_MICRO"]
         },
         "progen": {"target": "lpc4088"},
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC4088_DM": {
         "inherits": ["LPC4088"]
@@ -398,14 +418,14 @@
         "progen": {"target": "lpc4330"},
         "extra_labels": ["NXP", "LPC43XX", "LPC4330"],
         "supported_toolchains": ["ARM", "GCC_CR", "IAR", "GCC_ARM"],
-        "features": ["ANALOGIN", "ANALOGOUT", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC4330_M0": {
         "inherits": ["LPCTarget"],
         "core": "Cortex-M0",
         "extra_labels": ["NXP", "LPC43XX", "LPC4330"],
         "supported_toolchains": ["ARM", "GCC_CR", "IAR"],
-        "features": ["ANALOGIN", "ANALOGOUT", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "DEBUG_AWARENESS", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC4337": {
         "inherits": ["LPCTarget"],
@@ -413,7 +433,7 @@
         "progen": {"target": "lpc4337"},
         "extra_labels": ["NXP", "LPC43XX", "LPC4337"],
         "supported_toolchains": ["ARM"],
-        "features": ["ANALOGIN", "ANALOGOUT", "DEBUG_AWARENESS", "ERROR_RED", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "DEBUG_AWARENESS", "ERROR_RED", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "LPC1800": {
         "inherits": ["LPCTarget"],
@@ -435,7 +455,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"],
+        "default_build": "small"
     },
     "ELEKTOR_COCORICO": {
         "core": "Cortex-M0+",
@@ -450,7 +471,8 @@
             "uvision": {
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
-        }
+        },
+        "default_build": "small"
     },
     "KL05Z": {
         "supported_form_factors": ["ARDUINO"],
@@ -466,7 +488,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "KL25Z": {
         "supported_form_factors": ["ARDUINO"],
@@ -477,7 +500,7 @@
         "inherits": ["Target"],
         "progen": {"target": "frdm-kl25z"},
         "detect_code": ["0200"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "KL26Z": {
         "supported_form_factors": ["ARDUINO"],
@@ -487,7 +510,7 @@
         "supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
         "inherits": ["Target"],
         "progen": {"target": "kl26z"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "KL43Z": {
         "supported_form_factors": ["ARDUINO"],
@@ -497,7 +520,7 @@
         "supported_toolchains": ["GCC_ARM", "ARM"],
         "inherits": ["Target"],
         "progen": {"target": "frdm-kl43z"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "KL46Z": {
         "supported_form_factors": ["ARDUINO"],
@@ -508,7 +531,7 @@
         "inherits": ["Target"],
         "progen": {"target": "frdm-kl46z"},
         "detect_code": ["0220"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "K20D50M": {
         "inherits": ["Target"],
@@ -518,7 +541,7 @@
         "supported_toolchains": ["GCC_ARM", "ARM", "IAR"],
         "progen": {"target": "frdm-k20d50m"},
         "detect_code": ["0230"],
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "TEENSY3_1": {
         "inherits": ["Target"],
@@ -533,7 +556,7 @@
         },
         "progen": {"target": "teensy-31"},
         "detect_code": ["0230"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "K22F": {
         "supported_form_factors": ["ARDUINO"],
@@ -545,7 +568,7 @@
         "inherits": ["Target"],
         "progen": {"target": "frdm-k22f"},
         "detect_code": ["0231"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "KL27Z": {
         "inherits": ["Target"],
@@ -558,7 +581,8 @@
         "default_toolchain": "ARM",
         "detect_code": ["0261"],
         "progen_target": {"target": "frdm-kl27z"},
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "standard"
     },
     "K64F": {
         "supported_form_factors": ["ARDUINO"],
@@ -566,11 +590,15 @@
         "supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
         "extra_labels": ["Freescale", "KSDK2_MCUS", "FRDM", "KPSDK_MCUS", "KPSDK_CODE", "MCU_K64F"],
         "is_disk_virtual": true,
-        "macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED"],
+        "macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "MBEDTLS_ENTROPY_HARDWARE_ALT"],
         "inherits": ["Target"],
         "progen": {"target": "frdm-k64f"},
         "detect_code": ["0240"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "STORAGE"]
+    },
+    "K64F_UVISOR": {
+        "inherits": ["K64F"],
+        "extra_labels_add": ["K64F", "UVISOR_SUPPORTED"]
     },
     "MTS_GAMBIT": {
         "inherits": ["Target"],
@@ -580,7 +608,7 @@
         "is_disk_virtual": true,
         "macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "TARGET_K64F"],
         "progen": {"target": "mts-gambit"},
-        "features": ["I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "HEXIWEAR": {
         "inherits": ["Target"],
@@ -592,7 +620,8 @@
         "default_toolchain": "ARM",
         "detect_code": ["0214"],
         "progen": {"target": "hexiwear-k64f"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "standard"
     },
     "NUCLEO_F030R8": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -603,7 +632,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f030r8"},
         "detect_code": ["0725"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F031K6": {
         "supported_form_factors": ["ARDUINO"],
@@ -614,7 +644,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f031k6"},
         "detect_code": ["0791"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F042K6": {
         "supported_form_factors": ["ARDUINO"],
@@ -625,7 +656,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f042k6"},
         "detect_code": ["0785"],
-        "features": ["ANALOGIN", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F070RB": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -636,7 +668,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f070rb"},
         "detect_code": ["0755"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F072RB": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -647,7 +680,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f072rb"},
         "detect_code": ["0730"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F091RC": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -658,7 +692,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f091rc"},
         "detect_code": ["0750"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F103RB": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -669,7 +704,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f103rb"},
         "detect_code": ["0700"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F302R8": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -680,7 +716,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f302r8"},
         "detect_code": ["0705"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F303K8": {
         "supported_form_factors": ["ARDUINO"],
@@ -691,7 +728,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f303k8"},
         "detect_code": ["0775"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F303RE": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -702,7 +740,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f303re"},
         "detect_code": ["0745"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F334R8": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -713,7 +752,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f334r8"},
         "detect_code": ["0735"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F401RE": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -724,7 +764,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f401re"},
         "detect_code": ["0720"],
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F410RB": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -735,7 +776,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f410rb"},
         "detect_code": ["0740"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F411RE": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -746,7 +788,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f411re"},
         "detect_code": ["0740"],
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "ELMO_F411RE": {
         "supported_form_factors": ["ARDUINO"],
@@ -756,7 +799,8 @@
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM"],
         "inherits": ["Target"],
         "detect_code": ["----"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F446RE": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -767,7 +811,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-f446re"},
         "detect_code": ["0777"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "B96B_F446VE": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -777,7 +822,8 @@
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"],
         "inherits": ["Target"],
         "detect_code": ["0840"],
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_ASYNCH_DMA", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_ASYNCH_DMA", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_F746ZG": {
         "inherits": ["Target"],
@@ -791,7 +837,7 @@
             }
         },
         "detect_code": ["0816"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "NUCLEO_L031K6": {
         "inherits": ["Target"],
@@ -802,7 +848,8 @@
         "supported_form_factors": ["ARDUINO"],
         "detect_code": ["0790"],
         "progen": {"target": "nucleo-l031k6"},
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_L053R8": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -813,7 +860,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-l053r8"},
         "detect_code": ["0715"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_L073RZ": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -824,7 +872,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-l073rz"},
         "detect_code": ["0760"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_L152RE": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -835,7 +884,8 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-l152re"},
         "detect_code": ["0710"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NUCLEO_L476RG": {
         "supported_form_factors": ["ARDUINO", "MORPHO"],
@@ -846,14 +896,16 @@
         "inherits": ["Target"],
         "progen": {"target": "nucleo-l476rg"},
         "detect_code": ["0765"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "STM32F3XX": {
         "inherits": ["Target"],
         "core": "Cortex-M4",
         "default_toolchain": "uARM",
         "extra_labels": ["STM", "STM32F3XX"],
-        "supported_toolchains": ["ARM", "uARM", "GCC_ARM"]
+        "supported_toolchains": ["ARM", "uARM", "GCC_ARM"],
+        "default_build": "small"
     },
     "STM32F407": {
         "inherits": ["Target"],
@@ -870,7 +922,7 @@
         "macros": ["LSI_VALUE=32000"],
         "inherits": ["Target"],
         "progen": {"target": "lpc1768"},
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "DISCO_F051R8": {
         "inherits": ["Target"],
@@ -878,7 +930,8 @@
         "default_toolchain": "uARM",
         "extra_labels": ["STM", "STM32F0", "STM32F051", "STM32F051R8"],
         "supported_toolchains": ["GCC_ARM"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F100RB": {
         "inherits": ["Target"],
@@ -886,7 +939,8 @@
         "default_toolchain": "uARM",
         "extra_labels": ["STM", "STM32F1", "STM32F100RB"],
         "supported_toolchains": ["GCC_ARM"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F303VC": {
         "inherits": ["Target"],
@@ -894,7 +948,8 @@
         "default_toolchain": "uARM",
         "extra_labels": ["STM", "STM32F3", "STM32F303", "STM32F303VC"],
         "supported_toolchains": ["GCC_ARM"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F334C8": {
         "inherits": ["Target"],
@@ -904,7 +959,8 @@
         "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"],
         "progen": {"target": "disco-f334c8"},
         "detect_code": ["0810"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F407VG": {
         "inherits": ["Target"],
@@ -912,7 +968,7 @@
         "progen": {"target": "disco-f407vg"},
         "extra_labels": ["STM", "STM32F4", "STM32F407", "STM32F407VG"],
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "DISCO_F429ZI": {
         "inherits": ["Target"],
@@ -921,7 +977,8 @@
         "extra_labels": ["STM", "STM32F4", "STM32F429", "STM32F429ZI"],
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"],
         "progen": {"target": "disco-f429zi"},
-        "features": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F469NI": {
         "supported_form_factors": ["ARDUINO"],
@@ -932,7 +989,8 @@
         "inherits": ["Target"],
         "progen": {"target": "disco-f469ni"},
         "detect_code": ["0788"],
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_L053C8": {
         "inherits": ["Target"],
@@ -941,7 +999,8 @@
         "extra_labels": ["STM", "STM32L0", "STM32L053C8"],
         "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"],
         "progen": {"target": "disco-l053c8"},
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F746NG": {
         "inherits": ["Target"],
@@ -950,7 +1009,7 @@
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"],
         "progen": {"target": "disco-f746ng"},
         "detect_code": ["0815"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "DISCO_L476VG": {
         "inherits": ["Target"],
@@ -960,7 +1019,8 @@
         "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"],
         "progen": {"target": "disco-l476vg"},
         "detect_code": ["0820"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "MTS_MDOT_F405RG": {
         "inherits": ["Target"],
@@ -970,7 +1030,7 @@
         "is_disk_virtual": true,
         "macros": ["HSE_VALUE=26000000", "OS_CLOCK=48000000"],
         "progen": {"target": "mts-mdot-f405rg"},
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "MTS_MDOT_F411RE": {
         "inherits": ["Target"],
@@ -983,7 +1043,7 @@
             "toolchains": ["GCC_ARM", "ARM_STD", "ARM_MICRO"]
         },
         "progen": {"target": "mts-mdot-f411re"},
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "MTS_DRAGONFLY_F411RE": {
         "inherits": ["Target"],
@@ -996,7 +1056,7 @@
             "toolchains": ["GCC_ARM", "ARM_STD", "ARM_MICRO"]
         },
         "progen": {"target": "mts-dragonfly-f411re"},
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "MOTE_L152RC": {
         "inherits": ["Target"],
@@ -1006,7 +1066,8 @@
         "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"],
         "progen": {"target": "stm32l151rc"},
         "detect_code": ["4100"],
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "DISCO_F401VC": {
         "inherits": ["Target"],
@@ -1014,7 +1075,8 @@
         "default_toolchain": "GCC_ARM",
         "extra_labels": ["STM", "STM32F4", "STM32F401", "STM32F401VC"],
         "supported_toolchains": ["GCC_ARM"],
-        "features": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "standard"
     },
     "UBLOX_C029": {
         "supported_form_factors": ["ARDUINO"],
@@ -1024,7 +1086,8 @@
         "extra_labels": ["STM", "STM32F4", "STM32F439", "STM32F439ZI"],
         "macros": ["HSE_VALUE=24000000", "HSE_STARTUP_TIMEOUT=5000"],
         "inherits": ["Target"],
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "NZ32_SC151": {
         "inherits": ["Target"],
@@ -1034,7 +1097,8 @@
         "extra_labels": ["STM", "STM32L1", "STM32L151RC"],
         "supported_toolchains": ["ARM", "uARM", "GCC_ARM"],
         "progen": {"target": "stm32l151rc"},
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "MCU_NRF51": {
         "inherits": ["Target"],
@@ -1173,23 +1237,26 @@
         "inherits": ["MCU_NRF51_16K"],
         "progen": {"target": "mkit"},
         "extra_labels_add": ["NRF51822", "NRF51822_MKIT"],
-        "macros_add": ["TARGET_NRF51822_MKIT"]
+        "macros_add": ["TARGET_NRF51822_MKIT"],
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "NRF51822_BOOT": {
         "inherits": ["MCU_NRF51_16K_BOOT"],
         "extra_labels_add": ["NRF51822", "NRF51822_MKIT"],
-        "macros_add": ["TARGET_NRF51822_MKIT"]
+        "macros_add": ["TARGET_NRF51822_MKIT"],
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "NRF51822_OTA": {
         "inherits": ["MCU_NRF51_16K_OTA"],
         "extra_labels_add": ["NRF51822", "NRF51822_MKIT"],
-        "macros_add": ["TARGET_NRF51822_MKIT"]
+        "macros_add": ["TARGET_NRF51822_MKIT"],
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "ARCH_BLE": {
         "supported_form_factors": ["ARDUINO"],
         "inherits": ["MCU_NRF51_16K"],
         "progen": {"target": "arch-ble"},
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "ARCH_BLE_BOOT": {
         "supported_form_factors": ["ARDUINO"],
@@ -1224,7 +1291,7 @@
     "SEEED_TINY_BLE": {
         "inherits": ["MCU_NRF51_16K"],
         "progen": {"target": "seed-tinyble"},
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "SEEED_TINY_BLE_BOOT": {
         "inherits": ["MCU_NRF51_16K_BOOT"],
@@ -1240,7 +1307,7 @@
         "inherits": ["MCU_NRF51_16K"],
         "progen": {"target": "hrm1017"},
         "macros_add": ["TARGET_NRF_LFCLK_RC"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "HRM1017_BOOT": {
         "inherits": ["MCU_NRF51_16K_BOOT"],
@@ -1256,7 +1323,7 @@
         "supported_form_factors": ["ARDUINO"],
         "inherits": ["MCU_NRF51_16K"],
         "progen": {"target": "rblab-nrf51822"},
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "RBLAB_NRF51822_BOOT": {
         "supported_form_factors": ["ARDUINO"],
@@ -1272,7 +1339,7 @@
     },
     "RBLAB_BLENANO": {
         "inherits": ["MCU_NRF51_16K"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "RBLAB_BLENANO_BOOT": {
         "inherits": ["MCU_NRF51_16K_BOOT"],
@@ -1286,11 +1353,11 @@
     },
     "NRF51822_Y5_MBUG": {
         "inherits": ["MCU_NRF51_16K"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "WALLBOT_BLE": {
         "inherits": ["MCU_NRF51_16K"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "WALLBOT_BLE_BOOT": {
         "inherits": ["MCU_NRF51_16K_BOOT"],
@@ -1307,7 +1374,7 @@
         "program_cycle_s": 10,
         "progen": {"target": "dfcm-nnn40"},
         "macros_add": ["TARGET_NRF_LFCLK_RC"],
-        "features": ["ANALOGIN", "DEBUG_AWARENESS", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "DEBUG_AWARENESS", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "DELTA_DFCM_NNN40_BOOT": {
         "inherits": ["MCU_NRF51_32K_BOOT"],
@@ -1325,7 +1392,7 @@
         "supported_form_factors": ["ARDUINO"],
         "inherits": ["MCU_NRF51_32K"],
         "progen": {"target": "nrf51-dk"},
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "NRF51_DK_BOOT": {
         "supported_form_factors": ["ARDUINO"],
@@ -1342,7 +1409,7 @@
     "NRF51_DONGLE": {
         "inherits": ["MCU_NRF51_32K"],
         "progen": {"target": "nrf51-dongle"},
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "NRF51_DONGLE_BOOT": {
         "inherits": ["MCU_NRF51_32K_BOOT"],
@@ -1357,7 +1424,7 @@
     "NRF51_MICROBIT": {
         "inherits": ["MCU_NRF51_16K_S110"],
         "macros_add": ["TARGET_NRF_LFCLK_RC"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "NRF51_MICROBIT_BOOT": {
         "inherits": ["MCU_NRF51_16K_BOOT_S110"],
@@ -1387,7 +1454,7 @@
     "TY51822R3": {
         "inherits": ["MCU_NRF51_32K"],
         "macros_add": ["TARGET_NRF_32MHZ_XTAL"],
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SLEEP", "SPI", "SPISLAVE"]
     },
     "TY51822R3_BOOT": {
         "inherits": ["MCU_NRF51_32K_BOOT"],
@@ -1402,7 +1469,7 @@
     "ARM_MPS2_Target": {
         "inherits": ["Target"],
         "public": false,
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_MPS2_M0": {
         "inherits": ["ARM_MPS2_Target"],
@@ -1410,7 +1477,7 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "MPS2", "MPS2_M0"],
         "macros": ["CMSDK_CM0"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_MPS2_M0P": {
         "inherits": ["ARM_MPS2_Target"],
@@ -1418,7 +1485,7 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "MPS2", "MPS2_M0P"],
         "macros": ["CMSDK_CM0plus"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_MPS2_M1": {
         "inherits": ["ARM_MPS2_Target"],
@@ -1426,7 +1493,7 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "MPS2", "MPS2_M1"],
         "macros": ["CMSDK_CM1"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_MPS2_M3": {
         "inherits": ["ARM_MPS2_Target"],
@@ -1434,7 +1501,7 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "MPS2", "MPS2_M3"],
         "macros": ["CMSDK_CM3"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_MPS2_M4": {
         "inherits": ["ARM_MPS2_Target"],
@@ -1442,7 +1509,7 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "MPS2", "MPS2_M4"],
         "macros": ["CMSDK_CM4"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_MPS2_M7": {
         "inherits": ["ARM_MPS2_Target"],
@@ -1450,12 +1517,12 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "MPS2", "MPS2_M7"],
         "macros": ["CMSDK_CM7"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_IOTSS_Target": {
         "inherits": ["Target"],
         "public": false,
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
     },
     "ARM_IOTSS_BEID": {
         "inherits": ["ARM_IOTSS_Target"],
@@ -1463,7 +1530,22 @@
         "supported_toolchains": ["ARM"],
         "extra_labels": ["ARM_SSG", "IOTSS", "IOTSS_BEID"],
         "macros": ["CMSDK_BEID"],
-        "features": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+        "device_has": ["AACI", "ANALOGIN", "CLCD", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "TSC"]
+    },
+    "ARM_BEETLE_SOC": {
+        "inherits": ["ARM_IOTSS_Target"],
+        "core": "Cortex-M3",
+        "supported_toolchains": ["ARM", "GCC_ARM"],
+        "default_toolchain": "ARM",
+        "extra_labels": ["ARM_SSG", "BEETLE"],
+        "macros": ["CMSDK_BEETLE", "WSF_MS_PER_TICK=20", "WSF_TOKEN_ENABLED=FALSE", "WSF_TRACE_ENABLED=TRUE", "WSF_ASSERT_ENABLED=FALSE", "WSF_PRINTF_MAX_LEN=128", "ASIC", "CONFIG_HOST_REV=0x20", "CONFIG_ALLOW_DEEP_SLEEP=FALSE", "HCI_VS_TARGET", "CONFIG_ALLOW_SETTING_WRITE=TRUE", "WSF_MAX_HANDLERS=20", "NO_LEDS"],
+        "progen": {
+            "target": "beetle",
+            "uvision5": {
+                "template": ["uvision5_arm_beetle_soc.uvproj.tmpl"]
+            }
+        },
+        "device_has": ["ANALOGIN", "CLCD", "I2C", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI"]
     },
     "RZ_A1H": {
         "supported_form_factors": ["ARDUINO"],
@@ -1478,7 +1560,7 @@
                 "template": ["iar_rz_a1h.ewp.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
     },
     "VK_RZ_A1H": {
         "inherits": ["Target"],
@@ -1493,7 +1575,8 @@
             }
         },
         "program_cycle_s": 2,
-        "features": ["ANALOGIN", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "CAN", "ERROR_PATTERN", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
+        "default_build": "standard"
     },
     "MAXWSNENV": {
         "inherits": ["Target"],
@@ -1502,7 +1585,7 @@
         "extra_labels": ["Maxim", "MAX32610"],
         "supported_toolchains": ["GCC_ARM", "IAR", "ARM"],
         "progen": {"target": "maxwsnenv"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "STDIO_MESSAGES"]
     },
     "MAX32600MBED": {
         "inherits": ["Target"],
@@ -1511,7 +1594,7 @@
         "extra_labels": ["Maxim", "MAX32600"],
         "supported_toolchains": ["GCC_ARM", "IAR", "ARM"],
         "progen": {"target": "max32600mbed"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "STDIO_MESSAGES"]
     },
     "EFM32GG_STK3700": {
         "inherits": ["Target"],
@@ -1520,7 +1603,7 @@
         "extra_labels": ["Silicon_Labs", "EFM32"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "efm32gg-stk"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
     },
     "EFM32LG_STK3600": {
         "inherits": ["Target"],
@@ -1529,7 +1612,7 @@
         "extra_labels": ["Silicon_Labs", "EFM32"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "efm32lg-stk"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
     },
     "EFM32WG_STK3800": {
         "inherits": ["Target"],
@@ -1538,7 +1621,7 @@
         "extra_labels": ["Silicon_Labs", "EFM32"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "efm32wg-stk"},
-        "features": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
     },
     "EFM32ZG_STK3200": {
         "inherits": ["Target"],
@@ -1553,7 +1636,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "EFM32HG_STK3400": {
         "inherits": ["Target"],
@@ -1568,7 +1652,8 @@
                 "template": ["uvision_microlib.uvproj.tmpl"]
             }
         },
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"],
+        "default_build": "small"
     },
     "EFM32PG_STK3401": {
         "inherits": ["Target"],
@@ -1577,7 +1662,7 @@
         "extra_labels": ["Silicon_Labs", "EFM32"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"],
         "progen": {"target": "efm32pg-stk"},
-        "features": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"]
     },
     "WIZWIKI_W7500": {
         "supported_form_factors": ["ARDUINO"],
@@ -1586,7 +1671,7 @@
         "supported_toolchains": ["uARM", "ARM"],
         "inherits": ["Target"],
         "progen": {"target": "wizwiki-w7500"},
-        "features": ["ANALOGIN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "WIZWIKI_W7500P": {
         "supported_form_factors": ["ARDUINO"],
@@ -1595,7 +1680,7 @@
         "supported_toolchains": ["uARM", "ARM"],
         "inherits": ["Target"],
         "progen": {"target": "wizwiki-w7500p"},
-        "features": ["ANALOGIN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "WIZWIKI_W7500ECO": {
         "inherits": ["Target"],
@@ -1603,7 +1688,7 @@
         "progen": {"target": "wizwiki_w7500eco"},
         "extra_labels": ["WIZNET", "W7500x", "WIZwiki_W7500ECO"],
         "supported_toolchains": ["uARM", "ARM"],
-        "features": ["ANALOGIN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
+        "device_has": ["ANALOGIN", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "SPISLAVE", "STDIO_MESSAGES"]
     },
     "SAMR21G18A": {
         "inherits": ["Target"],
@@ -1612,7 +1697,7 @@
         "extra_labels": ["Atmel", "SAM_CortexM0P", "SAMR21"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "samr21g18a"},
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
     },
     "SAMD21J18A": {
         "inherits": ["Target"],
@@ -1621,7 +1706,7 @@
         "extra_labels": ["Atmel", "SAM_CortexM0P", "SAMD21"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "samd21j18a"},
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
     },
     "SAMD21G18A": {
         "inherits": ["Target"],
@@ -1630,7 +1715,7 @@
         "extra_labels": ["Atmel", "SAM_CortexM0P", "SAMD21"],
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "samd21g18a"},
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
     },
     "SAML21J18A": {
         "inherits": ["Target"],
@@ -1640,7 +1725,7 @@
         "supported_toolchains": ["GCC_ARM", "ARM", "uARM"],
         "progen": {"target": "samr21j18a"},
         "progen_target": "samr21j18a",
-        "features": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
+        "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
     },
     "SAMG55J19": {
         "inherits": ["Target"],
@@ -1651,6 +1736,7 @@
         "default_toolchain": "ARM",
         "progen": {"target": "samg55j19"},
         "progen_target": "samg55j19",
-        "features": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"]
+        "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"],
+        "default_build": "standard"
     }
-}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/config_test.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,94 @@
+"""
+mbed SDK
+Copyright (c) 2011-2016 ARM Limited
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+from tools.build_api import get_config
+from tools.config import ConfigException
+import os, sys
+
+# Compare the output of config against a dictionary of known good results
+def compare_config(cfg, expected):
+    try:
+        for k in cfg:
+            if cfg[k].value != expected[k]:
+                return "'%s': expected '%s', got '%s'" % (k, expected[k], cfg[k].value)
+    except KeyError:
+        return "Unexpected key '%s' in configuration data" % k
+    for k in expected:
+        if k != "desc" and k != "expected_macros" and not k in cfg:
+            return "Expected key '%s' was not found in configuration data" % k
+    return ""
+
+def test_tree(full_name, name):
+    failed = 0
+    sys.path.append(full_name)
+    if "test_data" in sys.modules:
+       del sys.modules["test_data"]
+    import test_data
+    for target, expected in test_data.expected_results.items():
+        sys.stdout.write("%s:'%s'(%s) " % (name, expected["desc"], target))
+        sys.stdout.flush()
+        err_msg = None
+        try:
+            cfg, macros = get_config(full_name, target, "GCC_ARM")
+        except ConfigException as e:
+            err_msg = e.message
+        if err_msg:
+            if expected.has_key("exception_msg"):
+                if err_msg.find(expected["exception_msg"]) == -1:
+                    print "FAILED!"
+                    sys.stderr.write("    Unexpected error message!\n")
+                    sys.stderr.write("    Expected: '%s'\n" % expected["exception_msg"])
+                    sys.stderr.write("    Got: '%s'\n" % err_msg)
+                    failed += 1
+                else:
+                    print "OK"
+            else:
+                print "FAILED!"
+                sys.stderr.write("    Error while getting configuration!\n")
+                sys.stderr.write("    " + err_msg + "\n")
+                failed += 1
+        else:
+            res = compare_config(cfg, expected)
+            if res:
+                print "FAILED!"
+                sys.stdout.write("    " + res + "\n")
+                failed += 1
+            else:
+                expected_macros = expected.get("expected_macros", None)
+                if expected_macros is not None:
+                    if sorted(expected_macros) != sorted(macros):
+                        print "FAILED!"
+                        sys.stderr.write("    List of macros doesn't match\n")
+                        sys.stderr.write("    Expected: '%s'\n" % ",".join(sorted(expected_macros)))
+                        sys.stderr.write("    Got: '%s'\n" % ",".join(sorted(expected_macros)))
+                        failed += 1
+                    else:
+                        print "OK"
+                else:
+                    print "OK"
+    sys.path.remove(full_name)
+    return failed
+
+failed = 0
+root_dir = os.path.abspath(os.path.dirname(__file__))
+tlist = sorted(os.listdir(root_dir), key = lambda e: int(e[4:]) if e.startswith('test') else -1)
+for test_name in tlist:
+    full_name = os.path.join(root_dir, test_name)
+    if os.path.isdir(full_name) and test_name.startswith('test'):
+        failed += test_tree(full_name, test_name)
+sys.exit(failed)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test01/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,43 @@
+{
+    "custom_targets": {
+        "b1": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "base1_1": "v_base1_1_b1",
+                "base1_2": "v_base1_2_b1",
+                "base1_3": "v_base1_3_b1"
+            }
+        },
+        "d1": {
+            "inherits": ["b1"],
+            "config": {
+                "derived1": "v_derived1_d1",
+                "derived2": "v_derived2_d1"
+            },
+            "overrides": {
+                "base1_1": "v_base1_1_d1",
+                "base1_2": "v_base1_2_d1"
+            }
+        },
+        "b2": {
+            "config": {
+                "base2_1": "v_base2_1_b2",
+                "base2_2": "v_base2_2_b2"
+            }
+        },
+        "f": {
+            "inherits": ["b2", "d1"],
+            "config": {
+                "f1_1": "v_f1_1_f",
+                "f1_2": "v_f1_2_f"
+            },
+            "overrides": {
+                "base2_1": "v_base2_1_f",
+                "base1_1": "v_base1_1_f",
+                "derived2": "v_derived2_f",
+                "f1_1": "v_f1_1_f_override"
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test01/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,46 @@
+# Test for configuration data defined in targets
+# A base target (B1) defines 3 configuration parameters (base1_1, base1_2 and base1_3)
+# A derived target (D1) inherits drom B1 and defines one configuration parameters (derived1 and derived2) and overrides base1_1 and base1_2
+# Another base target (B2) defines its own configuration parameters (base2_1 and base2_2)
+# The final target F derives from B2 and D1, defines two configuration paramaters (f1_1 and f1_2)
+# and overrides base2_1, base1_1, derived2 and its own configuration parameter f1_1 (which is legal)
+# Final result:
+#     base1_1 must have the value defined in F
+#     base1_2 must have the value defined in D1
+#     base1_3 must have the value defined in B1
+#     derived1 must have the value defined in D1
+#     derived2 must have the value defined in F
+#     base2_1 must have the value defined in F
+#     base2_2 must have the value defined in B2
+#     f1_1 must have the value defined and then overriden in F
+#     f1_2 must have the value defined in F
+
+expected_results = {
+    "f": {
+        "desc": "test multiple target inheritance",
+        "target.base1_1": "v_base1_1_f",
+        "target.base1_2": "v_base1_2_d1",
+        "target.base1_3": "v_base1_3_b1",
+        "target.derived1": "v_derived1_d1",
+        "target.derived2": "v_derived2_f",
+        "target.base2_1": "v_base2_1_f",
+        "target.base2_2": "v_base2_2_b2",
+        "target.f1_1": "v_f1_1_f_override",
+        "target.f1_2": "v_f1_2_f"
+    },
+    "b1": {
+        "desc": "test with a single base target, no inheritance",
+        "target.base1_1": "v_base1_1_b1",
+        "target.base1_2": "v_base1_2_b1",
+        "target.base1_3": "v_base1_3_b1"
+    },
+    "d1": {
+        "desc": "test single target inheritance",
+        "target.base1_1": "v_base1_1_d1",
+        "target.base1_2": "v_base1_2_d1",
+        "target.base1_3": "v_base1_3_b1",
+        "target.derived1": "v_derived1_d1",
+        "target.derived2": "v_derived2_d1"
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test02/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,47 @@
+{
+    "custom_targets": {
+        "b1": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "base1_1": "v_base1_1_b1",
+                "base1_2": "v_base1_2_b1",
+                "base1_3": "v_base1_3_b1"
+            }
+        },
+        "d1": {
+            "inherits": ["b1"],
+            "config": {
+                "derived1": "v_derived1_d1",
+                "derived2": "v_derived2_d1"
+            },
+            "overrides": {
+                "base1_1": "v_base1_1_d1",
+                "base1_2": "v_base1_2_d1"
+            }
+        },
+        "b2": {
+            "inherits": ["b1"],
+            "config": {
+                "base2_1": "v_base2_1_b2",
+                "base2_2": "v_base2_2_b2"
+            },
+            "overrides": {
+                "base1_2": "v_base1_2_b2"
+            }
+        },
+        "f": {
+            "inherits": ["d1", "b2"],
+            "config": {
+                "f1_1": "v_f1_1_f",
+                "f1_2": "v_f1_2_f"
+            },
+            "overrides": {
+                "base2_1": "v_base2_1_f",
+                "base1_1": "v_base1_1_f",
+                "derived2": "v_derived2_f",
+                "f1_1": "v_f1_1_f_override"
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test02/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,30 @@
+# This is similar to test1, but this time B2 also inherits from B1, which allows it to override its config data.
+# B2 also overrides base1_2, like D1.
+# The order of inheritace in F is also reversed ([D1, B2] instead of [B2, D1])
+# Since the last override of base1_2 in inheritance order is in B2, base1_2 must now
+# have the value that was overriden in B2, not in D1.
+# This test also shows that multiple inheritance works for a simple diamond shaped inheritance pattern
+
+expected_results = {
+    "f": {
+        "desc": "test multiple target inheritance (diamond shape)",
+        "target.base1_1": "v_base1_1_f",
+        "target.base1_2": "v_base1_2_b2",
+        "target.base1_3": "v_base1_3_b1",
+        "target.derived1": "v_derived1_d1",
+        "target.derived2": "v_derived2_f",
+        "target.base2_1": "v_base2_1_f",
+        "target.base2_2": "v_base2_2_b2",
+        "target.f1_1": "v_f1_1_f_override",
+        "target.f1_2": "v_f1_2_f"
+    },
+    "b2": {
+        "desc": "another single inheritance test",
+        "target.base1_1": "v_base1_1_b1",
+        "target.base1_2": "v_base1_2_b2",
+        "target.base1_3": "v_base1_3_b1",
+        "target.base2_1": "v_base2_1_b2",
+        "target.base2_2": "v_base2_2_b2"
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test03/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,46 @@
+{
+    "custom_targets": {
+        "b1": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "base1_1": "v_base1_1_b1",
+                "base1_2": "v_base1_2_b1",
+                "base1_3": "v_base1_3_b1"
+            }
+        },
+        "d1": {
+            "inherits": ["b1"],
+            "config": {
+                "derived1": "v_derived1_d1",
+                "derived2": "v_derived2_d1"
+            },
+            "overrides": {
+                "base1_1": "v_base1_1_d1",
+                "base1_2": "v_base1_2_d1"
+            }
+        },
+        "b2": {
+            "config": {
+                "base2_1": "v_base2_1_b2",
+                "base2_2": "v_base2_2_b2"
+            },
+            "overrides": {
+                "base1_1": "v_base1_1_b2"
+            }
+        },
+        "f": {
+            "inherits": ["b2", "d1"],
+            "config": {
+                "f1_1": "v_f1_1_f",
+                "f1_2": "v_f1_2_f"
+            },
+            "overrides": {
+                "base2_1": "v_base2_1_f",
+                "base1_1": "v_base1_1_f",
+                "derived2": "v_derived2_f",
+                "f1_1": "v_f1_1_f_override"
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test03/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,18 @@
+# Similar to test1, but this time B2 attempt to override base1_1. Since B2 doesn't directly inherit
+# from B1, this must raise an error
+
+expected_results = {
+    "f": {
+        "desc": "attempt to override undefined parameter in inherited target",
+        "exception_msg": "Attempt to override undefined parameter 'base1_1' in 'target:b2'"
+    },
+    "d1": {
+        "desc": "single target inheritance again",
+        "target.base1_1": "v_base1_1_d1",
+        "target.base1_2": "v_base1_2_d1",
+        "target.base1_3": "v_base1_3_b1",
+        "target.derived1": "v_derived1_d1",
+        "target.derived2": "v_derived2_d1"
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test04/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,46 @@
+{
+    "custom_targets": {
+        "b1": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "base1_1": "v_base1_1_b1",
+                "base1_2": "v_base1_2_b1",
+                "base1_3": "v_base1_3_b1"
+            }
+        },
+        "d1": {
+            "inherits": ["b1"],
+            "config": {
+                "derived1": "v_derived1_d1",
+                "derived2": "v_derived2_d1"
+            },
+            "overrides": {
+                "base1_1": "v_base1_1_d1",
+                "base1_2": "v_base1_2_d1"
+            }
+        },
+        "b2": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "base2_1": "v_base2_1_b2",
+                "base2_2": "v_base2_2_b2",
+                "base1_1": "v_base1_1_b2"
+            }
+        },
+        "f": {
+            "inherits": ["b2", "d1"],
+            "config": {
+                "f1_1": "v_f1_1_f",
+                "f1_2": "v_f1_2_f"
+            },
+            "overrides": {
+                "base2_1": "v_base2_1_f",
+                "base1_1": "v_base1_1_f",
+                "derived2": "v_derived2_f",
+                "f1_1": "v_f1_1_f_override"
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test04/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,18 @@
+# Similar to test1, but this time B2 attempt to define base1_1. Since base1_1
+# is already defined in B1 and F derives from both B1 and B2, this results
+# in an error. However, when building for B2 instead of F, defining base1_1
+# should be OK.
+
+expected_results = {
+    "f": {
+        "desc": "attempt to redefine parameter in target inheritance tree",
+        "exception_msg": "Parameter name 'base1_1' defined in both 'target:b2' and 'target:b1'"
+    },
+    "b2": {
+        "desc": "it should be OK to define parameters with the same name in non-related targets",
+        "target.base2_1": "v_base2_1_b2",
+        "target.base2_2": "v_base2_2_b2",
+        "target.base1_1": "v_base1_1_b2"
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test05/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,35 @@
+{
+    "custom_targets": {
+        "base": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0"
+        },
+        "b1": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b1_label"]
+        },
+        "b2": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b2_label"]
+        },
+        "both": {
+            "inherits": ["b1", "b2"]
+        }
+    },
+    "config": {
+        "app1": "v_app1",
+        "app2": "v_app2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "app1": "v_app1[b1_label]"
+        },
+        "b2_label": {
+            "app2": "v_app2[b2_label]"
+        },
+        "dummy_label": {
+            "app1": "dummy.app1",
+            "app2": "dummy.app2"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test05/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,29 @@
+# This tests overriding configuration values based on target labels.
+# Four targets are defined:
+#    - "base" is the base target, it doesn't define any extra labels
+#    - "b1" inherits from "base" and adds the "b1_label" label
+#    - "b2" inherits from "base" and adds the "b2_label" label
+#    - "both" inherits from both "b1" and "b2", so it inherits both labels
+
+expected_results = {
+    "b1": {
+        "desc": "override values based on labels (first label)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2"
+    },
+    "b2": {
+        "desc": "override values based on labels (second label)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2[b2_label]"
+    },
+    "both": {
+        "desc": "override values based on labels (both labels)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2[b2_label]"
+    },
+    "base": {
+        "desc": "override values based on labels (no labels)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test06/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,17 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib2[b1_label]",
+            "p2": "v_p2_lib2[b1_label]"
+        },
+        "b2_label": {
+            "p1": "v_p1_lib2[b2_label]",
+            "p2": "v_p2_lib2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test06/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,16 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib1[b1_label]"
+        },
+        "b2_label": {
+            "p2": "v_p2_lib1[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test06/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,31 @@
+{
+    "custom_targets": {
+        "base": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0"
+        },
+        "b1": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b1_label"]
+        },
+        "b2": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b2_label"]
+        },
+        "both": {
+            "inherits": ["b1", "b2"]
+        }
+    },
+    "config": {
+        "app1": "v_app1",
+        "app2": "v_app2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "app1": "v_app1[b1_label]"
+        },
+        "b2_label": {
+            "app2": "v_app2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test06/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,49 @@
+# This build on top of test5 by adding a few libraries with their own configurations
+# and overrides. The same targets are used for building and testing (base, b1, b2, both)
+
+expected_results = {
+   "base": {
+        "desc": "override values based on labels with libs (no labels)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2",
+        "lib2.p2": "v_p2_lib2"
+    },
+    "b1": {
+        "desc": "override values based on labels with libs (first label)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1[b1_label]",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2[b1_label]",
+        "lib2.p2": "v_p2_lib2[b1_label]"
+    },
+    "b2": {
+        "desc": "override values based on labels with libs (second label)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2[b2_label]",
+        "lib2.p2": "v_p2_lib2[b2_label]"
+    },
+    # The values for lib2.p1 and lib2.p2 illustrate how overriding on multiple
+    # labels work. In lib2, both lib2.p1 and lib2.p2 are overriden for both
+    # labels (b1_label and b2_label). However, since "b2_label" is specified
+    # after "b1_label", it sets the final values of the overrides.
+    "both": {
+        "desc": "override values based on labels with libs (both labels)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1[b1_label]",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2[b2_label]",
+        "lib2.p2": "v_p2_lib2[b2_label]"
+    },
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test07/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,17 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib2[b1_label]",
+            "p2": "v_p2_lib2[b1_label]"
+        },
+        "b2_label": {
+            "p1": "v_p1_lib2[b2_label]",
+            "p2": "v_p2_lib2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test07/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,16 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib1[b1_label]"
+        },
+        "b2_label": {
+            "p2": "v_p2_lib1[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test07/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,36 @@
+{
+    "custom_targets": {
+        "base": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0"
+        },
+        "b1": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b1_label"]
+        },
+        "b2": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b2_label"]
+        },
+        "both": {
+            "inherits": ["b1", "b2"]
+        }
+    },
+    "config": {
+        "app1": "v_app1",
+        "app2": "v_app2"
+    },
+    "target_overrides": {
+        "*": {
+            "lib1.p3": "v_p3_lib1_app",
+            "lib1.p1": "v_p1_lib1_app",
+            "lib2.p1": "v_p1_lib2_app"
+        },
+        "b1_label": {
+            "app1": "v_app1[b1_label]"
+        },
+        "b2_label": {
+            "app2": "v_app2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test07/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,48 @@
+# This build on top of test6 by adding overrides for libs in the application
+
+expected_results = {
+   "base": {
+        "desc": "override values based on labels with libs (no labels)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2"
+    },
+    "b1": {
+        "desc": "override values based on labels with libs (first label)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b1_label]"
+    },
+    "b2": {
+        "desc": "override values based on labels with libs (second label)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b2_label]"
+    },
+    # The values for lib2.p1 and lib2.p2 illustrate how overriding on multiple
+    # labels work. In lib2, both lib2.p1 and lib2.p2 are overriden for both
+    # labels (b1_label and b2_label). However, since "b2_label" is specified
+    # after "b1_label", it sets the final values of the overrides.
+    "both": {
+        "desc": "override values based on labels with libs (both labels)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b2_label]"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test08/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,17 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib2[b1_label]",
+            "p2": "v_p2_lib2[b1_label]"
+        },
+        "b2_label": {
+            "p1": "v_p1_lib2[b2_label]",
+            "p2": "v_p2_lib2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test08/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,16 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib1[b1_label]"
+        },
+        "b2_label": {
+            "p2": "v_p2_lib1[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test08/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,54 @@
+{
+    "custom_targets": {
+        "base": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "par1": "v_par1_base",
+                "par2": "v_par2_base",
+                "par3": "v_par3_base"
+            }
+        },
+        "b1": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b1_label"],
+            "overrides": {
+                "par1": "v_par1_b1"
+            }
+        },
+        "b2": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b2_label"],
+            "overrides": {
+                "par2": "v_par2_b2"
+            }
+        },
+        "both": {
+            "inherits": ["b1", "b2"],
+            "config": {
+                "par4": "v_par4_both"
+            },
+            "overrides": {
+                "par3": "v_par3_both"
+            }
+        }
+    },
+    "config": {
+        "app1": "v_app1",
+        "app2": "v_app2"
+    },
+    "target_overrides": {
+        "*": {
+            "lib1.p3": "v_p3_lib1_app",
+            "lib1.p1": "v_p1_lib1_app",
+            "lib2.p1": "v_p1_lib2_app",
+            "target.par1": "v_par1_target_app"
+        },
+        "b1_label": {
+            "app1": "v_app1[b1_label]"
+        },
+        "b2_label": {
+            "app2": "v_app2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test08/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,58 @@
+# This build on top of test7 by adding some configuration values in targets
+# and overriding them in the application
+
+expected_results = {
+   "base": {
+        "desc": "override values based on labels with libs and target params (no labels)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_base",
+        "target.par3": "v_par3_base"
+    },
+    "b1": {
+        "desc": "override values based on labels with libs and target params (first label)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b1_label]",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_base",
+        "target.par3": "v_par3_base"
+    },
+    "b2": {
+        "desc": "override values based on labels with libs and target params (second label)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b2_label]",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_b2",
+        "target.par3": "v_par3_base"
+    },
+    "both": {
+        "desc": "override values based on labels with libs and target params (both labels)",
+        "app.app1": "v_app1[b1_label]",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b2_label]",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_b2",
+        "target.par3": "v_par3_both",
+        "target.par4": "v_par4_both"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test09/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,17 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib2[b1_label]",
+            "p2": "v_p2_lib2[b1_label]"
+        },
+        "b2_label": {
+            "p1": "v_p1_lib2[b2_label]",
+            "p2": "v_p2_lib2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test09/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,16 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib1[b1_label]"
+        },
+        "b2_label": {
+            "p2": "v_p2_lib1[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test09/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,32 @@
+{
+    "custom_targets": {
+        "base": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0"
+        },
+        "b1": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b1_label"]
+        },
+        "b2": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b2_label"]
+        },
+        "both": {
+            "inherits": ["b1", "b2"]
+        }
+    },
+    "config": {
+        "app1": "v_app1",
+        "app2": "v_app2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "app1": "v_app1[b1_label]",
+            "app_wrong": "v_dummy"
+        },
+        "b2_label": {
+            "app2": "v_app2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test09/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,34 @@
+# This build on top of test6 by adding an invalid override in mbed_app_override.json for b1_label.
+# This will prevent the configuration for working for b1 and both, but it should still
+# work for base and b2.
+
+expected_results = {
+   "base": {
+        "desc": "override values based on labels with libs (no labels)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2",
+        "lib2.p2": "v_p2_lib2"
+    },
+    "b1": {
+        "desc": "override values based on labels with libs - invalid override (first label)",
+        "exception_msg": "Attempt to override undefined parameter 'app.app_wrong' in 'application[b1_label]"
+    },
+    "b2": {
+        "desc": "override values based on labels with libs (second label)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2[b2_label]",
+        "lib2.p2": "v_p2_lib2[b2_label]"
+    },
+    "both": {
+        "desc": "override values based on labels with libs - invalid override (both labels)",
+        "exception_msg": "Attempt to override undefined parameter 'app.app_wrong' in 'application[b1_label]"
+    },
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test10/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,17 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib2[b1_label]",
+            "p2": "v_p2_lib2[b1_label]"
+        },
+        "b2_label": {
+            "p1": "v_p1_lib2[b2_label]",
+            "p2": "v_p2_lib2[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test10/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,16 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    },
+    "target_overrides": {
+        "b1_label": {
+            "p1": "v_p1_lib1[b1_label]"
+        },
+        "b2_label": {
+            "p2": "v_p2_lib1[b2_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test10/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,58 @@
+{
+    "custom_targets": {
+        "base": {
+            "inherits": ["Target"],
+            "core": "Cortex-M0",
+            "config": {
+                "par1": "v_par1_base",
+                "par2": "v_par2_base",
+                "par3": "v_par3_base"
+            }
+        },
+        "b1": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b1_label"],
+            "overrides": {
+                "par1": "v_par1_b1"
+            }
+        },
+        "b2": {
+            "inherits": ["base"],
+            "extra_labels_add": ["b2_label"],
+            "overrides": {
+                "par2": "v_par2_b2"
+            }
+        },
+        "both": {
+            "inherits": ["b1", "b2"],
+            "config": {
+                "par4": "v_par4_both"
+            },
+            "overrides": {
+                "par3": "v_par3_both"
+            }
+        }
+    },
+    "config": {
+        "app1": "v_app1",
+        "app2": "v_app2"
+    },
+    "target_overrides": {
+        "*": {
+            "lib1.p3": "v_p3_lib1_app",
+            "lib1.p1": "v_p1_lib1_app",
+            "lib2.p1": "v_p1_lib2_app",
+            "target.par1": "v_par1_target_app"
+        },
+        "b1_label": {
+            "app.app1": "v_app1[b1_label_label]"
+        },
+        "b2_label": {
+            "app2": "v_app2[b2_label]"
+        },
+        "both": {
+            "target.par4": "v_par4_app[both_label]",
+            "lib2.p1": "v_p1_lib2_app[both_label]"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test10/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,57 @@
+# This builds on top of test8 by adding target-conditional overrides in mbed_app_config.json.
+
+expected_results = {
+   "base": {
+        "desc": "override values based on labels with libs, target params and target overrides (no labels)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_base",
+        "target.par3": "v_par3_base"
+    },
+    "b1": {
+        "desc": "override values based on labels with libs, target params and target overrides (first label)",
+        "app.app1": "v_app1[b1_label_label]",
+        "app.app2": "v_app2",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b1_label]",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_base",
+        "target.par3": "v_par3_base"
+    },
+    "b2": {
+        "desc": "override values based on labels with libs, target params and target overrides (second label)",
+        "app.app1": "v_app1",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2[b2_label]",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_b2",
+        "target.par3": "v_par3_base"
+    },
+    "both": {
+        "desc": "override values based on labels with libs, target params and target overrides (both labels)",
+        "app.app1": "v_app1[b1_label_label]",
+        "app.app2": "v_app2[b2_label]",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1[b2_label]",
+        "lib1.p3": "v_p3_lib1_app",
+        "lib2.p1": "v_p1_lib2_app[both_label]",
+        "lib2.p2": "v_p2_lib2[b2_label]",
+        "target.par1": "v_par1_target_app",
+        "target.par2": "v_par2_b2",
+        "target.par3": "v_par3_both",
+        "target.par4": "v_par4_app[both_label]"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test11/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,7 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test11/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,14 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    },
+    "target_overrides": {
+        "K64F": {
+            "p1": "v_p1_lib1[b1_label]",
+            "lib2.p1": "dummy"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test11/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,9 @@
+# Two libraries (lib1 and lib2) define their own configuration parameters
+# lib1 tries to override a configuration parameter in lib2, which raises an error
+
+expected_results = {
+   "K64F": {
+        "desc": "lib1 trying to override a config parameter in lib2",
+        "exception_msg": "Invalid prefix 'lib2' for parameter name 'lib2.p1' in 'library:lib1[K64F]'"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test12/lib1/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,7 @@
+{
+    "name": "lib2",
+    "config": {
+        "p1": "v_p1_lib2",
+        "p2": "v_p2_lib2"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test12/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+{
+    "name": "lib1",
+    "config": {
+        "p1": "v_p1_lib1",
+        "p2": "v_p2_lib1",
+        "p3": "v_p3_lib1"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test12/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+{
+    "target_overrides": {
+        "K64F": {
+            "lib1.p1": "v_p1_lib1_app",
+            "lib2.p1": "v_p1_lib2_app"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test12/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,14 @@
+# Two libraries (lib1 and lib2) define their own configuration parameters
+# The application config doesn't have any parameters itself, it just overrides the parameter
+# named p1 from both lib1 and lib2.
+
+expected_results = {
+   "K64F": {
+        "desc": "app without its own parameters overrides parameters in other libs",
+        "lib1.p1": "v_p1_lib1_app",
+        "lib1.p2": "v_p2_lib1",
+        "lib1.p3": "v_p3_lib1",
+        "lib2.p1": "v_p1_lib2_app",
+        "lib2.p2": "v_p2_lib2"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test13/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,3 @@
+{
+    "name": "lib1"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test13/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,3 @@
+{
+    "name": "lib1"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test13/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+# Create two libraries named "lib1", which must raise an error
+
+expected_results = {
+    "K64F": {
+        "desc": "attempt to configure two libraries named 'lib1'",
+        "exception_msg": "Library name 'lib1' is not unique"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test14/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,3 @@
+{
+    "unknown_key": "dummy_value"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test14/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+# Put an invalid key in the application configuration
+
+expected_results = {
+    "K64F": {
+        "desc": "invalid key in mbed_app_config.json",
+        "exception_msg": "Unknown key(s)"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test15/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib1",
+    "unknown_key": "dummy_value"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test15/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+# Put an invalid key in the library configuration
+
+expected_results = {
+    "K64F": {
+        "desc": "invalid key in mbed_lib_config.json",
+        "exception_msg": "Unknown key(s)"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test16/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib1",
+    "macros": ["LIB1_1=1", "LIB1_2"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test16/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib2",
+    "macros": ["LIB2_1=5", "LIB1_2"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test16/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,3 @@
+{
+    "macros": ["APP1=10", "APP2", "LIB2_1=5"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test16/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,12 @@
+# Macro test: defined macros in the top level app and 2 libs, check if they
+# are reported properly.
+# The app defines one macro with value the same as lib2, while lib2 defined
+# the same macro without value as lib1. Since the definitions are comptabile,
+# no error should be raised
+
+expected_results = {
+    "K64F": {
+        "desc": "test macro definitions",
+        "expected_macros": ["APP1=10", "APP2", "LIB1_1=1","LIB1_2", "LIB2_1=5"]
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test17/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib1",
+    "macros": ["LIB1_1=1", "LIB1_2"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test17/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib2",
+    "macros": ["LIB2_1=5", "LIB1_2"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test17/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,3 @@
+{
+    "macros": ["APP1=10", "APP2", "LIB2_1=10"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test17/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,9 @@
+# Build on top of test16
+# Adds an invalid macro redefinition in the app
+
+expected_results = {
+    "K64F": {
+        "desc": "test invalid macro re-definition in the app",
+        "exception_msg": "Macro 'LIB2_1' defined in both 'library:lib2' and 'application' with incompatible values"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test18/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib1",
+    "macros": ["LIB1_1=1", "LIB1_2"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test18/lib2/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "name": "lib2",
+    "macros": ["LIB2_1=5", "LIB1_2=3"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test18/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,3 @@
+{
+    "macros": ["APP1=10", "APP2", "LIB2_1=5"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test18/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+# Like test17, but this time the invalid re-definition is in lib2, not in the app
+
+expected_results = {
+    "K64F": {
+        "desc": "test invalid macro re-definition in a library",
+        "exception_msg": "defined in both"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test19/mbed_app.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,4 @@
+{
+    "macros": [],
+    "invalid_key": "invalid_value"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test19/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+# Test that invalid keys in application configuration are not allowed
+
+expected_results = {
+    "K64F": {
+        "desc": "test invalid key in application config",
+        "exception_msg": "Unknown key(s) 'invalid_key'"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test20/lib1/mbed_lib.json	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,5 @@
+{
+    "name": "lib1",
+    "macros": [],
+    "invalid_key": "invalid_value"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/config_test/test20/test_data.py	Tue Jun 14 11:07:30 2016 +0100
@@ -0,0 +1,8 @@
+# Like test19, but this time check invalid key in a library configuration
+
+expected_results = {
+    "K64F": {
+        "desc": "test invalid key in lib config",
+        "exception_msg": "Unknown key(s) 'invalid_key'"
+    }
+}
--- a/toolchains/__init__.py	Tue Jun 07 11:35:02 2016 +0100
+++ b/toolchains/__init__.py	Tue Jun 14 11:07:30 2016 +0100
@@ -247,7 +247,7 @@
                 self.PROFILE = TOOLCHAIN_PROFILES[self.name].get(profile)
                 self.info("Using toolchain %s profile %s" % (self.name, profile))
 
-        if 'UVISOR_PRESENT=1' in self.macros:
+        if 'UVISOR' in self.target.features and 'UVISOR_SUPPORTED' in self.target.extra_labels:
             self.target.core = re.sub(r"F$", '', self.target.core)
 
     def get_output(self):
@@ -258,7 +258,10 @@
         """
         msg = None
 
-        if event['type'] in ['info', 'debug']:
+        if not self.VERBOSE and event['type'] == 'tool_error':
+            msg = event['message']
+        
+        elif event['type'] in ['info', 'debug']:
             msg = event['message']
 
         elif event['type'] == 'cc':
@@ -314,6 +317,7 @@
             # Target and Toolchain symbols
             labels = self.get_labels()
             self.symbols = ["TARGET_%s" % t for t in labels['TARGET']]
+            self.symbols.extend(["FEATURE_%s" % t for t in labels['FEATURE']])
             self.symbols.extend(["TOOLCHAIN_%s" % t for t in labels['TOOLCHAIN']])
 
             # Config support
@@ -332,10 +336,9 @@
             # Add target's symbols
             self.symbols += self.target.macros
             # Add target's hardware
-            try :
-                self.symbols += ["DEVICE_" + feature + "=1" for feature in self.target.features]
-            except AttributeError :
-                pass
+            self.symbols += ["DEVICE_" + data + "=1" for data in self.target.device_has]
+            # Add target's features
+            self.symbols += ["FEATURE_" + data + "=1" for data in self.target.features]
             # Add extra symbols passed via 'macros' parameter
             self.symbols += self.macros
 
@@ -355,6 +358,7 @@
             toolchain_labels.remove('mbedToolchain')
             self.labels = {
                 'TARGET': self.target.get_labels() + ["DEBUG" if "debug-info" in self.options else "RELEASE"],
+                'FEATURE': self.target.features,
                 'TOOLCHAIN': toolchain_labels
             }
         return self.labels
@@ -422,6 +426,7 @@
 
                 if ((d.startswith('.') or d in self.legacy_ignore_dirs) or
                     (d.startswith('TARGET_') and d[7:] not in labels['TARGET']) or
+                    (d.startswith('FEATURE_') and d[8:] not in labels['FEATURE']) or
                     (d.startswith('TOOLCHAIN_') and d[10:] not in labels['TOOLCHAIN']) or
                     (d == 'TESTS')):
                     dirs.remove(d)
@@ -778,10 +783,6 @@
     def default_cmd(self, command):
         self.debug("Command: %s"% ' '.join(command))
         _stdout, _stderr, _rc = run_cmd(command)
-        # Print all warning / erros from stderr to console output
-        for error_line in _stderr.splitlines():
-            print error_line
-
         self.debug("Return: %s"% _rc)
 
         for output_line in _stdout.splitlines():
@@ -794,6 +795,7 @@
                 self.tool_error(line)
             raise ToolException(_stderr)
 
+
     ### NOTIFICATIONS ###
     def info(self, message):
         self.notify({'type': 'info', 'message': message})
@@ -829,30 +831,25 @@
     def mem_stats(self, map):
         # Creates parser object
         toolchain = self.__class__.__name__
-        t = MemmapParser()
+
+        # Create memap object
+        memap = MemapParser()
+
+        # Parse and decode a map file
+        if memap.parse(abspath(map), toolchain) is False:
+            self.info("Unknown toolchain for memory statistics %s" % toolchain)
+            return
 
-        try:
-            with open(map, 'rt') as f:
-                # Decode map file depending on the toolchain
-                if toolchain == "ARM_STD" or toolchain == "ARM_MICRO":
-                    t.search_objects(abspath(map), "ARM")
-                    t.parse_map_file_armcc(f)
-                elif toolchain == "GCC_ARM":
-                    t.parse_map_file_gcc(f)
-                elif toolchain == "IAR":
-                    self.info("[WARNING] IAR Compiler not fully supported (yet)")
-                    t.search_objects(abspath(map), toolchain)
-                    t.parse_map_file_iar(f)
-                else:
-                    self.info("Unknown toolchain for memory statistics %s" % toolchain)
-                    return
+        # Write output to stdout in text (pretty table) format
+        memap.generate_output('table')
 
-                t.generate_output(sys.stdout, False)
-                map_out = splitext(map)[0] + "_map.json"
-                with open(map_out, 'w') as fo:
-                    t.generate_output(fo, True)
-        except OSError:
-            return
+        # Write output to file in JSON format
+        map_out = splitext(map)[0] + "_map.json"
+        memap.generate_output('json', map_out)
+ 
+        # Write output to file in CSV format for the CI
+        map_csv = splitext(map)[0] + "_map.csv"
+        memap.generate_output('csv-ci', map_csv)
             
     
 from tools.settings import ARM_BIN