Merge pull request #2802 from theotherjimmy/toolchain-profiles

[Tools] Add simple build profiles to toolchains
pull/2859/head
Sam Grove 2016-09-30 14:57:12 -05:00 committed by GitHub
commit ddc823a722
20 changed files with 457 additions and 231 deletions

View File

@ -19,3 +19,4 @@ install:
- sudo pip install jinja2 - sudo pip install jinja2
- sudo pip install pytest - sudo pip install pytest
- sudo pip install pylint - sudo pip install pylint
- sudo pip install hypothesis

View File

@ -0,0 +1,72 @@
# Toolchain Profiles User Perspective
A Toolchain or build system Profile is a set of flags that is garenteed to be passed to the underlieing compiler suite.
These flags are stored in a JSON file that may be merged with other JSON files of the same structure.
## JSON Toolchain Profile Format
The JSON object that represents a Toolchain Profile is a dict mapping from Toolchains, like `GCC_ARM`, to their flags, like `-O3`.
The structure is as follows: Each toolchain supported by a Toolchain Profile has an dict in the root dict.
This dict contains a mapping from a flag type to a list of flags that should be passed the corresponding part of the compiler suite.
The required flag types are:
| Key | Description |
|:---------|:--------------------------------------|
| `c` | Flags for the C Compiler |
| `cxx` | Flags for the C++ Compiler |
| `common` | Flags for both the C and C++ Compilers|
| `asm` | Flags for the Assembler |
## Example
An example of a Toolchain Profile is given below:
```json
{
"GCC_ARM": {
"common": ["-c", "-Wall", "-Wextra",
"-Wno-unused-parameter", "-Wno-missing-field-initializers",
"-fmessage-length=0", "-fno-exceptions", "-fno-builtin",
"-ffunction-sections", "-fdata-sections", "-funsigned-char",
"-MMD", "-fno-delete-null-pointer-checks",
"-fomit-frame-pointer", "-Os"],
"asm": ["-x", "assembler-with-cpp"],
"c": ["-std=gnu99"],
"cxx": ["-std=gnu++98", "-fno-rtti", "-Wvla"],
"ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r",
"-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit"]
},
"ARM": {
"common": ["-c", "--gnu", "-Otime", "--split_sections",
"--apcs=interwork", "--brief_diagnostics", "--restrict",
"--multibyte_chars", "-O3"],
"asm": [],
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
"ld": []
},
"IAR": {
"common": [
"--no_wrap_diagnostics", "non-native end of line sequence", "-e",
"--diag_suppress=Pa050,Pa084,Pa093,Pa082", "-Oh"],
"asm": [],
"c": ["--vla"],
"cxx": ["--guard_calls", "--no_static_destruction"],
"ld": ["--skip_dynamic_initialization", "--threaded_lib"]
}
}
```
From this Toolchain profile, we can tell that:
- `GCC_ARM`, `ARM`, and `IAR` compiler suites are supported.
- The `ARM` C and C++ Compilers will be using optimization level `-O3`
- The `IAR` linker will skip dynamic initialization
- etc.
# Toolchain Profile API Perspective
The Toolchains no longer take in an optional argument, `build_profile`, that will contain a map from flag types to lists of flags.
This looks exactly the same in python as it does in the JSON format above.
The meaning of the flags, and which ones are required is the same as the User Perspective
A developer using the API must parse the User provided files themselves and extract the appropriate sub-dict from the file afterwards.
A convienence function that does this for a developer is `tools.options.extract_profile` and will call args_error when a Toolchain Profile JSON file does not provide flags for the selected Toolchain.

View File

@ -31,6 +31,7 @@ from tools.toolchains import TOOLCHAINS, TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS
from tools.toolchains import mbedToolchain from tools.toolchains import mbedToolchain
from tools.targets import TARGET_NAMES, TARGET_MAP from tools.targets import TARGET_NAMES, TARGET_MAP
from tools.options import get_default_options_parser from tools.options import get_default_options_parser
from tools.options import extract_profile
from tools.build_api import build_library, build_mbed_libs, build_lib from tools.build_api import build_library, build_mbed_libs, build_lib
from tools.build_api import mcu_toolchain_matrix from tools.build_api import mcu_toolchain_matrix
from tools.build_api import static_analysis_scan, static_analysis_scan_lib, static_analysis_scan_library from tools.build_api import static_analysis_scan, static_analysis_scan_lib, static_analysis_scan_library
@ -222,13 +223,20 @@ if __name__ == '__main__':
try: try:
mcu = TARGET_MAP[target] mcu = TARGET_MAP[target]
# CMSIS and MBED libs analysis # CMSIS and MBED libs analysis
static_analysis_scan(mcu, toolchain, CPPCHECK_CMD, CPPCHECK_MSG_FORMAT, verbose=options.verbose, jobs=options.jobs) profile = extract_profile(parser, options, toolchain)
static_analysis_scan(
mcu, toolchain, CPPCHECK_CMD, CPPCHECK_MSG_FORMAT,
verbose=options.verbose, jobs=options.jobs,
build_profile=profile)
for lib_id in libraries: for lib_id in libraries:
# Static check for library # Static check for library
static_analysis_scan_lib(lib_id, mcu, toolchain, CPPCHECK_CMD, CPPCHECK_MSG_FORMAT, static_analysis_scan_lib(
options=options.options, lib_id, mcu, toolchain, CPPCHECK_CMD,
extra_verbose=options.extra_verbose_notify, verbose=options.verbose, jobs=options.jobs, clean=options.clean, CPPCHECK_MSG_FORMAT,
macros=options.macros) extra_verbose=options.extra_verbose_notify,
verbose=options.verbose, jobs=options.jobs,
clean=options.clean, macros=options.macros,
build_profile=profile)
pass pass
except Exception, e: except Exception, e:
if options.verbose: if options.verbose:
@ -248,9 +256,9 @@ if __name__ == '__main__':
else: else:
try: try:
mcu = TARGET_MAP[target] mcu = TARGET_MAP[target]
profile = extract_profile(parser, options, toolchain)
if options.source_dir: if options.source_dir:
lib_build_res = build_library(options.source_dir, options.build_dir, mcu, toolchain, lib_build_res = build_library(options.source_dir, options.build_dir, mcu, toolchain,
options=options.options,
extra_verbose=options.extra_verbose_notify, extra_verbose=options.extra_verbose_notify,
verbose=options.verbose, verbose=options.verbose,
silent=options.silent, silent=options.silent,
@ -258,26 +266,27 @@ if __name__ == '__main__':
clean=options.clean, clean=options.clean,
archive=(not options.no_archive), archive=(not options.no_archive),
macros=options.macros, macros=options.macros,
name=options.artifact_name) name=options.artifact_name,
build_profile=profile)
else: else:
lib_build_res = build_mbed_libs(mcu, toolchain, lib_build_res = build_mbed_libs(mcu, toolchain,
options=options.options,
extra_verbose=options.extra_verbose_notify, extra_verbose=options.extra_verbose_notify,
verbose=options.verbose, verbose=options.verbose,
silent=options.silent, silent=options.silent,
jobs=options.jobs, jobs=options.jobs,
clean=options.clean, clean=options.clean,
macros=options.macros) macros=options.macros,
build_profile=profile)
for lib_id in libraries: for lib_id in libraries:
build_lib(lib_id, mcu, toolchain, build_lib(lib_id, mcu, toolchain,
options=options.options,
extra_verbose=options.extra_verbose_notify, extra_verbose=options.extra_verbose_notify,
verbose=options.verbose, verbose=options.verbose,
silent=options.silent, silent=options.silent,
clean=options.clean, clean=options.clean,
macros=options.macros, macros=options.macros,
jobs=options.jobs) jobs=options.jobs,
build_profile=profile)
if lib_build_res: if lib_build_res:
successes.append(tt_id) successes.append(tt_id)
else: else:

View File

@ -274,10 +274,10 @@ def get_mbed_official_release(version):
def prepare_toolchain(src_paths, target, toolchain_name, def prepare_toolchain(src_paths, target, toolchain_name,
macros=None, options=None, clean=False, jobs=1, macros=None, clean=False, jobs=1,
notify=None, silent=False, verbose=False, notify=None, silent=False, verbose=False,
extra_verbose=False, config=None, extra_verbose=False, config=None,
app_config=None): app_config=None, build_profile=None):
""" Prepares resource related objects - toolchain, target, config """ Prepares resource related objects - toolchain, target, config
Positional arguments: Positional arguments:
@ -287,7 +287,6 @@ def prepare_toolchain(src_paths, target, toolchain_name,
Keyword arguments: Keyword arguments:
macros - additional macros macros - additional macros
options - general compiler options like debug-symbols or small-build
clean - Rebuild everything if True clean - Rebuild everything if True
jobs - how many compilers we can run at once jobs - how many compilers we can run at once
notify - Notify function for logs notify - Notify function for logs
@ -296,6 +295,7 @@ def prepare_toolchain(src_paths, target, toolchain_name,
extra_verbose - even more output! extra_verbose - even more output!
config - a Config object to use instead of creating one config - a Config object to use instead of creating one
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
""" """
# We need to remove all paths which are repeated to avoid # We need to remove all paths which are repeated to avoid
@ -309,8 +309,8 @@ def prepare_toolchain(src_paths, target, toolchain_name,
# Toolchain instance # Toolchain instance
try: try:
toolchain = TOOLCHAIN_CLASSES[toolchain_name]( toolchain = TOOLCHAIN_CLASSES[toolchain_name](
target, options, notify, macros, silent, target, notify, macros, silent,
extra_verbose=extra_verbose) extra_verbose=extra_verbose, build_profile=build_profile)
except KeyError: except KeyError:
raise KeyError("Toolchain %s not supported" % toolchain_name) raise KeyError("Toolchain %s not supported" % toolchain_name)
@ -361,12 +361,12 @@ def scan_resources(src_paths, toolchain, dependencies_paths=None,
return resources return resources
def build_project(src_paths, build_path, target, toolchain_name, def build_project(src_paths, build_path, target, toolchain_name,
libraries_paths=None, options=None, linker_script=None, libraries_paths=None, linker_script=None,
clean=False, notify=None, verbose=False, name=None, clean=False, notify=None, verbose=False, name=None,
macros=None, inc_dirs=None, jobs=1, silent=False, macros=None, inc_dirs=None, jobs=1, silent=False,
report=None, properties=None, project_id=None, report=None, properties=None, project_id=None,
project_description=None, extra_verbose=False, config=None, project_description=None, extra_verbose=False, config=None,
app_config=None): app_config=None, build_profile=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:
@ -378,7 +378,6 @@ def build_project(src_paths, build_path, target, toolchain_name,
Keyword arguments: Keyword arguments:
libraries_paths - The location of libraries to include when linking libraries_paths - The location of libraries to include when linking
options - general compiler options like debug-symbols or small-build
linker_script - the file that drives the linker to do it's job linker_script - the file that drives the linker to do it's job
clean - Rebuild everything if True clean - Rebuild everything if True
notify - Notify function for logs notify - Notify function for logs
@ -395,6 +394,7 @@ def build_project(src_paths, build_path, target, toolchain_name,
extra_verbose - even more output! extra_verbose - even more output!
config - a Config object to use instead of creating one config - a Config object to use instead of creating one
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
""" """
# Convert src_path to a list if needed # Convert src_path to a list if needed
@ -411,9 +411,10 @@ def build_project(src_paths, build_path, target, toolchain_name,
# Pass all params to the unified prepare_toolchain() # Pass all params to the unified prepare_toolchain()
toolchain = prepare_toolchain( toolchain = prepare_toolchain(
src_paths, target, toolchain_name, macros=macros, options=options, src_paths, target, toolchain_name, macros=macros, clean=clean,
clean=clean, jobs=jobs, notify=notify, silent=silent, verbose=verbose, jobs=jobs, notify=notify, silent=silent, verbose=verbose,
extra_verbose=extra_verbose, config=config, app_config=app_config) extra_verbose=extra_verbose, config=config, app_config=app_config,
build_profile=build_profile)
# The first path will give the name to the library # The first path will give the name to the library
if name is None: if name is None:
@ -483,11 +484,12 @@ def build_project(src_paths, build_path, target, toolchain_name,
raise raise
def build_library(src_paths, build_path, target, toolchain_name, def build_library(src_paths, build_path, target, toolchain_name,
dependencies_paths=None, options=None, name=None, clean=False, dependencies_paths=None, name=None, clean=False,
archive=True, notify=None, verbose=False, macros=None, archive=True, notify=None, verbose=False, macros=None,
inc_dirs=None, jobs=1, silent=False, report=None, inc_dirs=None, jobs=1, silent=False, report=None,
properties=None, extra_verbose=False, project_id=None, properties=None, extra_verbose=False, project_id=None,
remove_config_header_file=False, app_config=None): remove_config_header_file=False, app_config=None,
build_profile=None):
""" Build a library """ Build a library
Positional arguments: Positional arguments:
@ -499,7 +501,6 @@ def build_library(src_paths, build_path, target, toolchain_name,
Keyword arguments: Keyword arguments:
dependencies_paths - The location of libraries to include when linking dependencies_paths - The location of libraries to include when linking
options - general compiler options like debug-symbols or small-build
name - the name of the library name - the name of the library
clean - Rebuild everything if True clean - Rebuild everything if True
archive - whether the library will create an archive file archive - whether the library will create an archive file
@ -515,6 +516,7 @@ def build_library(src_paths, build_path, target, toolchain_name,
project_id - the name that goes in the report project_id - the name that goes in the report
remove_config_header_file - delete config header file when done building remove_config_header_file - delete config header file when done building
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
""" """
# Convert src_path to a list if needed # Convert src_path to a list if needed
@ -536,9 +538,10 @@ def build_library(src_paths, build_path, target, toolchain_name,
# Pass all params to the unified prepare_toolchain() # Pass all params to the unified prepare_toolchain()
toolchain = prepare_toolchain( toolchain = prepare_toolchain(
src_paths, target, toolchain_name, macros=macros, options=options, src_paths, target, toolchain_name, macros=macros, clean=clean,
clean=clean, jobs=jobs, notify=notify, silent=silent, verbose=verbose, jobs=jobs, notify=notify, silent=silent, verbose=verbose,
extra_verbose=extra_verbose, app_config=app_config) extra_verbose=extra_verbose, app_config=app_config,
build_profile=build_profile)
# The first path will give the name to the library # The first path will give the name to the library
if name is None: if name is None:
@ -639,9 +642,10 @@ def build_library(src_paths, build_path, target, toolchain_name,
### Legacy methods ### ### Legacy methods ###
###################### ######################
def build_lib(lib_id, target, toolchain_name, options=None, verbose=False, def build_lib(lib_id, target, toolchain_name, verbose=False,
clean=False, macros=None, notify=None, jobs=1, silent=False, clean=False, macros=None, notify=None, jobs=1, silent=False,
report=None, properties=None, extra_verbose=False): report=None, properties=None, extra_verbose=False,
build_profile=None):
""" Legacy method for building mbed libraries """ Legacy method for building mbed libraries
Positional arguments: Positional arguments:
@ -650,7 +654,6 @@ def build_lib(lib_id, target, toolchain_name, options=None, verbose=False,
toolchain_name - the name of the build tools toolchain_name - the name of the build tools
Keyword arguments: Keyword arguments:
options - general compiler options like debug-symbols or small-build
clean - Rebuild everything if True clean - Rebuild everything if True
verbose - Write the actual tools command lines used if True verbose - Write the actual tools command lines used if True
macros - additional macros macros - additional macros
@ -660,6 +663,7 @@ def build_lib(lib_id, target, toolchain_name, options=None, verbose=False,
report - a dict where a result may be appended report - a dict where a result may be appended
properties - UUUUHHHHH beats me properties - UUUUHHHHH beats me
extra_verbose - even more output! extra_verbose - even more output!
build_profile - a dict of flags that will be passed to the compiler
""" """
lib = Library(lib_id) lib = Library(lib_id)
if not lib.is_supported(target, toolchain_name): if not lib.is_supported(target, toolchain_name):
@ -715,8 +719,8 @@ def build_lib(lib_id, target, toolchain_name, options=None, verbose=False,
try: try:
# Toolchain instance # Toolchain instance
toolchain = TOOLCHAIN_CLASSES[toolchain_name]( toolchain = TOOLCHAIN_CLASSES[toolchain_name](
target, options, macros=macros, notify=notify, silent=silent, target, macros=macros, notify=notify, silent=silent,
extra_verbose=extra_verbose) extra_verbose=extra_verbose, build_profile=build_profile)
toolchain.VERBOSE = verbose toolchain.VERBOSE = verbose
toolchain.jobs = jobs toolchain.jobs = jobs
toolchain.build_all = clean toolchain.build_all = clean
@ -804,9 +808,10 @@ def build_lib(lib_id, target, toolchain_name, options=None, verbose=False,
# We do have unique legacy conventions about how we build and package the mbed # We do have unique legacy conventions about how we build and package the mbed
# library # library
def build_mbed_libs(target, toolchain_name, options=None, verbose=False, def build_mbed_libs(target, toolchain_name, verbose=False,
clean=False, macros=None, notify=None, jobs=1, silent=False, clean=False, macros=None, notify=None, jobs=1, silent=False,
report=None, properties=None, extra_verbose=False): report=None, properties=None, extra_verbose=False,
build_profile=None):
""" Function returns True is library was built and false if building was """ Function returns True is library was built and false if building was
skipped skipped
@ -815,7 +820,6 @@ def build_mbed_libs(target, toolchain_name, options=None, verbose=False,
toolchain_name - the name of the build tools toolchain_name - the name of the build tools
Keyword arguments: Keyword arguments:
options - general compiler options like debug-symbols or small-build
verbose - Write the actual tools command lines used if True verbose - Write the actual tools command lines used if True
clean - Rebuild everything if True clean - Rebuild everything if True
macros - additional macros macros - additional macros
@ -825,6 +829,7 @@ def build_mbed_libs(target, toolchain_name, options=None, verbose=False,
report - a dict where a result may be appended report - a dict where a result may be appended
properties - UUUUHHHHH beats me properties - UUUUHHHHH beats me
extra_verbose - even more output! extra_verbose - even more output!
build_profile - a dict of flags that will be passed to the compiler
""" """
if report != None: if report != None:
@ -859,8 +864,8 @@ def build_mbed_libs(target, toolchain_name, options=None, verbose=False,
try: try:
# Toolchain # Toolchain
toolchain = TOOLCHAIN_CLASSES[toolchain_name]( toolchain = TOOLCHAIN_CLASSES[toolchain_name](
target, options, macros=macros, notify=notify, silent=silent, target, macros=macros, notify=notify, silent=silent,
extra_verbose=extra_verbose) extra_verbose=extra_verbose, build_profile=build_profile)
toolchain.VERBOSE = verbose toolchain.VERBOSE = verbose
toolchain.jobs = jobs toolchain.jobs = jobs
toolchain.build_all = clean toolchain.build_all = clean
@ -1096,9 +1101,9 @@ def get_target_supported_toolchains(target):
def static_analysis_scan(target, toolchain_name, cppcheck_cmd, def static_analysis_scan(target, toolchain_name, cppcheck_cmd,
cppcheck_msg_format, options=None, verbose=False, cppcheck_msg_format, verbose=False,
clean=False, macros=None, notify=None, jobs=1, clean=False, macros=None, notify=None, jobs=1,
extra_verbose=False): extra_verbose=False, build_profile=None):
"""Perform static analysis on a target and toolchain combination """Perform static analysis on a target and toolchain combination
Positional arguments: Positional arguments:
@ -1108,18 +1113,19 @@ def static_analysis_scan(target, toolchain_name, cppcheck_cmd,
cppcheck_msg_format - the format of the check messages cppcheck_msg_format - the format of the check messages
Keyword arguments: Keyword arguments:
options - things like debug-symbols, or small-build, etc.
verbose - more printing! verbose - more printing!
clean - start from a clean slate clean - start from a clean slate
macros - extra macros to compile with macros - extra macros to compile with
notify - the notification event handling function notify - the notification event handling function
jobs - number of commands to run at once jobs - number of commands to run at once
extra_verbose - even moar printing extra_verbose - even moar printing
build_profile - a dict of flags that will be passed to the compiler
""" """
# Toolchain # Toolchain
toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, macros=macros,
macros=macros, notify=notify, notify=notify,
extra_verbose=extra_verbose) extra_verbose=extra_verbose,
build_profile=build_profile)
toolchain.VERBOSE = verbose toolchain.VERBOSE = verbose
toolchain.jobs = jobs toolchain.jobs = jobs
toolchain.build_all = clean toolchain.build_all = clean
@ -1241,9 +1247,9 @@ def static_analysis_scan(target, toolchain_name, cppcheck_cmd,
def static_analysis_scan_lib(lib_id, target, toolchain, cppcheck_cmd, def static_analysis_scan_lib(lib_id, target, toolchain, cppcheck_cmd,
cppcheck_msg_format, options=None, verbose=False, cppcheck_msg_format, verbose=False,
clean=False, macros=None, notify=None, jobs=1, clean=False, macros=None, notify=None, jobs=1,
extra_verbose=False): extra_verbose=False, build_profile=None):
"""Perform static analysis on a library as if it were to be compiled for a """Perform static analysis on a library as if it were to be compiled for a
particular target and toolchain combination particular target and toolchain combination
""" """
@ -1251,9 +1257,9 @@ def static_analysis_scan_lib(lib_id, target, toolchain, cppcheck_cmd,
if lib.is_supported(target, toolchain): if lib.is_supported(target, toolchain):
static_analysis_scan_library( static_analysis_scan_library(
lib.source_dir, lib.build_dir, target, toolchain, cppcheck_cmd, lib.source_dir, lib.build_dir, target, toolchain, cppcheck_cmd,
cppcheck_msg_format, lib.dependencies, options, verbose=verbose, cppcheck_msg_format, lib.dependencies, verbose=verbose,
clean=clean, macros=macros, notify=notify, jobs=jobs, clean=clean, macros=macros, notify=notify, jobs=jobs,
extra_verbose=extra_verbose) extra_verbose=extra_verbose, build_profile=build_profile)
else: else:
print('Library "%s" is not yet supported on target %s with toolchain %s' print('Library "%s" is not yet supported on target %s with toolchain %s'
% (lib_id, target.name, toolchain)) % (lib_id, target.name, toolchain))
@ -1261,10 +1267,10 @@ def static_analysis_scan_lib(lib_id, target, toolchain, cppcheck_cmd,
def static_analysis_scan_library(src_paths, build_path, target, toolchain_name, def static_analysis_scan_library(src_paths, build_path, target, toolchain_name,
cppcheck_cmd, cppcheck_msg_format, cppcheck_cmd, cppcheck_msg_format,
dependencies_paths=None, options=None, dependencies_paths=None,
name=None, clean=False, notify=None, name=None, clean=False, notify=None,
verbose=False, macros=None, jobs=1, verbose=False, macros=None, jobs=1,
extra_verbose=False): extra_verbose=False, build_profile=None):
""" Function scans library for statically detectable defects """ Function scans library for statically detectable defects
Positional arguments: Positional arguments:
@ -1277,7 +1283,6 @@ def static_analysis_scan_library(src_paths, build_path, target, toolchain_name,
Keyword arguments: Keyword arguments:
dependencies_paths - the paths to sources that this library depends on dependencies_paths - the paths to sources that this library depends on
options - things like debug-symbols, or small-build, etc.
name - the name of this library name - the name of this library
clean - start from a clean slate clean - start from a clean slate
notify - the notification event handling function notify - the notification event handling function
@ -1285,6 +1290,7 @@ def static_analysis_scan_library(src_paths, build_path, target, toolchain_name,
macros - extra macros to compile with macros - extra macros to compile with
jobs - number of commands to run at once jobs - number of commands to run at once
extra_verbose - even moar printing extra_verbose - even moar printing
build_profile - a dict of flags that will be passed to the compiler
""" """
if type(src_paths) != ListType: if type(src_paths) != ListType:
src_paths = [src_paths] src_paths = [src_paths]
@ -1295,9 +1301,10 @@ def static_analysis_scan_library(src_paths, build_path, target, toolchain_name,
src_path) src_path)
# Toolchain instance # Toolchain instance
toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, macros=macros,
macros=macros, notify=notify, notify=notify,
extra_verbose=extra_verbose) extra_verbose=extra_verbose,
build_profile=build_profile)
toolchain.VERBOSE = verbose toolchain.VERBOSE = verbose
toolchain.jobs = jobs toolchain.jobs = jobs

View File

@ -19,6 +19,7 @@ limitations under the License.
TEST BUILD & RUN TEST BUILD & RUN
""" """
import sys import sys
import json
from time import sleep from time import sleep
from shutil import copy from shutil import copy
from os.path import join, abspath, dirname from os.path import join, abspath, dirname
@ -41,6 +42,7 @@ 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
from tools.targets import TARGET_MAP from tools.targets import TARGET_MAP
from tools.options import get_default_options_parser from tools.options import get_default_options_parser
from tools.options import extract_profile
from tools.build_api import build_project from tools.build_api import build_project
from tools.build_api import mcu_toolchain_matrix from tools.build_api import mcu_toolchain_matrix
from utils import argparse_filestring_type from utils import argparse_filestring_type
@ -220,6 +222,7 @@ if __name__ == '__main__':
if options.source_dir and not options.build_dir: if options.source_dir and not options.build_dir:
args_error(parser, "argument --build is required when argument --source is provided") args_error(parser, "argument --build is required when argument --source is provided")
if options.color: if options.color:
# This import happens late to prevent initializing colorization when we don't need it # This import happens late to prevent initializing colorization when we don't need it
import colorize import colorize
@ -271,7 +274,8 @@ if __name__ == '__main__':
build_dir = options.build_dir build_dir = options.build_dir
try: try:
bin_file = build_project(test.source_dir, build_dir, mcu, toolchain, test.dependencies, options.options, bin_file = build_project(test.source_dir, build_dir, mcu, toolchain,
test.dependencies,
linker_script=options.linker_script, linker_script=options.linker_script,
clean=options.clean, clean=options.clean,
verbose=options.verbose, verbose=options.verbose,
@ -280,7 +284,10 @@ if __name__ == '__main__':
macros=options.macros, macros=options.macros,
jobs=options.jobs, jobs=options.jobs,
name=options.artifact_name, name=options.artifact_name,
app_config=options.app_config) app_config=options.app_config,
build_profile=extract_profile(parser,
options,
toolchain))
print 'Image: %s'% bin_file print 'Image: %s'% bin_file
if options.disk: if options.disk:

View File

@ -14,12 +14,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
""" """
from json import load
from os.path import join, dirname
from argparse import ArgumentParser from argparse import ArgumentParser
from tools.toolchains import TOOLCHAINS from tools.toolchains import TOOLCHAINS
from tools.targets import TARGET_NAMES from tools.targets import TARGET_NAMES
from tools.utils import argparse_force_uppercase_type, \ from tools.utils import argparse_force_uppercase_type, \
argparse_lowercase_hyphen_type, argparse_many, \ argparse_lowercase_hyphen_type, argparse_many, \
argparse_filestring_type argparse_filestring_type, args_error
def get_default_options_parser(add_clean=True, add_options=True, def get_default_options_parser(add_clean=True, add_options=True,
add_app_config=False): add_app_config=False):
@ -70,21 +72,35 @@ def get_default_options_parser(add_clean=True, add_options=True,
help="clean the build directory") help="clean the build directory")
if add_options: if add_options:
parser.add_argument("-o", "--options", action="append", parser.add_argument("--profile", dest="profile", action="append",
help=('Add a build argument ("save-asm": save the ' type=argparse_filestring_type,
'asm generated by the compiler, "debug-info":' default=[])
' generate debugging information, "analyze": '
'run Goanna static code analyzer")'),
type=argparse_lowercase_hyphen_type(['save-asm',
'debug-info',
'analyze',
'small-lib',
'std-lib'],
"build option"))
if add_app_config: if add_app_config:
parser.add_argument("--app-config", default=None, dest="app_config", parser.add_argument("--app-config", default=None, dest="app_config",
type=argparse_filestring_type, type=argparse_filestring_type,
help="Path of an app configuration file (Default is to look for 'mbed_app.json')") help="Path of an app configuration file (Default is to look for 'mbed_app.json')")
return parser return parser
def extract_profile(parser, options, toolchain):
"""Extract a Toolchain profile from parsed options
Positional arguments:
parser - parser used to parse the command line arguments
options - The parsed command line arguments
toolchain - the toolchain that the profile should be extracted for
"""
profile = {'c': [], 'cxx': [], 'ld': [], 'common': [], 'asm': []}
filenames = options.profile or [join(dirname(__file__), "profiles",
"default.json")]
for filename in filenames:
contents = load(open(filename))
try:
for key in profile.iterkeys():
profile[key] += contents[toolchain][key]
except KeyError:
args_error(parser, ("argument --profile: toolchain {} is not"
" supported by profile {}").format(toolchain,
filename))
return profile

View File

@ -0,0 +1,9 @@
{
"GCC_ARM": {
"common": ["-pedantic"],
"asm": [],
"c": [],
"cxx": [],
"ld": []
}
}

34
tools/profiles/debug.json Normal file
View File

@ -0,0 +1,34 @@
{
"GCC_ARM": {
"common": ["-c", "-Wall", "-Wextra",
"-Wno-unused-parameter", "-Wno-missing-field-initializers",
"-fmessage-length=0", "-fno-exceptions", "-fno-builtin",
"-ffunction-sections", "-fdata-sections", "-funsigned-char",
"-MMD", "-fno-delete-null-pointer-checks",
"-fomit-frame-pointer", "-O0", "-g"],
"asm": ["-x", "assembler-with-cpp"],
"c": ["-std=gnu99"],
"cxx": ["-std=gnu++98", "-fno-rtti", "-Wvla"],
"ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r",
"-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit"]
},
"ARM": {
"common": ["-c", "--gnu", "-Otime", "--split_sections",
"--apcs=interwork", "--brief_diagnostics", "--restrict",
"--multibyte_chars", "-O0", "-g"],
"asm": [],
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
"ld": []
},
"IAR": {
"common": [
"--no_wrap_diagnostics", "non-native end of line sequence", "-e",
"--diag_suppress=Pa050,Pa084,Pa093,Pa082", "-On", "-r"],
"asm": [],
"c": ["--vla"],
"cxx": ["--guard_calls", "--no_static_destruction"],
"ld": ["--skip_dynamic_initialization", "--threaded_lib"]
}
}

View File

@ -0,0 +1,34 @@
{
"GCC_ARM": {
"common": ["-c", "-Wall", "-Wextra",
"-Wno-unused-parameter", "-Wno-missing-field-initializers",
"-fmessage-length=0", "-fno-exceptions", "-fno-builtin",
"-ffunction-sections", "-fdata-sections", "-funsigned-char",
"-MMD", "-fno-delete-null-pointer-checks",
"-fomit-frame-pointer", "-Os"],
"asm": ["-x", "assembler-with-cpp"],
"c": ["-std=gnu99"],
"cxx": ["-std=gnu++98", "-fno-rtti", "-Wvla"],
"ld": ["-Wl,--gc-sections", "-Wl,--wrap,main", "-Wl,--wrap,_malloc_r",
"-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r",
"-Wl,--wrap,_calloc_r", "-Wl,--wrap,exit", "-Wl,--wrap,atexit"]
},
"ARM": {
"common": ["-c", "--gnu", "-Otime", "--split_sections",
"--apcs=interwork", "--brief_diagnostics", "--restrict",
"--multibyte_chars", "-O3"],
"asm": [],
"c": ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
"cxx": ["--cpp", "--no_rtti", "--no_vla"],
"ld": []
},
"IAR": {
"common": [
"--no_wrap_diagnostics", "-e",
"--diag_suppress=Pa050,Pa084,Pa093,Pa082", "-Oh"],
"asm": [],
"c": ["--vla"],
"cxx": ["--guard_calls", "--no_static_destruction"],
"ld": ["--skip_dynamic_initialization", "--threaded_lib"]
}
}

View File

@ -0,0 +1,9 @@
{
"GCC_ARM": {
"common": [ "-DMBED_RTOS_SINGLE_THREAD"],
"asm": [],
"c": [],
"cxx": [],
"ld": [ "--specs=nano.specs"]
}
}

View File

@ -0,0 +1,16 @@
{
"GCC_ARM": {
"common": ["-save-temps"],
"asm": [],
"c": [],
"cxx": [],
"ld": []
},
"ARM": {
"common": ["--asm", "--interleave"],
"asm": [],
"c": [],
"cxx": [],
"ld": []
}
}

View File

@ -19,6 +19,7 @@ from tools.utils import argparse_filestring_type, argparse_many, args_error
from tools.utils import argparse_force_lowercase_type from tools.utils import argparse_force_lowercase_type
from tools.utils import argparse_force_uppercase_type from tools.utils import argparse_force_uppercase_type
from tools.project_api import export_project from tools.project_api import export_project
from tools.options import extract_profile
def setup_project(ide, target, program=None, source_dir=None, build=None, export_path=None): def setup_project(ide, target, program=None, source_dir=None, build=None, export_path=None):
@ -63,7 +64,8 @@ def setup_project(ide, target, program=None, source_dir=None, build=None, export
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,
clean=False, zip_proj=False, options=None, export_path=None, silent=False): clean=False, zip_proj=False, build_profile=None, export_path=None,
silent=False):
"""Do an export of a project. """Do an export of a project.
Positional arguments: Positional arguments:
@ -87,7 +89,7 @@ def export(target, ide, build=None, src=None, macros=None, project_id=None,
return export_project(src, project_dir, target, ide, clean=clean, name=name, return export_project(src, project_dir, target, ide, clean=clean, name=name,
macros=macros, libraries_paths=lib, zip_proj=zip_name, macros=macros, libraries_paths=lib, zip_proj=zip_name,
options=options, silent=silent) build_profile=build_profile, silent=silent)
def main(): def main():
@ -167,11 +169,10 @@ def main():
dest="macros", dest="macros",
help="Add a macro definition") help="Add a macro definition")
parser.add_argument("-o", parser.add_argument("--profile",
type=argparse_many(str), type=argparse_filestring_type,
dest="opts", default=[],
default=["debug-info"], help="Toolchain profile")
help="Toolchain options")
options = parser.parse_args() options = parser.parse_args()
@ -220,10 +221,12 @@ def main():
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")
# Export to selected toolchain # Export to selected toolchain
_, toolchain_name = get_exporter_toolchain(options.ide)
profile = extract_profile(parser, options, toolchain_name)
export(options.mcu, options.ide, build=options.build, export(options.mcu, options.ide, build=options.build,
src=options.source_dir, macros=options.macros, src=options.source_dir, macros=options.macros,
project_id=options.program, clean=options.clean, project_id=options.program, clean=options.clean,
zip_proj=zip_proj, options=options.opts) zip_proj=zip_proj, build_profile=profile)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -135,10 +135,11 @@ def zip_export(file_name, prefix, resources, project_files, inc_repos):
def export_project(src_paths, export_path, target, ide, def export_project(src_paths, export_path, target, ide,
libraries_paths=None, options=None, linker_script=None, libraries_paths=None, linker_script=None, clean=False,
clean=False, notify=None, verbose=False, name=None, notify=None, verbose=False, name=None, inc_dirs=None,
inc_dirs=None, jobs=1, silent=False, extra_verbose=False, jobs=1, silent=False, extra_verbose=False, config=None,
config=None, macros=None, zip_proj=None, inc_repos=False): macros=None, zip_proj=None, inc_repos=False,
build_profile=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:
@ -149,7 +150,6 @@ def export_project(src_paths, export_path, target, ide,
Keyword Arguments: Keyword Arguments:
libraries_paths - paths to additional libraries libraries_paths - paths to additional libraries
options - build options passed by -o flag
linker_script - path to the linker script for the specified target linker_script - path to the linker script for the specified target
clean - removes the export_path if it exists clean - removes the export_path if it exists
notify - function is passed all events, and expected to handle notification notify - function is passed all events, and expected to handle notification
@ -192,10 +192,10 @@ def export_project(src_paths, export_path, target, ide,
# Pass all params to the unified prepare_resources() # Pass all params to the unified prepare_resources()
toolchain = prepare_toolchain(paths, target, toolchain_name, toolchain = prepare_toolchain(paths, target, toolchain_name,
macros=macros, options=options, clean=clean, macros=macros, clean=clean, jobs=jobs,
jobs=jobs, notify=notify, silent=silent, notify=notify, silent=silent, verbose=verbose,
verbose=verbose, extra_verbose=extra_verbose, extra_verbose=extra_verbose, config=config,
config=config) build_profile=build_profile)
# The first path will give the name to the library # The first path will give the name to the library
if name is None: if name is None:
name = basename(normpath(abspath(src_paths[0]))) name = basename(normpath(abspath(src_paths[0])))

View File

@ -27,7 +27,7 @@ ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, ROOT) sys.path.insert(0, ROOT)
from tools.test_api import test_path_to_name, find_tests, print_tests, build_tests, test_spec_from_test_builds from tools.test_api import test_path_to_name, find_tests, print_tests, build_tests, test_spec_from_test_builds
from tools.options import get_default_options_parser from tools.options import get_default_options_parser, extract_profile
from tools.build_api import build_project, build_library from tools.build_api import build_project, build_library
from tools.build_api import print_build_memory_usage from tools.build_api import print_build_memory_usage
from tools.targets import TARGET_MAP from tools.targets import TARGET_MAP
@ -132,7 +132,7 @@ if __name__ == '__main__':
# Find all tests in the relevant paths # Find all tests in the relevant paths
for path in all_paths: for path in all_paths:
all_tests.update(find_tests(path, mcu, toolchain, options.options, all_tests.update(find_tests(path, mcu, toolchain,
app_config=options.app_config)) app_config=options.app_config))
# Filter tests by name if specified # Filter tests by name if specified
@ -180,10 +180,10 @@ if __name__ == '__main__':
build_properties = {} build_properties = {}
library_build_success = False library_build_success = False
profile = extract_profile(parser, options, toolchain)
try: try:
# Build sources # Build sources
build_library(base_source_paths, options.build_dir, mcu, toolchain, build_library(base_source_paths, options.build_dir, mcu, toolchain,
options=options.options,
jobs=options.jobs, jobs=options.jobs,
clean=options.clean, clean=options.clean,
report=build_report, report=build_report,
@ -193,7 +193,8 @@ if __name__ == '__main__':
verbose=options.verbose, verbose=options.verbose,
notify=notify, notify=notify,
archive=False, archive=False,
app_config=options.app_config) app_config=options.app_config,
build_profile=profile)
library_build_success = True library_build_success = True
except ToolException, e: except ToolException, e:
@ -212,7 +213,6 @@ if __name__ == '__main__':
# Build all the tests # Build all the tests
test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, mcu, toolchain, test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, mcu, toolchain,
options=options.options,
clean=options.clean, clean=options.clean,
report=build_report, report=build_report,
properties=build_properties, properties=build_properties,
@ -221,7 +221,8 @@ if __name__ == '__main__':
notify=notify, notify=notify,
jobs=options.jobs, jobs=options.jobs,
continue_on_build_fail=options.continue_on_build_fail, continue_on_build_fail=options.continue_on_build_fail,
app_config=options.app_config) app_config=options.app_config,
build_profile=profile)
# 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

@ -1,13 +1,98 @@
"""Tests for the toolchain sub-system"""
import sys import sys
import os import os
from string import printable
from copy import deepcopy
from hypothesis import given
from hypothesis.strategies import text, lists, fixed_dictionaries
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..",
".."))
sys.path.insert(0, ROOT) sys.path.insert(0, ROOT)
from tools.toolchains import TOOLCHAIN_CLASSES, LEGACY_TOOLCHAIN_NAMES from tools.toolchains import TOOLCHAIN_CLASSES, LEGACY_TOOLCHAIN_NAMES
from tools.targets import TARGET_MAP from tools.targets import TARGET_MAP
def test_instantiation(): def test_instantiation():
for name, Class in TOOLCHAIN_CLASSES.items(): """Test that all exported toolchain may be instantiated"""
CLS = Class(TARGET_MAP["K64F"]) for name, tc_class in TOOLCHAIN_CLASSES.items():
assert name == CLS.name or name == LEGACY_TOOLCHAIN_NAMES[CLS.name] cls = tc_class(TARGET_MAP["K64F"])
assert name == cls.name or\
name == LEGACY_TOOLCHAIN_NAMES[cls.name]
ALPHABET = [char for char in printable if char not in [u'.', u'/']]
@given(fixed_dictionaries({
'common': lists(text()),
'c': lists(text()),
'cxx': lists(text()),
'asm': lists(text()),
'ld': lists(text())}),
lists(text(min_size=1, alphabet=ALPHABET), min_size=1))
def test_toolchain_profile_c(profile, source_file):
"""Test that the appropriate profile parameters are passed to the
C compiler"""
filename = deepcopy(source_file)
filename[-1] += ".c"
to_compile = os.path.join(*filename)
for _, tc_class in TOOLCHAIN_CLASSES.items():
toolchain = tc_class(TARGET_MAP["K64F"], build_profile=profile)
toolchain.inc_md5 = ""
toolchain.build_dir = ""
compile_command = toolchain.compile_command(to_compile,
to_compile + ".o", [])
for parameter in profile['c'] + profile['common']:
assert any(parameter in cmd for cmd in compile_command), \
"Toolchain %s did not propigate arg %s" % (toolchain.name,
parameter)
@given(fixed_dictionaries({
'common': lists(text()),
'c': lists(text()),
'cxx': lists(text()),
'asm': lists(text()),
'ld': lists(text())}),
lists(text(min_size=1, alphabet=ALPHABET), min_size=1))
def test_toolchain_profile_cpp(profile, source_file):
"""Test that the appropriate profile parameters are passed to the
C++ compiler"""
filename = deepcopy(source_file)
filename[-1] += ".cpp"
to_compile = os.path.join(*filename)
for _, tc_class in TOOLCHAIN_CLASSES.items():
toolchain = tc_class(TARGET_MAP["K64F"], build_profile=profile)
toolchain.inc_md5 = ""
toolchain.build_dir = ""
compile_command = toolchain.compile_command(to_compile,
to_compile + ".o", [])
for parameter in profile['cxx'] + profile['common']:
assert any(parameter in cmd for cmd in compile_command), \
"Toolchain %s did not propigate arg %s" % (toolchain.name,
parameter)
@given(fixed_dictionaries({
'common': lists(text()),
'c': lists(text()),
'cxx': lists(text()),
'asm': lists(text()),
'ld': lists(text())}),
lists(text(min_size=1, alphabet=ALPHABET), min_size=1))
def test_toolchain_profile_asm(profile, source_file):
"""Test that the appropriate profile parameters are passed to the
Assembler"""
filename = deepcopy(source_file)
filename[-1] += ".s"
to_compile = os.path.join(*filename)
for _, tc_class in TOOLCHAIN_CLASSES.items():
toolchain = tc_class(TARGET_MAP["K64F"], build_profile=profile)
toolchain.inc_md5 = ""
toolchain.build_dir = ""
compile_command = toolchain.compile_command(to_compile,
to_compile + ".o", [])
if not compile_command:
assert compile_command, to_compile
for parameter in profile['asm']:
assert any(parameter in cmd for cmd in compile_command), \
"Toolchain %s did not propigate arg %s" % (toolchain.name,
parameter)

View File

@ -355,14 +355,12 @@ class SingleTestRunner(object):
print self.logger.log_line(self.logger.LogType.NOTIF, 'Skipped tests for %s target. Target platform not found'% (target)) print self.logger.log_line(self.logger.LogType.NOTIF, 'Skipped tests for %s target. Target platform not found'% (target))
continue continue
build_mbed_libs_options = ["analyze"] if self.opts_goanna_for_mbed_sdk else None
clean_mbed_libs_options = True if self.opts_goanna_for_mbed_sdk or clean or self.opts_clean else None clean_mbed_libs_options = True if self.opts_goanna_for_mbed_sdk or clean or self.opts_clean else None
try: try:
build_mbed_libs_result = build_mbed_libs(T, build_mbed_libs_result = build_mbed_libs(T,
toolchain, toolchain,
options=build_mbed_libs_options,
clean=clean_mbed_libs_options, clean=clean_mbed_libs_options,
verbose=self.opts_verbose, verbose=self.opts_verbose,
jobs=self.opts_jobs, jobs=self.opts_jobs,
@ -423,7 +421,6 @@ class SingleTestRunner(object):
libraries.append(lib['id']) libraries.append(lib['id'])
build_project_options = ["analyze"] if self.opts_goanna_for_tests else None
clean_project_options = True if self.opts_goanna_for_tests or clean or self.opts_clean else None clean_project_options = True if self.opts_goanna_for_tests or clean or self.opts_clean else None
# Build all required libraries # Build all required libraries
@ -432,7 +429,6 @@ class SingleTestRunner(object):
build_lib(lib_id, build_lib(lib_id,
T, T,
toolchain, toolchain,
options=build_project_options,
verbose=self.opts_verbose, verbose=self.opts_verbose,
clean=clean_mbed_libs_options, clean=clean_mbed_libs_options,
jobs=self.opts_jobs, jobs=self.opts_jobs,
@ -479,7 +475,6 @@ class SingleTestRunner(object):
T, T,
toolchain, toolchain,
test.dependencies, test.dependencies,
options=build_project_options,
clean=clean_project_options, clean=clean_project_options,
verbose=self.opts_verbose, verbose=self.opts_verbose,
name=project_name, name=project_name,
@ -1990,7 +1985,7 @@ def test_path_to_name(path, base):
return "-".join(name_parts).lower() return "-".join(name_parts).lower()
def find_tests(base_dir, target_name, toolchain_name, options=None, app_config=None): def find_tests(base_dir, target_name, toolchain_name, app_config=None):
""" Finds all tests in a directory recursively """ Finds all tests in a directory recursively
base_dir: path to the directory to scan for tests (ex. 'path/to/project') base_dir: path to the directory to scan for tests (ex. 'path/to/project')
target_name: name of the target to use for scanning (ex. 'K64F') target_name: name of the target to use for scanning (ex. 'K64F')
@ -2002,7 +1997,7 @@ def find_tests(base_dir, target_name, toolchain_name, options=None, app_config=N
tests = {} tests = {}
# Prepare the toolchain # Prepare the toolchain
toolchain = prepare_toolchain([base_dir], target_name, toolchain_name, options=options, toolchain = prepare_toolchain([base_dir], target_name, toolchain_name,
silent=True, app_config=app_config) silent=True, app_config=app_config)
# Scan the directory for paths to probe for 'TESTS' folders # Scan the directory for paths to probe for 'TESTS' folders
@ -2060,9 +2055,10 @@ def norm_relative_path(path, start):
return path return path
def build_tests(tests, base_source_paths, build_path, target, toolchain_name, def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
options=None, clean=False, notify=None, verbose=False, jobs=1, clean=False, notify=None, verbose=False, jobs=1, macros=None,
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):
"""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
@ -2095,7 +2091,6 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
try: try:
bin_file = build_project(src_path, test_build_path, target, toolchain_name, bin_file = build_project(src_path, test_build_path, target, toolchain_name,
options=options,
jobs=jobs, jobs=jobs,
clean=clean, clean=clean,
macros=macros, macros=macros,
@ -2104,7 +2099,8 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
report=report, report=report,
properties=properties, properties=properties,
verbose=verbose, verbose=verbose,
app_config=app_config) app_config=app_config,
build_profile=build_profile)
except Exception, e: except Exception, e:
if not isinstance(e, NotSupportedException): if not isinstance(e, NotSupportedException):

View File

@ -31,7 +31,7 @@ from distutils.spawn import find_executable
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
from tools.utils import run_cmd, mkdir, rel_path, ToolException, NotSupportedException, split_path, compile_worker from tools.utils import run_cmd, mkdir, rel_path, ToolException, NotSupportedException, split_path, compile_worker
from tools.settings import BUILD_OPTIONS, MBED_ORG_USER from tools.settings import MBED_ORG_USER
import tools.hooks as hooks import tools.hooks as hooks
from tools.memap import MemapParser from tools.memap import MemapParser
from hashlib import md5 from hashlib import md5
@ -217,7 +217,9 @@ class mbedToolchain:
__metaclass__ = ABCMeta __metaclass__ = ABCMeta
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): profile_template = {'common':[], 'c':[], 'cxx':[], 'asm':[], 'ld':[]}
def __init__(self, target, notify=None, macros=None, silent=False, extra_verbose=False, build_profile=None):
self.target = target self.target = target
self.name = self.__class__.__name__ self.name = self.__class__.__name__
@ -225,7 +227,7 @@ class mbedToolchain:
self.hook = hooks.Hook(target, self) self.hook = hooks.Hook(target, self)
# Toolchain flags # Toolchain flags
self.flags = deepcopy(self.DEFAULT_FLAGS) self.flags = deepcopy(build_profile or self.profile_template)
# User-defined macros # User-defined macros
self.macros = macros or [] self.macros = macros or []
@ -291,15 +293,6 @@ class mbedToolchain:
self.output = str() self.output = str()
self.map_outputs = list() # Place to store memmap scan results in JSON like data structures self.map_outputs = list() # Place to store memmap scan results in JSON like data structures
# Build options passed by -o flag
self.options = options if options is not None else []
# Build options passed by settings.py or mbed_settings.py
self.options.extend(BUILD_OPTIONS)
if self.options:
self.info("Build Options: %s" % (', '.join(self.options)))
# uVisor spepcific rules # uVisor spepcific rules
if 'UVISOR' in self.target.features and 'UVISOR_SUPPORTED' in self.target.extra_labels: if 'UVISOR' in self.target.features and 'UVISOR_SUPPORTED' in self.target.extra_labels:
self.target.core = re.sub(r"F$", '', self.target.core) self.target.core = re.sub(r"F$", '', self.target.core)
@ -434,10 +427,20 @@ class mbedToolchain:
toolchain_labels = [c.__name__ for c in getmro(self.__class__)] toolchain_labels = [c.__name__ for c in getmro(self.__class__)]
toolchain_labels.remove('mbedToolchain') toolchain_labels.remove('mbedToolchain')
self.labels = { self.labels = {
'TARGET': self.target.labels + ["DEBUG" if "debug-info" in self.options else "RELEASE"], 'TARGET': self.target.labels,
'FEATURE': self.target.features, 'FEATURE': self.target.features,
'TOOLCHAIN': toolchain_labels 'TOOLCHAIN': toolchain_labels
} }
# This is a policy decision and it should /really/ be in the config system
# ATM it's here for backward compatibility
if (("-g" in self.flags['common'] and
"-O0") in self.flags['common'] or
("-r" in self.flags['common'] and
"-On" in self.flags['common'])):
self.labels['TARGET'].append("DEBUG")
else:
self.labels['TARGET'].append("RELEASE")
return self.labels return self.labels

View File

@ -30,20 +30,6 @@ class ARM(mbedToolchain):
INDEX_PATTERN = re.compile('(?P<col>\s*)\^') INDEX_PATTERN = re.compile('(?P<col>\s*)\^')
DEP_PATTERN = re.compile('\S+:\s(?P<file>.+)\n') DEP_PATTERN = re.compile('\S+:\s(?P<file>.+)\n')
# ANY changes to these default flags is backwards incompatible and require
# an update to the mbed-sdk-tools and website that introduces a profile
# for the previous version of these flags
DEFAULT_FLAGS = {
'common': ["-c", "--gnu",
"-Otime", "--split_sections", "--apcs=interwork",
"--brief_diagnostics", "--restrict", "--multibyte_chars"],
'asm': [],
'c': ["--md", "--no_depend_system_headers", "--c99", "-D__ASSERT_MSG"],
'cxx': ["--cpp", "--no_rtti", "--no_vla"],
'ld': [],
}
@staticmethod @staticmethod
def check_executable(): def check_executable():
"""Returns True if the executable (armcc) location specified by the """Returns True if the executable (armcc) location specified by the
@ -51,8 +37,11 @@ class ARM(mbedToolchain):
Returns False otherwise.""" Returns False otherwise."""
return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin') return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin')
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): def __init__(self, target, notify=None, macros=None,
mbedToolchain.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose) silent=False, extra_verbose=False, build_profile=None):
mbedToolchain.__init__(self, target, notify, macros, silent,
extra_verbose=extra_verbose,
build_profile=build_profile)
if target.core == "Cortex-M0+": if target.core == "Cortex-M0+":
cpu = "Cortex-M0" cpu = "Cortex-M0"
@ -71,14 +60,6 @@ class ARM(mbedToolchain):
main_cc = join(ARM_BIN, "armcc") main_cc = join(ARM_BIN, "armcc")
self.flags['common'] += ["--cpu=%s" % cpu] self.flags['common'] += ["--cpu=%s" % cpu]
if "save-asm" in self.options:
self.flags['common'].extend(["--asm", "--interleave"])
if "debug-info" in self.options:
self.flags['common'].append("-g")
self.flags['c'].append("-O0")
else:
self.flags['c'].append("-O3")
self.asm = [main_cc] + self.flags['common'] + self.flags['asm'] + ["-I \""+ARM_INC+"\""] self.asm = [main_cc] + self.flags['common'] + self.flags['asm'] + ["-I \""+ARM_INC+"\""]
self.cc = [main_cc] + self.flags['common'] + self.flags['c'] + ["-I \""+ARM_INC+"\""] self.cc = [main_cc] + self.flags['common'] + self.flags['c'] + ["-I \""+ARM_INC+"\""]
@ -241,8 +222,10 @@ class ARM(mbedToolchain):
class ARM_STD(ARM): class ARM_STD(ARM):
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): def __init__(self, target, notify=None, macros=None,
ARM.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose) silent=False, extra_verbose=False, build_profile=None):
ARM.__init__(self, target, notify, macros, silent,
extra_verbose=extra_verbose, build_profile=build_profile)
# Run-time values # Run-time values
self.ld.extend(["--libpath", join(TOOLCHAIN_PATHS['ARM'], "lib")]) self.ld.extend(["--libpath", join(TOOLCHAIN_PATHS['ARM'], "lib")])
@ -251,8 +234,10 @@ class ARM_STD(ARM):
class ARM_MICRO(ARM): class ARM_MICRO(ARM):
PATCHED_LIBRARY = False PATCHED_LIBRARY = False
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): def __init__(self, target, notify=None, macros=None,
ARM.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose) silent=False, extra_verbose=False, build_profile=None):
ARM.__init__(self, target, notify, macros, silent,
extra_verbose=extra_verbose, build_profile=build_profile)
# Extend flags # Extend flags
self.flags['common'].extend(["-D__MICROLIB"]) self.flags['common'].extend(["-D__MICROLIB"])

View File

@ -28,26 +28,12 @@ class GCC(mbedToolchain):
DIAGNOSTIC_PATTERN = re.compile('((?P<file>[^:]+):(?P<line>\d+):)(\d+:)? (?P<severity>warning|error): (?P<message>.+)') DIAGNOSTIC_PATTERN = re.compile('((?P<file>[^:]+):(?P<line>\d+):)(\d+:)? (?P<severity>warning|error): (?P<message>.+)')
INDEX_PATTERN = re.compile('(?P<col>\s*)\^') INDEX_PATTERN = re.compile('(?P<col>\s*)\^')
# ANY changes to these default flags is backwards incompatible and require def __init__(self, target, notify=None, macros=None,
# an update to the mbed-sdk-tools and website that introduces a profile silent=False, tool_path="", extra_verbose=False,
# for the previous version of these flags build_profile=None):
DEFAULT_FLAGS = { mbedToolchain.__init__(self, target, notify, macros, silent,
'common': ["-c", "-Wall", "-Wextra", extra_verbose=extra_verbose,
"-Wno-unused-parameter", "-Wno-missing-field-initializers", build_profile=build_profile)
"-fmessage-length=0", "-fno-exceptions", "-fno-builtin",
"-ffunction-sections", "-fdata-sections", "-funsigned-char",
"-MMD", "-fno-delete-null-pointer-checks", "-fomit-frame-pointer"
],
'asm': ["-x", "assembler-with-cpp"],
'c': ["-std=gnu99"],
'cxx': ["-std=gnu++98", "-fno-rtti", "-Wvla"],
'ld': ["-Wl,--gc-sections", "-Wl,--wrap,main",
"-Wl,--wrap,_malloc_r", "-Wl,--wrap,_free_r", "-Wl,--wrap,_realloc_r", "-Wl,--wrap,_calloc_r",
"-Wl,--wrap,exit", "-Wl,--wrap,atexit"],
}
def __init__(self, target, options=None, notify=None, macros=None, silent=False, tool_path="", extra_verbose=False):
mbedToolchain.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose)
if target.core == "Cortex-M0+": if target.core == "Cortex-M0+":
cpu = "cortex-m0plus" cpu = "cortex-m0plus"
@ -75,8 +61,6 @@ class GCC(mbedToolchain):
self.cpu.append("-mfpu=fpv5-d16") self.cpu.append("-mfpu=fpv5-d16")
self.cpu.append("-mfloat-abi=softfp") self.cpu.append("-mfloat-abi=softfp")
if target.core == "Cortex-A9": if target.core == "Cortex-A9":
self.cpu.append("-mthumb-interwork") self.cpu.append("-mthumb-interwork")
self.cpu.append("-marm") self.cpu.append("-marm")
@ -85,20 +69,8 @@ class GCC(mbedToolchain):
self.cpu.append("-mfloat-abi=hard") self.cpu.append("-mfloat-abi=hard")
self.cpu.append("-mno-unaligned-access") self.cpu.append("-mno-unaligned-access")
# Note: We are using "-O2" instead of "-Os" to avoid this known GCC bug:
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46762
self.flags["common"] += self.cpu self.flags["common"] += self.cpu
if "save-asm" in self.options:
self.flags["common"].append("-save-temps")
if "debug-info" in self.options:
self.flags["common"].append("-g")
self.flags["common"].append("-O0")
else:
self.flags["common"].append("-Os")
main_cc = join(tool_path, "arm-none-eabi-gcc") main_cc = join(tool_path, "arm-none-eabi-gcc")
main_cppc = join(tool_path, "arm-none-eabi-g++") main_cppc = join(tool_path, "arm-none-eabi-g++")
self.asm = [main_cc] + self.flags['asm'] + self.flags["common"] self.asm = [main_cc] + self.flags['asm'] + self.flags["common"]
@ -280,27 +252,12 @@ class GCC_ARM(GCC):
Returns False otherwise.""" Returns False otherwise."""
return mbedToolchain.generic_check_executable("GCC_ARM", 'arm-none-eabi-gcc', 1) return mbedToolchain.generic_check_executable("GCC_ARM", 'arm-none-eabi-gcc', 1)
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): def __init__(self, target, notify=None, macros=None,
GCC.__init__(self, target, options, notify, macros, silent, TOOLCHAIN_PATHS['GCC_ARM'], extra_verbose=extra_verbose) silent=False, extra_verbose=False, build_profile=None):
GCC.__init__(self, target, notify, macros, silent,
TOOLCHAIN_PATHS['GCC_ARM'], extra_verbose=extra_verbose,
build_profile=build_profile)
# Use latest gcc nanolib
if "std-lib" in self.options:
use_nano = False
elif "small-lib" in self.options:
use_nano = True
elif target.default_lib == "std":
use_nano = False
elif target.default_lib == "small":
use_nano = True
else:
use_nano = False
if use_nano:
self.ld.append("--specs=nano.specs")
self.flags['ld'].append("--specs=nano.specs")
self.cc += ["-DMBED_RTOS_SINGLE_THREAD"]
self.cppc += ["-DMBED_RTOS_SINGLE_THREAD"]
self.macros.extend(["MBED_RTOS_SINGLE_THREAD"])
self.sys_libs.append("nosys") self.sys_libs.append("nosys")
@ -312,8 +269,11 @@ class GCC_CR(GCC):
Returns False otherwise.""" Returns False otherwise."""
return mbedToolchain.generic_check_executable("GCC_CR", 'arm-none-eabi-gcc', 1) return mbedToolchain.generic_check_executable("GCC_CR", 'arm-none-eabi-gcc', 1)
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): def __init__(self, target, notify=None, macros=None,
GCC.__init__(self, target, options, notify, macros, silent, TOOLCHAIN_PATHS['GCC_CR'], extra_verbose=extra_verbose) silent=False, extra_verbose=False, build_profile=None):
GCC.__init__(self, target, notify, macros, silent,
TOOLCHAIN_PATHS['GCC_CR'], extra_verbose=extra_verbose,
build_profile=build_profile)
additional_compiler_flags = [ additional_compiler_flags = [
"-D__NEWLIB__", "-D__CODE_RED", "-D__USE_CMSIS", "-DCPP_USE_HEAP", "-D__NEWLIB__", "-D__CODE_RED", "-D__USE_CMSIS", "-DCPP_USE_HEAP",

View File

@ -29,24 +29,6 @@ class IAR(mbedToolchain):
DIAGNOSTIC_PATTERN = re.compile('"(?P<file>[^"]+)",(?P<line>[\d]+)\s+(?P<severity>Warning|Error)(?P<message>.+)') DIAGNOSTIC_PATTERN = re.compile('"(?P<file>[^"]+)",(?P<line>[\d]+)\s+(?P<severity>Warning|Error)(?P<message>.+)')
INDEX_PATTERN = re.compile('(?P<col>\s*)\^') INDEX_PATTERN = re.compile('(?P<col>\s*)\^')
# ANY changes to these default flags is backwards incompatible and require
# an update to the mbed-sdk-tools and website that introduces a profile
# for the previous version of these flags
DEFAULT_FLAGS = {
'common': [
"--no_wrap_diagnostics",
# Pa050: No need to be notified about "non-native end of line sequence"
# Pa084: Pointless integer comparison -> checks for the values of an enum, but we use values outside of the enum to notify errors (ie: NC).
# Pa093: Implicit conversion from float to integer (ie: wait_ms(85.4) -> wait_ms(85))
# Pa082: Operation involving two values from two registers (ie: (float)(*obj->MR)/(float)(LPC_PWM1->MR0))
"-e", # Enable IAR language extension
"--diag_suppress=Pa050,Pa084,Pa093,Pa082"],
'asm': [],
'c': ["--vla"],
'cxx': ["--guard_calls", "--no_static_destruction"],
'ld': ["--skip_dynamic_initialization", "--threaded_lib"],
}
@staticmethod @staticmethod
def check_executable(): def check_executable():
"""Returns True if the executable (arm-none-eabi-gcc) location """Returns True if the executable (arm-none-eabi-gcc) location
@ -54,8 +36,11 @@ class IAR(mbedToolchain):
Returns False otherwise.""" Returns False otherwise."""
return mbedToolchain.generic_check_executable("IAR", 'iccarm', 2, "bin") return mbedToolchain.generic_check_executable("IAR", 'iccarm', 2, "bin")
def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False): def __init__(self, target, notify=None, macros=None,
mbedToolchain.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose) silent=False, extra_verbose=False, build_profile=None):
mbedToolchain.__init__(self, target, notify, macros, silent,
extra_verbose=extra_verbose,
build_profile=build_profile)
if target.core == "Cortex-M7F" or target.core == "Cortex-M7FD": if target.core == "Cortex-M7F" or target.core == "Cortex-M7FD":
cpuchoice = "Cortex-M7" cpuchoice = "Cortex-M7"
else: else:
@ -94,12 +79,6 @@ class IAR(mbedToolchain):
asm_flags_cmd += ["--fpu", "VFPv5_sp"] asm_flags_cmd += ["--fpu", "VFPv5_sp"]
c_flags_cmd.append("--fpu=VFPv5_sp") c_flags_cmd.append("--fpu=VFPv5_sp")
if "debug-info" in self.options:
c_flags_cmd.append("-r")
c_flags_cmd.append("-On")
else:
c_flags_cmd.append("-Oh")
IAR_BIN = join(TOOLCHAIN_PATHS['IAR'], "bin") IAR_BIN = join(TOOLCHAIN_PATHS['IAR'], "bin")
main_cc = join(IAR_BIN, "iccarm") main_cc = join(IAR_BIN, "iccarm")