mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #4103 from andrewleech/extra_targets
Add extra_targets.json support to build toolspull/4639/head
commit
f3dc8a6bb1
|
@ -32,6 +32,7 @@ from tools.toolchains import mbedToolchain
|
|||
from tools.targets import TARGET_NAMES, TARGET_MAP
|
||||
from tools.options import get_default_options_parser
|
||||
from tools.options import extract_profile
|
||||
from tools.options import extract_mcus
|
||||
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 print_build_results
|
||||
|
@ -134,7 +135,7 @@ if __name__ == '__main__':
|
|||
|
||||
|
||||
# Get target list
|
||||
targets = options.mcu if options.mcu else TARGET_NAMES
|
||||
targets = extract_mcus(parser, options) if options.mcu else TARGET_NAMES
|
||||
|
||||
# Get toolchains list
|
||||
toolchains = options.tool if options.tool else TOOLCHAINS
|
||||
|
|
|
@ -26,6 +26,7 @@ sys.path.insert(0, ROOT)
|
|||
|
||||
from tools.utils import args_error
|
||||
from tools.options import get_default_options_parser
|
||||
from tools.options import extract_mcus
|
||||
from tools.build_api import get_config
|
||||
from config import Config
|
||||
from utils import argparse_filestring_type
|
||||
|
@ -49,7 +50,7 @@ if __name__ == '__main__':
|
|||
# Target
|
||||
if options.mcu is None :
|
||||
args_error(parser, "argument -m/--mcu is required")
|
||||
target = options.mcu[0]
|
||||
target = extract_mcus(parser, options)[0]
|
||||
|
||||
# Toolchain
|
||||
if options.tool is None:
|
||||
|
|
|
@ -42,6 +42,7 @@ from tools.tests import test_known, test_name_known
|
|||
from tools.targets import TARGET_MAP
|
||||
from tools.options import get_default_options_parser
|
||||
from tools.options import extract_profile
|
||||
from tools.options import extract_mcus
|
||||
from tools.build_api import build_project
|
||||
from tools.build_api import mcu_toolchain_matrix
|
||||
from tools.build_api import mcu_toolchain_list
|
||||
|
@ -200,7 +201,7 @@ if __name__ == '__main__':
|
|||
# Target
|
||||
if options.mcu is None :
|
||||
args_error(parser, "argument -m/--mcu is required")
|
||||
mcu = options.mcu[0]
|
||||
mcu = extract_mcus(parser, options)[0]
|
||||
|
||||
# Toolchain
|
||||
if options.tool is None:
|
||||
|
|
|
@ -17,9 +17,9 @@ limitations under the License.
|
|||
from json import load
|
||||
from os.path import join, dirname
|
||||
from os import listdir
|
||||
from argparse import ArgumentParser
|
||||
from argparse import ArgumentParser, ArgumentTypeError
|
||||
from tools.toolchains import TOOLCHAINS
|
||||
from tools.targets import TARGET_NAMES
|
||||
from tools.targets import TARGET_NAMES, Target, update_target_data
|
||||
from tools.utils import argparse_force_uppercase_type, \
|
||||
argparse_lowercase_hyphen_type, argparse_many, \
|
||||
argparse_filestring_type, args_error, argparse_profile_filestring_type,\
|
||||
|
@ -47,10 +47,7 @@ def get_default_options_parser(add_clean=True, add_options=True,
|
|||
parser.add_argument("-m", "--mcu",
|
||||
help=("build for the given MCU (%s)" %
|
||||
', '.join(targetnames)),
|
||||
metavar="MCU",
|
||||
type=argparse_many(
|
||||
argparse_force_uppercase_type(
|
||||
targetnames, "MCU")))
|
||||
metavar="MCU")
|
||||
|
||||
parser.add_argument("-t", "--tool",
|
||||
help=("build using the given TOOLCHAIN (%s)" %
|
||||
|
@ -130,3 +127,19 @@ def mcu_is_enabled(parser, mcu):
|
|||
"See https://developer.mbed.org/platforms/Renesas-GR-PEACH/#important-notice "
|
||||
"for more information") % (mcu, mcu))
|
||||
return True
|
||||
|
||||
def extract_mcus(parser, options):
|
||||
try:
|
||||
if options.source_dir:
|
||||
for source_dir in options.source_dir:
|
||||
Target.add_extra_targets(source_dir)
|
||||
update_target_data()
|
||||
except KeyError:
|
||||
pass
|
||||
targetnames = TARGET_NAMES
|
||||
targetnames.sort()
|
||||
try:
|
||||
return argparse_many(argparse_force_uppercase_type(targetnames, "MCU"))(options.mcu)
|
||||
except ArgumentTypeError as exc:
|
||||
args_error(parser, "argument -m/--mcu: {}".format(str(exc)))
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ from tools.utils import argparse_filestring_type, argparse_profile_filestring_ty
|
|||
from tools.utils import argparse_force_lowercase_type
|
||||
from tools.utils import argparse_force_uppercase_type
|
||||
from tools.utils import print_large_string
|
||||
from tools.options import extract_profile, list_profiles
|
||||
from tools.options import extract_profile, list_profiles, extract_mcus
|
||||
|
||||
def setup_project(ide, target, program=None, source_dir=None, build=None, export_path=None):
|
||||
"""Generate a name, if not provided, and find dependencies
|
||||
|
@ -247,7 +247,8 @@ def main():
|
|||
profile = extract_profile(parser, options, toolchain_name, fallback="debug")
|
||||
if options.clean:
|
||||
rmtree(BUILD_DIR)
|
||||
export(options.mcu, options.ide, build=options.build,
|
||||
mcu = extract_mcus(parser, options)[0]
|
||||
export(mcu, options.ide, build=options.build,
|
||||
src=options.source_dir, macros=options.macros,
|
||||
project_id=options.program, zip_proj=zip_proj,
|
||||
build_profile=profile, app_config=options.app_config)
|
||||
|
|
|
@ -22,7 +22,7 @@ import shutil
|
|||
import inspect
|
||||
import sys
|
||||
from copy import copy
|
||||
from collections import namedtuple
|
||||
from collections import namedtuple, Mapping
|
||||
from tools.targets.LPC import patch
|
||||
from tools.paths import TOOLS_BOOTLOADERS
|
||||
from tools.utils import json_file_to_dict
|
||||
|
@ -125,18 +125,38 @@ class Target(namedtuple("Target", "name json_data resolution_order resolution_or
|
|||
# Current/new location of the 'targets.json' file
|
||||
__targets_json_location = None
|
||||
|
||||
# Extra custom targets files
|
||||
__extra_target_json_files = []
|
||||
|
||||
@staticmethod
|
||||
@cached
|
||||
def get_json_target_data():
|
||||
"""Load the description of JSON target data"""
|
||||
return json_file_to_dict(Target.__targets_json_location or
|
||||
Target.__targets_json_location_default)
|
||||
targets = json_file_to_dict(Target.__targets_json_location or
|
||||
Target.__targets_json_location_default)
|
||||
|
||||
for extra_target in Target.__extra_target_json_files:
|
||||
for k, v in json_file_to_dict(extra_target).iteritems():
|
||||
if k in targets:
|
||||
print 'WARNING: Custom target "%s" cannot replace existing target.' % k
|
||||
else:
|
||||
targets[k] = v
|
||||
|
||||
return targets
|
||||
|
||||
@staticmethod
|
||||
def add_extra_targets(source_dir):
|
||||
extra_targets_file = os.path.join(source_dir, "custom_targets.json")
|
||||
if os.path.exists(extra_targets_file):
|
||||
Target.__extra_target_json_files.append(extra_targets_file)
|
||||
CACHES.clear()
|
||||
|
||||
@staticmethod
|
||||
def set_targets_json_location(location=None):
|
||||
"""Set the location of the targets.json file"""
|
||||
Target.__targets_json_location = (location or
|
||||
Target.__targets_json_location_default)
|
||||
Target.__extra_target_json_files = []
|
||||
# Invalidate caches, since the location of the JSON file changed
|
||||
CACHES.clear()
|
||||
|
||||
|
@ -507,14 +527,20 @@ class RTL8195ACode:
|
|||
################################################################################
|
||||
|
||||
# Instantiate all public targets
|
||||
TARGETS = [Target.get_target(name) for name, value
|
||||
in Target.get_json_target_data().items()
|
||||
if value.get("public", True)]
|
||||
def update_target_data():
|
||||
TARGETS[:] = [Target.get_target(tgt) for tgt, obj
|
||||
in Target.get_json_target_data().items()
|
||||
if obj.get("public", True)]
|
||||
# Map each target name to its unique instance
|
||||
TARGET_MAP.clear()
|
||||
TARGET_MAP.update(dict([(tgt.name, tgt) for tgt in TARGETS]))
|
||||
TARGET_NAMES[:] = TARGET_MAP.keys()
|
||||
|
||||
# Map each target name to its unique instance
|
||||
TARGET_MAP = dict([(t.name, t) for t in TARGETS])
|
||||
TARGETS = []
|
||||
TARGET_MAP = dict()
|
||||
TARGET_NAMES = []
|
||||
|
||||
TARGET_NAMES = TARGET_MAP.keys()
|
||||
update_target_data()
|
||||
|
||||
# Some targets with different name have the same exporters
|
||||
EXPORT_MAP = {}
|
||||
|
@ -537,9 +563,5 @@ def set_targets_json_location(location=None):
|
|||
# re-initialization does not create new variables, it keeps the old ones
|
||||
# instead. This ensures compatibility with code that does
|
||||
# "from tools.targets import TARGET_NAMES"
|
||||
TARGETS[:] = [Target.get_target(tgt) for tgt, obj
|
||||
in Target.get_json_target_data().items()
|
||||
if obj.get("public", True)]
|
||||
TARGET_MAP.clear()
|
||||
TARGET_MAP.update(dict([(tgt.name, tgt) for tgt in TARGETS]))
|
||||
TARGET_NAMES[:] = TARGET_MAP.keys()
|
||||
update_target_data()
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ sys.path.insert(0, ROOT)
|
|||
|
||||
from tools.config import ConfigException
|
||||
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, extract_profile
|
||||
from tools.options import get_default_options_parser, extract_profile, extract_mcus
|
||||
from tools.build_api import build_project, build_library
|
||||
from tools.build_api import print_build_memory_usage
|
||||
from tools.build_api import merge_build_data
|
||||
|
@ -114,7 +114,7 @@ if __name__ == '__main__':
|
|||
# Target
|
||||
if options.mcu is None :
|
||||
args_error(parser, "argument -m/--mcu is required")
|
||||
mcu = options.mcu[0]
|
||||
mcu = extract_mcus(parser, options)[0]
|
||||
|
||||
# Toolchain
|
||||
if options.tool is None:
|
||||
|
|
|
@ -15,18 +15,23 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import tempfile
|
||||
from os.path import join, abspath, dirname
|
||||
from contextlib import contextmanager
|
||||
import unittest
|
||||
|
||||
# Be sure that the tools directory is in the search path
|
||||
|
||||
ROOT = abspath(join(dirname(__file__), "..", "..", ".."))
|
||||
sys.path.insert(0, ROOT)
|
||||
|
||||
from tools.targets import TARGETS
|
||||
from tools.targets import TARGETS, TARGET_MAP, Target, update_target_data
|
||||
from tools.arm_pack_manager import Cache
|
||||
|
||||
|
||||
class TestTargets(unittest.TestCase):
|
||||
|
||||
def test_device_name(self):
|
||||
|
@ -39,5 +44,98 @@ class TestTargets(unittest.TestCase):
|
|||
"Target %s contains invalid device_name %s" %
|
||||
(target.name, target.device_name))
|
||||
|
||||
@contextmanager
|
||||
def temp_target_file(self, extra_target, json_filename='custom_targets.json'):
|
||||
"""Create an extra targets temp file in a context manager"""
|
||||
tempdir = tempfile.mkdtemp()
|
||||
try:
|
||||
targetfile = os.path.join(tempdir, json_filename)
|
||||
with open(targetfile, 'w') as f:
|
||||
f.write(extra_target)
|
||||
yield tempdir
|
||||
finally:
|
||||
# Reset extra targets
|
||||
Target.set_targets_json_location()
|
||||
# Delete temp files
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
def test_add_extra_targets(self):
|
||||
"""Search for extra targets json in a source folder"""
|
||||
test_target_json = """
|
||||
{
|
||||
"Test_Target": {
|
||||
"inherits": ["Target"]
|
||||
}
|
||||
}
|
||||
"""
|
||||
with self.temp_target_file(test_target_json) as source_dir:
|
||||
Target.add_extra_targets(source_dir=source_dir)
|
||||
update_target_data()
|
||||
|
||||
assert 'Test_Target' in TARGET_MAP
|
||||
assert TARGET_MAP['Test_Target'].core is None, \
|
||||
"attributes should be inherited from Target"
|
||||
|
||||
def test_modify_existing_target(self):
|
||||
"""Set default targets file, then override base Target definition"""
|
||||
initial_target_json = """
|
||||
{
|
||||
"Target": {
|
||||
"core": null,
|
||||
"default_toolchain": "ARM",
|
||||
"supported_toolchains": null,
|
||||
"extra_labels": [],
|
||||
"is_disk_virtual": false,
|
||||
"macros": [],
|
||||
"device_has": [],
|
||||
"features": [],
|
||||
"detect_code": [],
|
||||
"public": false,
|
||||
"default_lib": "std",
|
||||
"bootloader_supported": false
|
||||
},
|
||||
"Test_Target": {
|
||||
"inherits": ["Target"],
|
||||
"core": "Cortex-M4",
|
||||
"supported_toolchains": ["ARM"]
|
||||
}
|
||||
}"""
|
||||
|
||||
test_target_json = """
|
||||
{
|
||||
"Target": {
|
||||
"core": "Cortex-M0",
|
||||
"default_toolchain": "GCC_ARM",
|
||||
"supported_toolchains": null,
|
||||
"extra_labels": [],
|
||||
"is_disk_virtual": false,
|
||||
"macros": [],
|
||||
"device_has": [],
|
||||
"features": [],
|
||||
"detect_code": [],
|
||||
"public": false,
|
||||
"default_lib": "std",
|
||||
"bootloader_supported": true
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
with self.temp_target_file(initial_target_json, json_filename="targets.json") as targets_dir:
|
||||
Target.set_targets_json_location(os.path.join(targets_dir, "targets.json"))
|
||||
update_target_data()
|
||||
assert TARGET_MAP["Test_Target"].core == "Cortex-M4"
|
||||
assert TARGET_MAP["Test_Target"].default_toolchain == 'ARM'
|
||||
assert TARGET_MAP["Test_Target"].bootloader_supported == False
|
||||
|
||||
with self.temp_target_file(test_target_json) as source_dir:
|
||||
Target.add_extra_targets(source_dir=source_dir)
|
||||
update_target_data()
|
||||
|
||||
assert TARGET_MAP["Test_Target"].core == "Cortex-M4"
|
||||
# The existing target should not be modified by custom targets
|
||||
assert TARGET_MAP["Test_Target"].default_toolchain != 'GCC_ARM'
|
||||
assert TARGET_MAP["Test_Target"].bootloader_supported != True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue