Integrate with mbeb-cli build system

PSA code generation will be called automatically upon mbed invocation.
The autogenerated files will be created under <mbed-os-root>/PSA_AUTOGEN directory.
pull/10447/head
Alexander Zilberkant 2019-04-21 15:33:32 +03:00 committed by Alexander Zilberkant
parent 117e3e82b6
commit 91505184d3
11 changed files with 151 additions and 45 deletions

3
.gitignore vendored
View File

@ -97,3 +97,6 @@ test_suite.json
# default delivery dir # default delivery dir
DELIVERY/ DELIVERY/
# Directory hosting PSA autogenerated source files
PSA_AUTOGEN/

View File

@ -21,7 +21,7 @@ from __future__ import print_function, division, absolute_import
import sys import sys
from time import time 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 # Be sure that the tools directory is in the search path
@ -44,7 +44,8 @@ from tools.utils import argparse_filestring_type, args_error, argparse_many
from tools.utils import argparse_dir_not_parent from tools.utils import argparse_dir_not_parent
from tools.utils import NoValidToolchainException from tools.utils import NoValidToolchainException
from tools.utils import print_end_warnings 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(): def main():
start = time() start = time()
@ -171,6 +172,9 @@ def main():
skipped = [] skipped = []
end_warnings = [] end_warnings = []
if options.clean:
clean_psa_autogen()
for toolchain in toolchains: for toolchain in toolchains:
for target_name in targets: for target_name in targets:
target = Target.get_target(target_name) target = Target.get_target(target_name)
@ -192,10 +196,17 @@ def main():
notifier = TerminalNotifier(options.verbose, options.silent) notifier = TerminalNotifier(options.verbose, options.silent)
profile = extract_profile(parser, options, internal_tc_name) 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 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( lib_build_res = build_library(
options.source_dir, options.build_dir, target, toolchain_name, options.source_dir, options.build_dir, target, toolchain_name,
jobs=options.jobs, jobs=options.jobs,
@ -205,7 +216,8 @@ def main():
name=options.artifact_name, name=options.artifact_name,
build_profile=profile, build_profile=profile,
ignore=options.ignore, ignore=options.ignore,
notify = notifier, notify=notifier,
resource_filter=resource_filter
) )
else: else:
lib_build_res = build_mbed_libs( lib_build_res = build_mbed_libs(

View File

@ -41,7 +41,7 @@ from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS, MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
MBED_LIBRARIES_PLATFORM, MBED_LIBRARIES_HAL, MBED_LIBRARIES_PLATFORM, MBED_LIBRARIES_HAL,
BUILD_DIR) BUILD_DIR)
from .resources import Resources, FileType, FileRef from .resources import Resources, FileType, FileRef, PsaManifestResourceFilter
from .notifier.mock import MockNotifier from .notifier.mock import MockNotifier
from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target
from .libraries import Library from .libraries import Library
@ -511,7 +511,7 @@ def build_project(src_paths, build_path, target, toolchain_name,
report=None, properties=None, project_id=None, report=None, properties=None, project_id=None,
project_description=None, config=None, project_description=None, config=None,
app_config=None, build_profile=None, stats_depth=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. """ Build a project. A project may be a test or a user program.
Positional arguments: Positional arguments:
@ -539,6 +539,7 @@ def build_project(src_paths, build_path, target, toolchain_name,
build_profile - a dict of flags that will be passed to the compiler build_profile - a dict of flags that will be passed to the compiler
stats_depth - depth level for memap to display file/dirs stats_depth - depth level for memap to display file/dirs
ignore - list of paths to add to mbedignore 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 # Convert src_path to a list if needed
if not isinstance(src_paths, list): if not isinstance(src_paths, list):
@ -581,8 +582,8 @@ def build_project(src_paths, build_path, target, toolchain_name,
try: try:
resources = Resources(notify).scan_with_toolchain( resources = Resources(notify).scan_with_toolchain(
src_paths, toolchain, inc_dirs=inc_dirs) src_paths, toolchain, inc_dirs=inc_dirs)
if spe_build: resources.filter(resource_filter)
resources.filter_spe()
# Change linker script if specified # Change linker script if specified
if linker_script is not None: if linker_script is not None:
resources.add_file_ref(FileType.LD_SCRIPT, linker_script, linker_script) resources.add_file_ref(FileType.LD_SCRIPT, linker_script, linker_script)
@ -664,7 +665,7 @@ def build_library(src_paths, build_path, target, toolchain_name,
archive=True, notify=None, macros=None, inc_dirs=None, jobs=1, archive=True, notify=None, macros=None, inc_dirs=None, jobs=1,
report=None, properties=None, project_id=None, report=None, properties=None, project_id=None,
remove_config_header_file=False, app_config=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 """ Build a library
Positional arguments: Positional arguments:
@ -690,6 +691,7 @@ def build_library(src_paths, build_path, target, toolchain_name,
app_config - location of a chosen mbed_app.json file app_config - location of a chosen mbed_app.json file
build_profile - a dict of flags that will be passed to the compiler build_profile - a dict of flags that will be passed to the compiler
ignore - list of paths to add to mbedignore 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 # Convert src_path to a list if needed
@ -750,6 +752,8 @@ def build_library(src_paths, build_path, target, toolchain_name,
try: try:
res = Resources(notify).scan_with_toolchain( res = Resources(notify).scan_with_toolchain(
src_paths, toolchain, dependencies_paths, inc_dirs=inc_dirs) 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 # Copy headers, objects and static libraries - all files needed for
# static lib # static lib

View File

@ -208,7 +208,7 @@ def export_project(src_paths, export_path, target, ide, libraries_paths=None,
linker_script=None, notify=None, name=None, inc_dirs=None, linker_script=None, notify=None, name=None, inc_dirs=None,
jobs=1, config=None, macros=None, zip_proj=None, jobs=1, config=None, macros=None, zip_proj=None,
inc_repos=False, build_profile=None, app_config=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 """Generates a project file and creates a zip archive if specified
Positional Arguments: Positional Arguments:
@ -230,6 +230,7 @@ def export_project(src_paths, export_path, target, ide, libraries_paths=None,
zip_proj - string name of the zip archive you wish to creat (exclude arg zip_proj - string name of the zip archive you wish to creat (exclude arg
if you do not wish to create an archive if you do not wish to create an archive
ignore - list of paths to add to mbedignore 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 # Convert src_path to a list if needed
@ -279,6 +280,8 @@ def export_project(src_paths, export_path, target, ide, libraries_paths=None,
if toolchain.config.name: if toolchain.config.name:
name = toolchain.config.name name = toolchain.config.name
resources.filter(resource_filter)
files, exporter = generate_project_files( files, exporter = generate_project_files(
resources, export_path, target, name, toolchain, ide, zip_proj, macros=macros resources, export_path, target, name, toolchain, ide, zip_proj, macros=macros
) )

View File

@ -21,7 +21,7 @@ TEST BUILD & RUN
from __future__ import print_function from __future__ import print_function
from builtins import str from builtins import str
import sys 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 # Be sure that the tools directory is in the search path
ROOT = abspath(join(dirname(__file__), "..")) ROOT = abspath(join(dirname(__file__), ".."))
@ -34,7 +34,6 @@ from tools.paths import MBED_LIBRARIES
from tools.paths import RPC_LIBRARY from tools.paths import RPC_LIBRARY
from tools.paths import USB_LIBRARIES from tools.paths import USB_LIBRARIES
from tools.paths import DSP_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 TESTS, Test, TEST_MAP
from tools.tests import TEST_MBED_LIB from tools.tests import TEST_MBED_LIB
from tools.tests import test_known, test_name_known from tools.tests import test_known, test_name_known
@ -56,7 +55,8 @@ from tools.utils import print_end_warnings
from tools.utils import print_large_string from tools.utils import print_large_string
from tools.settings import ROOT from tools.settings import ROOT
from tools.targets import Target 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): def default_args_dict(options):
return dict( return dict(
@ -74,7 +74,8 @@ def wrapped_build_project(src_dir, build_dir, mcu, end_warnings, options, *args,
error = False error = False
try: try:
bin_file, update_file = build_project( bin_file, update_file = build_project(
src_dir, build_dir, mcu, *args, **kwargs src_dir, build_dir, mcu,
*args, **kwargs
) )
if update_file: if update_file:
print('Update Image: %s' % update_file) print('Update Image: %s' % update_file)
@ -304,6 +305,10 @@ def main():
elif options.list_tests is True: elif options.list_tests is True:
print('\n'.join(map(str, sorted(TEST_MAP.values())))) print('\n'.join(map(str, sorted(TEST_MAP.values()))))
else: else:
if options.clean:
clean_psa_autogen()
# Target # Target
if options.mcu is None: if options.mcu is None:
args_error(parser, "argument -m/--mcu is required") args_error(parser, "argument -m/--mcu is required")
@ -315,9 +320,6 @@ def main():
toolchain = options.tool[0] toolchain = options.tool[0]
target = Target.get_target(mcu) 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): if (options.program is None) and (not options.source_dir):
args_error(parser, "one of -p, -n, or --source is required") args_error(parser, "one of -p, -n, or --source is required")
@ -337,6 +339,16 @@ def main():
args_error(parser, str(e)) args_error(parser, str(e))
if options.source_dir is not None: 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( wrapped_build_project(
options.source_dir, options.source_dir,
options.build_dir, options.build_dir,
@ -346,6 +358,7 @@ def main():
toolchain_name, toolchain_name,
notify=notify, notify=notify,
build_profile=extract_profile(parser, options, internal_tc_name), build_profile=extract_profile(parser, options, internal_tc_name),
resource_filter=resource_filter,
**default_args_dict(options) **default_args_dict(options)
) )
else: else:

View File

@ -85,11 +85,3 @@ CPPUTEST_TESTRUNNER_SCR = join(TEST_DIR, "utest", "testrunner")
CPPUTEST_TESTRUNNER_INC = join(TEST_DIR, "utest", "testrunner") CPPUTEST_TESTRUNNER_INC = join(TEST_DIR, "utest", "testrunner")
CPPUTEST_LIBRARY = join(BUILD_DIR, "cpputest") 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

View File

@ -40,7 +40,7 @@ from tools.export import (
) )
from tools.tests import TESTS, TEST_MAP from tools.tests import TESTS, TEST_MAP
from tools.tests import test_known, test_name_known, Test 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 ( from tools.utils import (
argparse_filestring_type, argparse_filestring_type,
argparse_profile_filestring_type, argparse_profile_filestring_type,
@ -53,6 +53,8 @@ from tools.utils import print_large_string
from tools.utils import NotSupportedException from tools.utils import NotSupportedException
from tools.options import extract_profile, list_profiles, extract_mcus from tools.options import extract_profile, list_profiles, extract_mcus
from tools.notifier.term import TerminalNotifier 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 """ The CLI entry point for exporting projects from the mbed tools to any of the
supported IDEs or project structures. supported IDEs or project structures.
@ -126,7 +128,7 @@ def setup_project(
def export(target, ide, build=None, src=None, macros=None, project_id=None, def export(target, ide, build=None, src=None, macros=None, project_id=None,
zip_proj=False, build_profile=None, export_path=None, notify=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. """Do an export of a project.
Positional arguments: Positional arguments:
@ -141,6 +143,7 @@ def export(target, ide, build=None, src=None, macros=None, project_id=None,
clean - start from a clean state before exporting clean - start from a clean state before exporting
zip_proj - create a zip file or not zip_proj - create a zip file or not
ignore - list of paths to add to mbedignore 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) Returns an object of type Exporter (tools/exports/exporters.py)
""" """
@ -168,7 +171,8 @@ def export(target, ide, build=None, src=None, macros=None, project_id=None,
build_profile=build_profile, build_profile=build_profile,
notify=TerminalNotifier(), notify=TerminalNotifier(),
app_config=app_config, app_config=app_config,
ignore=ignore ignore=ignore,
resource_filter=resource_filter
) )
def clean(source_dir): def clean(source_dir):
@ -376,6 +380,7 @@ def main():
if options.clean: if options.clean:
clean(options.source_dir) clean(options.source_dir)
clean_psa_autogen()
ide = resolve_exporter_alias(options.ide) ide = resolve_exporter_alias(options.ide)
exporter, toolchain_name = get_exporter_toolchain(ide) exporter, toolchain_name = get_exporter_toolchain(ide)
@ -385,6 +390,16 @@ def main():
args_error(parser, "%s not supported by %s" % (mcu, ide)) args_error(parser, "%s not supported by %s" % (mcu, ide))
try: 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( export(
mcu, mcu,
ide, ide,
@ -396,12 +411,14 @@ def main():
build_profile=profile, build_profile=profile,
app_config=options.app_config, app_config=options.app_config,
export_path=options.build_dir, export_path=options.build_dir,
ignore=options.ignore ignore=options.ignore,
resource_filter=resource_filter
) )
except NotSupportedException as exc: except NotSupportedException as exc:
print("[Not Supported] %s" % str(exc)) print("[Not Supported] %s" % str(exc))
exit(1) exit(1)
exit(0) exit(0)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -41,6 +41,7 @@ from os import walk, sep
from os.path import (join, splitext, dirname, relpath, basename, split, normpath, from os.path import (join, splitext, dirname, relpath, basename, split, normpath,
abspath, exists) abspath, exists)
from tools.settings import ROOT
from .ignore import MbedIgnoreSet, IGNORE_FILENAME from .ignore import MbedIgnoreSet, IGNORE_FILENAME
# Support legacy build conventions: the original mbed build system did not have # Support legacy build conventions: the original mbed build system did not have
@ -594,7 +595,45 @@ class Resources(object):
config.load_resources(self) config.load_resources(self)
return self return self
def filter_spe(self): def filter(self, res_filter):
spe_filter = lambda x: 'COMPONENT_SPE' in x if res_filter is None:
for type in [FileType.ASM_SRC, FileType.C_SRC, FileType.CPP_SRC]: return
self._file_refs[type] = set([f for f in self._file_refs[type] if spe_filter(f.name) or spe_filter(f.path)])
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')

View File

@ -387,6 +387,10 @@ class Target(namedtuple(
def is_PSA_non_secure_target(self): def is_PSA_non_secure_target(self):
return 'NSPE_Target' in self.labels 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): def get_post_build_hook(self, toolchain_labels):
"""Initialize the post-build hooks for a toolchain. For now, this """Initialize the post-build hooks for a toolchain. For now, this
function only allows "post binary" hooks (hooks that are executed function only allows "post binary" hooks (hooks that are executed

View File

@ -43,7 +43,8 @@ from tools.utils import argparse_dir_not_parent
from tools.utils import print_end_warnings from tools.utils import print_end_warnings
from tools.settings import ROOT from tools.settings import ROOT
from tools.targets import Target 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(): def main():
error = False error = False
@ -150,7 +151,6 @@ def main():
args_error(parser, "argument -m/--mcu is required") args_error(parser, "argument -m/--mcu is required")
mcu = extract_mcus(parser, options)[0] mcu = extract_mcus(parser, options)[0]
target = Target.get_target(mcu) target = Target.get_target(mcu)
mcu_secured = target.is_PSA_secure_target
# Toolchain # Toolchain
if options.tool is None: if options.tool is None:
@ -212,13 +212,14 @@ def main():
print_tests(tests, options.format) print_tests(tests, options.format)
sys.exit(0) sys.exit(0)
else: else:
if options.clean:
clean_psa_autogen()
# Build all tests # Build all tests
if not options.build_dir: if not options.build_dir:
args_error(parser, "argument --build is required") 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 # Default base source path is the current directory
@ -231,6 +232,16 @@ def main():
library_build_success = False library_build_success = False
profile = extract_profile(parser, options, internal_tc_name) profile = extract_profile(parser, options, internal_tc_name)
try: 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 # Build sources
notify = TerminalNotifier(options.verbose) notify = TerminalNotifier(options.verbose)
build_library(base_source_paths, options.build_dir, mcu, build_library(base_source_paths, options.build_dir, mcu,
@ -241,7 +252,9 @@ def main():
notify=notify, archive=False, notify=notify, archive=False,
app_config=config, app_config=config,
build_profile=profile, build_profile=profile,
ignore=options.ignore) ignore=options.ignore,
resource_filter=resource_filter
)
library_build_success = True library_build_success = True
except ToolException as e: except ToolException as e:
@ -260,6 +273,11 @@ def main():
if not library_build_success: if not library_build_success:
print("Failed to build library") print("Failed to build library")
else: else:
if target.is_PSA_secure_target:
resource_filter = SpeOnlyResourceFilter()
else:
resource_filter = None
# Build all the tests # Build all the tests
notify = TerminalNotifier(options.verbose) notify = TerminalNotifier(options.verbose)
test_build_success, test_build = build_tests( test_build_success, test_build = build_tests(
@ -279,7 +297,7 @@ def main():
build_profile=profile, build_profile=profile,
stats_depth=options.stats_depth, stats_depth=options.stats_depth,
ignore=options.ignore, 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 a path to a test spec is provided, write it to a file
if options.test_spec: if options.test_spec:

View File

@ -2120,7 +2120,8 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
clean=False, notify=None, jobs=1, macros=None, clean=False, notify=None, jobs=1, macros=None,
silent=False, report=None, properties=None, silent=False, report=None, properties=None,
continue_on_build_fail=False, app_config=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, """Given the data structure from 'find_tests' and the typical build parameters,
build all the tests build all the tests
@ -2179,7 +2180,7 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
'toolchain_paths': TOOLCHAIN_PATHS, 'toolchain_paths': TOOLCHAIN_PATHS,
'stats_depth': stats_depth, 'stats_depth': stats_depth,
'notify': MockNotifier(), 'notify': MockNotifier(),
'spe_build': spe_build 'resource_filter': resource_filter
} }
results.append(p.apply_async(build_test_worker, args, kwargs)) results.append(p.apply_async(build_test_worker, args, kwargs))