Update project generator script to allow working with any source

Update test exporters script
Update travis build script
Added config system CLI script
Fixed building of legacy libraries and layouts
pull/1893/head
Mihail Stoyanov 2016-06-09 23:51:26 +01:00
parent c2e3001739
commit 9f62d70fbf
7 changed files with 321 additions and 80 deletions

View File

@ -192,7 +192,7 @@ if __name__ == '__main__':
if options.usb_host:
libraries.append("usb_host")
if options.dsp:
libraries.extend(["cmsis_dsp", "dsp"])
libraries.extend(["dsp"])
if options.fat:
libraries.extend(["fat"])
if options.ublox:

View File

@ -394,33 +394,145 @@ def build_library(src_paths, build_path, target, toolchain_name,
# Let Exception propagate
raise e
def build_lib(lib_id, target, toolchain, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False):
""" Wrapper for build_library function.
######################
### Legacy methods ###
######################
def build_lib(lib_id, target, toolchain_name, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False):
""" Legacy method for building mbed libraries
Function builds library in proper directory using all dependencies and macros defined by user.
"""
lib = Library(lib_id)
if lib.is_supported(target, toolchain):
# We need to combine macros from parameter list with macros from library definition
MACROS = lib.macros if lib.macros else []
if macros:
MACROS.extend(macros)
return build_library(lib.source_dir, lib.build_dir, target, toolchain, lib.dependencies, options,
verbose=verbose,
silent=silent,
clean=clean,
macros=MACROS,
notify=notify,
inc_dirs=lib.inc_dirs,
inc_dirs_ext=lib.inc_dirs_ext,
jobs=jobs,
report=report,
properties=properties,
extra_verbose=extra_verbose)
else:
if not lib.is_supported(target, toolchain_name):
print 'Library "%s" is not yet supported on target %s with toolchain %s' % (lib_id, target.name, toolchain)
return False
# We need to combine macros from parameter list with macros from library definition
MACROS = lib.macros if lib.macros else []
if macros:
macros.extend(MACROS)
else:
macros = MACROS
src_paths = lib.source_dir
build_path = lib.build_dir
dependencies_paths = lib.dependencies
inc_dirs = lib.inc_dirs
inc_dirs_ext = lib.inc_dirs_ext
""" src_path: the path of the source directory
build_path: the path of the build directory
target: ['LPC1768', 'LPC11U24', 'LPC2368']
toolchain: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR']
library_paths: List of paths to additional libraries
clean: Rebuild everything if True
notify: Notify function for logs
verbose: Write the actual tools command lines if True
inc_dirs: additional include directories which should be included in build
inc_dirs_ext: additional include directories which should be copied to library directory
"""
if type(src_paths) != ListType:
src_paths = [src_paths]
# The first path will give the name to the library
name = basename(src_paths[0])
if report != None:
start = time()
id_name = name.upper()
description = name
vendor_label = target.extra_labels[0]
cur_result = None
prep_report(report, target.name, toolchain_name, id_name)
cur_result = create_result(target.name, toolchain_name, id_name, description)
if properties != None:
prep_properties(properties, target.name, toolchain_name, vendor_label)
for src_path in src_paths:
if not exists(src_path):
error_msg = "The library source folder does not exist: %s", src_path
if report != None:
cur_result["output"] = error_msg
cur_result["result"] = "FAIL"
add_result_to_report(report, cur_result)
raise Exception(error_msg)
try:
# Toolchain instance
toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent, extra_verbose=extra_verbose)
toolchain.VERBOSE = verbose
toolchain.jobs = jobs
toolchain.build_all = clean
toolchain.info("Building library %s (%s, %s)" % (name.upper(), target.name, toolchain_name))
# Scan Resources
resources = []
for src_path in src_paths:
resources.append(toolchain.scan_resources(src_path))
# Add extra include directories / files which are required by library
# This files usually are not in the same directory as source files so
# previous scan will not include them
if inc_dirs_ext is not None:
for inc_ext in inc_dirs_ext:
resources.append(toolchain.scan_resources(inc_ext))
# Dependencies Include Paths
dependencies_include_dir = []
if dependencies_paths is not None:
for path in dependencies_paths:
lib_resources = toolchain.scan_resources(path)
dependencies_include_dir.extend(lib_resources.inc_dirs)
if inc_dirs:
dependencies_include_dir.extend(inc_dirs)
# Create the desired build directory structure
bin_path = join(build_path, toolchain.obj_path)
mkdir(bin_path)
tmp_path = join(build_path, '.temp', toolchain.obj_path)
mkdir(tmp_path)
# Copy Headers
for resource in resources:
toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path)
dependencies_include_dir.extend(toolchain.scan_resources(build_path).inc_dirs)
# Compile Sources
objects = []
for resource in resources:
objects.extend(toolchain.compile_sources(resource, tmp_path, dependencies_include_dir))
needed_update = toolchain.build_library(objects, bin_path, name)
if report != None and needed_update:
end = time()
cur_result["elapsed_time"] = end - start
cur_result["output"] = toolchain.get_output()
cur_result["result"] = "OK"
add_result_to_report(report, cur_result)
except Exception, e:
if report != None:
end = time()
cur_result["result"] = "FAIL"
cur_result["elapsed_time"] = end - start
toolchain_output = toolchain.get_output()
if toolchain_output:
cur_result["output"] += toolchain_output
cur_result["output"] += str(e)
add_result_to_report(report, cur_result)
# Let Exception propagate
raise e
# We do have unique legacy conventions about how we build and package the mbed library
def build_mbed_libs(target, toolchain_name, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False):
@ -543,6 +655,7 @@ def build_mbed_libs(target, toolchain_name, options=None, verbose=False, clean=F
# Let Exception propagate
raise e
def get_unique_supported_toolchains():
""" Get list of all unique toolchains supported by targets """
unique_supported_toolchains = []

94
tools/get_config.py Normal file
View File

@ -0,0 +1,94 @@
#! /usr/bin/env python2
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import sys
from os.path import isdir, abspath, dirname, join
from os import _exit
# Be sure that the tools directory is in the search path
ROOT = abspath(join(dirname(__file__), ".."))
sys.path.insert(0, ROOT)
from tools.utils import args_error
from tools.options import get_default_options_parser
from tools.build_api import get_config
from config import Config
try:
import tools.private_settings as ps
except:
ps = object()
if __name__ == '__main__':
# Parse Options
parser = get_default_options_parser(add_clean=False, add_options=False)
parser.add_option("--source", dest="source_dir",
default=None, help="The source (input) directory", action="append")
parser.add_option("--prefix", dest="prefix", action="append",
default=None, help="Restrict listing to parameters that have this prefix")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
default=False, help="Verbose diagnostic output")
(options, args) = parser.parse_args()
for path in options.source_dir :
if not isdir(path) :
args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist".
format(path))
# Target
if options.mcu is None :
args_error(parser, "[ERROR] You should specify an MCU")
target = options.mcu
# Toolchain
if options.tool is None:
args_error(parser, "[ERROR] You should specify a TOOLCHAIN")
toolchain = options.tool
options.prefix = options.prefix or [""]
try:
params, macros = get_config(options.source_dir, target, toolchain)
if not params and not macros:
print "No configuration data available."
_exit(0)
if params:
print "Configuration parameters"
print "------------------------"
for p in params:
for s in options.prefix:
if p.startswith(s):
print(str(params[p]) if not options.verbose else params[p].get_verbose_description())
break
print ""
print "Macros"
print "------"
if macros:
print 'Defined with "macros":', macros
print "Generated from configuration parameters:", Config.parameters_to_macros(params)
except KeyboardInterrupt, e:
print "\n[CTRL+c] exit"
except Exception,e:
if options.verbose:
import traceback
traceback.print_exc(file=sys.stdout)
else:
print "[ERROR] %s" % str(e)
sys.exit(1)

View File

@ -59,17 +59,11 @@ LIBRARIES = [
},
# DSP libraries
{
"id": "cmsis_dsp",
"source_dir": DSP_CMSIS,
"build_dir": DSP_LIBRARIES,
"dependencies": [MBED_LIBRARIES],
},
{
"id": "dsp",
"source_dir": DSP_ABSTRACTION,
"source_dir": [DSP_ABSTRACTION, DSP_CMSIS],
"build_dir": DSP_LIBRARIES,
"dependencies": [MBED_LIBRARIES, DSP_CMSIS],
"dependencies": [MBED_LIBRARIES]
},
# File system libraries

View File

@ -1,21 +1,22 @@
import sys
from os.path import join, abspath, dirname, exists
from os.path import join, abspath, dirname, exists, basename
ROOT = abspath(join(dirname(__file__), ".."))
sys.path.insert(0, ROOT)
from shutil import move, rmtree
from optparse import OptionParser
from os import path
from tools.paths import EXPORT_DIR, EXPORT_WORKSPACE, EXPORT_TMP
from tools.paths import MBED_BASE, MBED_LIBRARIES
from tools.export import export, setup_user_prj, EXPORTERS, mcu_ide_matrix
from tools.utils import args_error
from tools.utils import args_error, mkdir
from tools.tests import TESTS, Test, TEST_MAP
from tools.targets import TARGET_NAMES
from tools.libraries import LIBRARIES
try:
import mbed_settings as ps
import tools.private_settings as ps
except:
ps = object()
@ -77,6 +78,17 @@ if __name__ == '__main__':
default=False,
help="writes tools/export/README.md")
parser.add_option("--source",
action="append",
dest="source_dir",
default=None,
help="The source (input) directory")
parser.add_option("-D", "",
action="append",
dest="macros",
help="Add a macro definition")
(options, args) = parser.parse_args()
# Print available tests in order and exit
@ -123,63 +135,86 @@ if __name__ == '__main__':
# Export results
successes = []
failures = []
zip = True
clean = True
# source_dir = use relative paths, otherwise sources are copied
sources_relative = True if options.source_dir else False
for mcu in mcus.split(','):
# Program Number or name
p, n = options.program, options.program_name
p, n, src, ide = options.program, options.program_name, options.source_dir, options.ide
if n is not None and p is not None:
args_error(parser, "[ERROR] specify either '-n' or '-p', not both")
if n:
if not n in TEST_MAP.keys():
# Check if there is an alias for this in mbed_settings.py
if getattr(ps, "test_alias", None) is not None:
alias = ps.test_alias.get(n, "")
if not alias in TEST_MAP.keys():
args_error(parser, "[ERROR] Program with name '%s' not found" % n)
if src is not None:
# --source is used to generate IDE files to toolchain directly in the source tree and doesn't generate zip file
project_dir = options.source_dir
project_name = n if n else "Unnamed_Project"
project_temp = path.join(options.source_dir[0], 'projectfiles', ide)
mkdir(project_temp)
lib_symbols = []
if options.macros:
lib_symbols += options.macros
zip = False # don't create zip
clean = False # don't cleanup because we use the actual source tree to generate IDE files
else:
if n is not None and p is not None:
args_error(parser, "[ERROR] specify either '-n' or '-p', not both")
if n:
if not n in TEST_MAP.keys():
# Check if there is an alias for this in private_settings.py
if getattr(ps, "test_alias", None) is not None:
alias = ps.test_alias.get(n, "")
if not alias in TEST_MAP.keys():
args_error(parser, "[ERROR] Program with name '%s' not found" % n)
else:
n = alias
else:
n = alias
else:
args_error(parser, "[ERROR] Program with name '%s' not found" % n)
p = TEST_MAP[n].n
if p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
args_error(parser, "[ERROR] Program with name '%s' not found" % n)
p = TEST_MAP[n].n
if p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
# Project
if p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
test = Test(p)
# Project
if p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
test = Test(p)
# Some libraries have extra macros (called by exporter symbols) to we need to pass
# them to maintain compilation macros integrity between compiled library and
# header files we might use with it
lib_symbols = []
for lib in LIBRARIES:
if lib['build_dir'] in test.dependencies:
lib_macros = lib.get('macros', None)
if lib_macros is not None:
lib_symbols.extend(lib_macros)
# Some libraries have extra macros (called by exporter symbols) to we need to pass
# them to maintain compilation macros integrity between compiled library and
# header files we might use with it
lib_symbols = []
if options.macros:
lib_symbols += options.macros
for lib in LIBRARIES:
if lib['build_dir'] in test.dependencies:
lib_macros = lib.get('macros', None)
if lib_macros is not None:
lib_symbols.extend(lib_macros)
if not options.build:
# Substitute the library builds with the sources
# TODO: Substitute also the other library build paths
if MBED_LIBRARIES in test.dependencies:
test.dependencies.remove(MBED_LIBRARIES)
test.dependencies.append(MBED_BASE)
if not options.build:
# Substitute the library builds with the sources
# TODO: Substitute also the other library build paths
if MBED_LIBRARIES in test.dependencies:
test.dependencies.remove(MBED_LIBRARIES)
test.dependencies.append(MBED_BASE)
# Build the project with the same directory structure of the mbed online IDE
project_dir = join(EXPORT_WORKSPACE, test.id)
setup_user_prj(project_dir, test.source_dir, test.dependencies)
# Build the project with the same directory structure of the mbed online IDE
project_name = test.id
project_dir = join(EXPORT_WORKSPACE, project_name)
project_temp = EXPORT_TMP
setup_user_prj(project_dir, test.source_dir, test.dependencies)
# Export to selected toolchain
tmp_path, report = export(project_dir, test.id, ide, mcu, EXPORT_WORKSPACE, EXPORT_TMP, extra_symbols=lib_symbols)
tmp_path, report = export(project_dir, project_name, ide, mcu, project_dir, project_temp, clean=clean, zip=zip, extra_symbols=lib_symbols, relative=sources_relative)
if report['success']:
zip_path = join(EXPORT_DIR, "%s_%s_%s.zip" % (test.id, ide, mcu))
move(tmp_path, zip_path)
zip_path = join(EXPORT_DIR, "%s_%s_%s.zip" % (project_name, ide, mcu))
if zip:
move(tmp_path, zip_path)
successes.append("%s::%s\t%s"% (mcu, ide, zip_path))
else:
failures.append("%s::%s\t%s"% (mcu, ide, report['errormsg']))

View File

@ -17,7 +17,8 @@ limitations under the License.
Author: Przemyslaw Wirkus <Przemyslaw.wirkus@arm.com>
"""
from tools.utils import construct_enum
from tools.utils import construct_enum, mkdir
import os
ResultExporterType = construct_enum(HTML='Html_Exporter',
@ -97,6 +98,9 @@ class ReportExporter():
def write_to_file(self, report, file_name):
if report is not None:
dirname = os.path.dirname(file_name)
if dirname:
mkdir(dirname)
with open(file_name, 'w') as f:
f.write(report)

View File

@ -61,7 +61,8 @@ class IAR(mbedToolchain):
IAR_BIN = join(IAR_PATH, "bin")
main_cc = join(IAR_BIN, "iccarm")
if target.core == "Cortex-M7F":
if target.core == "Cortex-M7F":
self.asm = [join(IAR_BIN, "iasmarm")] + ["--cpu", cpuchoice] + ["--fpu", "VFPv5_sp"]
else:
self.asm = [join(IAR_BIN, "iasmarm")] + ["--cpu", cpuchoice]