diff --git a/.gitignore b/.gitignore index e89472c..f4b10b5 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,6 @@ # default delivery dir DELIVERY/ + +# Directory hosting PSA autogenerated source files +PSA_AUTOGEN/ diff --git a/tools/build.py b/tools/build.py index 7fd477a..8846aaf 100644 --- a/tools/build.py +++ b/tools/build.py @@ -21,7 +21,7 @@ import sys from time import time -from os.path import join, abspath, dirname +from os.path import join, abspath, dirname, normpath # Be sure that the tools directory is in the search path @@ -44,7 +44,8 @@ from tools.utils import argparse_dir_not_parent from tools.utils import NoValidToolchainException from tools.utils import print_end_warnings -from tools.paths import is_relative_to_root +from tools.psa import generate_psa_sources, clean_psa_autogen +from tools.resources import OsAndSpeResourceFilter def main(): start = time() @@ -171,6 +172,9 @@ skipped = [] end_warnings = [] + if options.clean: + clean_psa_autogen() + for toolchain in toolchains: for target_name in targets: target = Target.get_target(target_name) @@ -192,10 +196,17 @@ notifier = TerminalNotifier(options.verbose, options.silent) profile = extract_profile(parser, options, internal_tc_name) - if target.is_PSA_secure_target and \ - not is_relative_to_root(options.source_dir): - options.source_dir = ROOT if options.source_dir: + if target.is_PSA_target: + generate_psa_sources( + source_dirs=options.source_dir, + ignore_paths=[options.build_dir] + ) + + resource_filter = None + if target.is_PSA_secure_target: + resource_filter = OsAndSpeResourceFilter() + lib_build_res = build_library( options.source_dir, options.build_dir, target, toolchain_name, jobs=options.jobs, @@ -205,7 +216,8 @@ name=options.artifact_name, build_profile=profile, ignore=options.ignore, - notify = notifier, + notify=notifier, + resource_filter=resource_filter ) else: lib_build_res = build_mbed_libs( diff --git a/tools/build_api.py b/tools/build_api.py index 125a920..2632b15 100755 --- a/tools/build_api.py +++ b/tools/build_api.py @@ -41,7 +41,7 @@ MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS, MBED_LIBRARIES_PLATFORM, MBED_LIBRARIES_HAL, BUILD_DIR) -from .resources import Resources, FileType, FileRef +from .resources import Resources, FileType, FileRef, PsaManifestResourceFilter from .notifier.mock import MockNotifier from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target from .libraries import Library @@ -511,7 +511,7 @@ report=None, properties=None, project_id=None, project_description=None, config=None, app_config=None, build_profile=None, stats_depth=None, - ignore=None, spe_build=False): + ignore=None, resource_filter=None): """ Build a project. A project may be a test or a user program. Positional arguments: @@ -539,6 +539,7 @@ build_profile - a dict of flags that will be passed to the compiler stats_depth - depth level for memap to display file/dirs ignore - list of paths to add to mbedignore + resource_filter - can be used for filtering out resources after scan """ # Convert src_path to a list if needed if not isinstance(src_paths, list): @@ -581,8 +582,8 @@ try: resources = Resources(notify).scan_with_toolchain( src_paths, toolchain, inc_dirs=inc_dirs) - if spe_build: - resources.filter_spe() + resources.filter(resource_filter) + # Change linker script if specified if linker_script is not None: resources.add_file_ref(FileType.LD_SCRIPT, linker_script, linker_script) @@ -664,7 +665,7 @@ archive=True, notify=None, macros=None, inc_dirs=None, jobs=1, report=None, properties=None, project_id=None, remove_config_header_file=False, app_config=None, - build_profile=None, ignore=None): + build_profile=None, ignore=None, resource_filter=None): """ Build a library Positional arguments: @@ -690,6 +691,7 @@ app_config - location of a chosen mbed_app.json file build_profile - a dict of flags that will be passed to the compiler ignore - list of paths to add to mbedignore + resource_filter - can be used for filtering out resources after scan """ # Convert src_path to a list if needed @@ -750,6 +752,8 @@ try: res = Resources(notify).scan_with_toolchain( src_paths, toolchain, dependencies_paths, inc_dirs=inc_dirs) + res.filter(resource_filter) + res.filter(PsaManifestResourceFilter()) # Copy headers, objects and static libraries - all files needed for # static lib diff --git a/tools/export/__init__.py b/tools/export/__init__.py index 48e02f4..963a05e 100644 --- a/tools/export/__init__.py +++ b/tools/export/__init__.py @@ -208,7 +208,7 @@ linker_script=None, notify=None, name=None, inc_dirs=None, jobs=1, config=None, macros=None, zip_proj=None, inc_repos=False, build_profile=None, app_config=None, - ignore=None): + ignore=None, resource_filter=None): """Generates a project file and creates a zip archive if specified Positional Arguments: @@ -230,6 +230,7 @@ zip_proj - string name of the zip archive you wish to creat (exclude arg if you do not wish to create an archive ignore - list of paths to add to mbedignore + resource_filter - can be used for filtering out resources after scan """ # Convert src_path to a list if needed @@ -279,6 +280,8 @@ if toolchain.config.name: name = toolchain.config.name + resources.filter(resource_filter) + files, exporter = generate_project_files( resources, export_path, target, name, toolchain, ide, zip_proj, macros=macros ) diff --git a/tools/make.py b/tools/make.py index 371e022..6fd8ee9 100644 --- a/tools/make.py +++ b/tools/make.py @@ -21,7 +21,7 @@ from __future__ import print_function from builtins import str import sys -from os.path import join, abspath, dirname +from os.path import join, abspath, dirname, normpath # Be sure that the tools directory is in the search path ROOT = abspath(join(dirname(__file__), "..")) @@ -34,7 +34,6 @@ from tools.paths import RPC_LIBRARY from tools.paths import USB_LIBRARIES from tools.paths import DSP_LIBRARIES -from tools.paths import is_relative_to_root from tools.tests import TESTS, Test, TEST_MAP from tools.tests import TEST_MBED_LIB from tools.tests import test_known, test_name_known @@ -56,7 +55,8 @@ from tools.utils import print_large_string from tools.settings import ROOT from tools.targets import Target - +from tools.psa import generate_psa_sources, clean_psa_autogen +from tools.resources import OsAndSpeResourceFilter def default_args_dict(options): return dict( @@ -74,7 +74,8 @@ error = False try: bin_file, update_file = build_project( - src_dir, build_dir, mcu, *args, **kwargs + src_dir, build_dir, mcu, + *args, **kwargs ) if update_file: print('Update Image: %s' % update_file) @@ -304,6 +305,10 @@ elif options.list_tests is True: print('\n'.join(map(str, sorted(TEST_MAP.values())))) else: + + if options.clean: + clean_psa_autogen() + # Target if options.mcu is None: args_error(parser, "argument -m/--mcu is required") @@ -315,9 +320,6 @@ toolchain = options.tool[0] target = Target.get_target(mcu) - if target.is_PSA_secure_target and \ - not is_relative_to_root(options.source_dir): - options.source_dir = ROOT if (options.program is None) and (not options.source_dir): args_error(parser, "one of -p, -n, or --source is required") @@ -337,6 +339,16 @@ args_error(parser, str(e)) if options.source_dir is not None: + if target.is_PSA_target: + generate_psa_sources( + source_dirs=options.source_dir, + ignore_paths=[options.build_dir] + ) + + resource_filter = None + if target.is_PSA_secure_target: + resource_filter = OsAndSpeResourceFilter() + wrapped_build_project( options.source_dir, options.build_dir, @@ -346,6 +358,7 @@ toolchain_name, notify=notify, build_profile=extract_profile(parser, options, internal_tc_name), + resource_filter=resource_filter, **default_args_dict(options) ) else: diff --git a/tools/paths.py b/tools/paths.py index d29eb15..0425b13 100644 --- a/tools/paths.py +++ b/tools/paths.py @@ -85,11 +85,3 @@ CPPUTEST_TESTRUNNER_INC = join(TEST_DIR, "utest", "testrunner") CPPUTEST_LIBRARY = join(BUILD_DIR, "cpputest") - - -def is_relative_to_root(dirs): - if not isinstance(dirs, list): - dirs = [dirs] - dirs = [realpath(d) for d in dirs] - out = commonprefix(dirs + [ROOT]) - return out == ROOT diff --git a/tools/project.py b/tools/project.py index c9f299e..1bf4769 100644 --- a/tools/project.py +++ b/tools/project.py @@ -40,7 +40,7 @@ ) from tools.tests import TESTS, TEST_MAP from tools.tests import test_known, test_name_known, Test -from tools.targets import TARGET_NAMES +from tools.targets import TARGET_NAMES, Target from tools.utils import ( argparse_filestring_type, argparse_profile_filestring_type, @@ -53,6 +53,8 @@ from tools.utils import NotSupportedException from tools.options import extract_profile, list_profiles, extract_mcus from tools.notifier.term import TerminalNotifier +from tools.psa import generate_psa_sources, clean_psa_autogen +from tools.resources import OsAndSpeResourceFilter """ The CLI entry point for exporting projects from the mbed tools to any of the supported IDEs or project structures. @@ -126,7 +128,7 @@ def export(target, ide, build=None, src=None, macros=None, project_id=None, zip_proj=False, build_profile=None, export_path=None, notify=None, - app_config=None, ignore=None): + app_config=None, ignore=None, resource_filter=None): """Do an export of a project. Positional arguments: @@ -141,6 +143,7 @@ clean - start from a clean state before exporting zip_proj - create a zip file or not ignore - list of paths to add to mbedignore + resource_filter - can be used for filtering out resources after scan Returns an object of type Exporter (tools/exports/exporters.py) """ @@ -168,7 +171,8 @@ build_profile=build_profile, notify=TerminalNotifier(), app_config=app_config, - ignore=ignore + ignore=ignore, + resource_filter=resource_filter ) def clean(source_dir): @@ -376,6 +380,7 @@ if options.clean: clean(options.source_dir) + clean_psa_autogen() ide = resolve_exporter_alias(options.ide) exporter, toolchain_name = get_exporter_toolchain(ide) @@ -385,6 +390,16 @@ args_error(parser, "%s not supported by %s" % (mcu, ide)) try: + target = Target.get_target(mcu) + if target.is_PSA_target: + generate_psa_sources(source_dirs=options.source_dir, + ignore_paths=[] + ) + + resource_filter = None + if target.is_PSA_secure_target: + resource_filter = OsAndSpeResourceFilter() + export( mcu, ide, @@ -396,12 +411,14 @@ build_profile=profile, app_config=options.app_config, export_path=options.build_dir, - ignore=options.ignore + ignore=options.ignore, + resource_filter=resource_filter ) except NotSupportedException as exc: print("[Not Supported] %s" % str(exc)) exit(1) exit(0) + if __name__ == "__main__": main() diff --git a/tools/resources/__init__.py b/tools/resources/__init__.py index 1ed7d7c..72b7037 100644 --- a/tools/resources/__init__.py +++ b/tools/resources/__init__.py @@ -41,6 +41,7 @@ from os.path import (join, splitext, dirname, relpath, basename, split, normpath, abspath, exists) +from tools.settings import ROOT from .ignore import MbedIgnoreSet, IGNORE_FILENAME # Support legacy build conventions: the original mbed build system did not have @@ -594,7 +595,45 @@ config.load_resources(self) return self - def filter_spe(self): - spe_filter = lambda x: 'COMPONENT_SPE' in x - for type in [FileType.ASM_SRC, FileType.C_SRC, FileType.CPP_SRC]: - self._file_refs[type] = set([f for f in self._file_refs[type] if spe_filter(f.name) or spe_filter(f.path)]) + def filter(self, res_filter): + if res_filter is None: + return + + for t in res_filter.file_types: + self._file_refs[t] = set(filter( + res_filter.predicate, self._file_refs[t])) + + +class ResourceFilter(object): + def __init__(self, file_types): + self.file_types = file_types + + def predicate(self, ref): + raise NotImplemented + + +class SpeOnlyResourceFilter(ResourceFilter): + def __init__(self): + ResourceFilter.__init__( + self, [FileType.ASM_SRC, FileType.C_SRC, FileType.CPP_SRC]) + + def predicate(self, ref): + return 'COMPONENT_SPE' in ref.name + + +class OsAndSpeResourceFilter(ResourceFilter): + def __init__(self): + ResourceFilter.__init__( + self, [FileType.ASM_SRC, FileType.C_SRC, FileType.CPP_SRC]) + + def predicate(self, ref): + return ROOT in abspath(ref.name) or 'COMPONENT_SPE' in ref.name + + +class PsaManifestResourceFilter(ResourceFilter): + def __init__(self): + ResourceFilter.__init__( + self, [FileType.JSON]) + + def predicate(self, ref): + return not ref.name.endswith('_psa.json') diff --git a/tools/targets/__init__.py b/tools/targets/__init__.py index 8df0fd5..251e31b 100644 --- a/tools/targets/__init__.py +++ b/tools/targets/__init__.py @@ -387,6 +387,10 @@ def is_PSA_non_secure_target(self): return 'NSPE_Target' in self.labels + @property + def is_PSA_target(self): + return self.is_PSA_secure_target or self.is_PSA_non_secure_target + def get_post_build_hook(self, toolchain_labels): """Initialize the post-build hooks for a toolchain. For now, this function only allows "post binary" hooks (hooks that are executed diff --git a/tools/test.py b/tools/test.py index 150b3b6..4efcd64 100644 --- a/tools/test.py +++ b/tools/test.py @@ -43,7 +43,8 @@ from tools.utils import print_end_warnings from tools.settings import ROOT from tools.targets import Target -from tools.paths import is_relative_to_root +from tools.psa import generate_psa_sources, clean_psa_autogen +from tools.resources import OsAndSpeResourceFilter, SpeOnlyResourceFilter def main(): error = False @@ -150,7 +151,6 @@ args_error(parser, "argument -m/--mcu is required") mcu = extract_mcus(parser, options)[0] target = Target.get_target(mcu) - mcu_secured = target.is_PSA_secure_target # Toolchain if options.tool is None: @@ -212,14 +212,15 @@ print_tests(tests, options.format) sys.exit(0) else: + + if options.clean: + clean_psa_autogen() + # Build all tests if not options.build_dir: args_error(parser, "argument --build is required") - if mcu_secured and not is_relative_to_root(options.source_dir): - base_source_paths = ROOT - else: - base_source_paths = options.source_dir + base_source_paths = options.source_dir # Default base source path is the current directory if not base_source_paths: @@ -231,6 +232,16 @@ library_build_success = False profile = extract_profile(parser, options, internal_tc_name) try: + resource_filter = None + if target.is_PSA_secure_target: + resource_filter = OsAndSpeResourceFilter() + + if target.is_PSA_target: + generate_psa_sources( + source_dirs=base_source_paths, + ignore_paths=[options.build_dir] + ) + # Build sources notify = TerminalNotifier(options.verbose) build_library(base_source_paths, options.build_dir, mcu, @@ -241,7 +252,9 @@ notify=notify, archive=False, app_config=config, build_profile=profile, - ignore=options.ignore) + ignore=options.ignore, + resource_filter=resource_filter + ) library_build_success = True except ToolException as e: @@ -260,6 +273,11 @@ if not library_build_success: print("Failed to build library") else: + if target.is_PSA_secure_target: + resource_filter = SpeOnlyResourceFilter() + else: + resource_filter = None + # Build all the tests notify = TerminalNotifier(options.verbose) test_build_success, test_build = build_tests( @@ -279,7 +297,7 @@ build_profile=profile, stats_depth=options.stats_depth, ignore=options.ignore, - spe_build=mcu_secured) + resource_filter=resource_filter) # If a path to a test spec is provided, write it to a file if options.test_spec: diff --git a/tools/test_api.py b/tools/test_api.py index 67ca652..3cad6f7 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -2120,7 +2120,8 @@ clean=False, notify=None, jobs=1, macros=None, silent=False, report=None, properties=None, continue_on_build_fail=False, app_config=None, - build_profile=None, stats_depth=None, ignore=None, spe_build=False): + build_profile=None, stats_depth=None, ignore=None, + resource_filter=None): """Given the data structure from 'find_tests' and the typical build parameters, build all the tests @@ -2179,7 +2180,7 @@ 'toolchain_paths': TOOLCHAIN_PATHS, 'stats_depth': stats_depth, 'notify': MockNotifier(), - 'spe_build': spe_build + 'resource_filter': resource_filter } results.append(p.apply_async(build_test_worker, args, kwargs))