diff --git a/tools/targets.py b/tools/targets.py index 73a3c0a840b..3d4a3b380c8 100644 --- a/tools/targets.py +++ b/tools/targets.py @@ -48,9 +48,9 @@ class HookError(Exception): caches = {} def cached(func): def wrapper(*args, **kwargs): - if not caches.has_key(func): - caches[func] = func(*args, **kwargs) - return caches[func] + if not caches.has_key((func.__name__, args)): + caches[(func.__name__, args)] = func(*args, **kwargs) + return caches[(func.__name__, args)] return wrapper class Target: @@ -58,17 +58,21 @@ class Target: # need to be computed differently than regular attributes __cumulative_attributes = ['extra_labels', 'macros', 'device_has', 'features'] - # {target_name: target_instance} map for all the targets in the system - __target_map = {} - - # List of targets that were added dynamically using "add_py_targets" (see below) - __py_targets = set() + # Location of the 'targets.json' file + __targets_json_location = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'hal', 'targets.json') # Load the description of JSON target data @staticmethod @cached def get_json_target_data(): - return json_file_to_dict(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'hal', 'targets.json')) + return json_file_to_dict(Target.__targets_json_location) + + # Set the location of the targets.json file + @staticmethod + def set_targets_json_location(location): + Target.__targets_json_location = location + # Invalidate caches, since the location of the JSON file changed + caches.clear() # Get the members of this module using Python's "inspect" module @staticmethod @@ -168,42 +172,26 @@ def __getattr__(self, attrname): return v # Add one or more new target(s) represented as a Python dictionary in 'new_targets' - # It it an error to add a target with a name that exists in "targets.json" - # However, it is OK to add a target that was previously added via "add_py_targets" - # (this makes testing easier without changing the regular semantics) + # It is an error to add a target with a name that already exists. @staticmethod def add_py_targets(new_targets): crt_data = Target.get_json_target_data() - # First add all elemnts to the internal dictionary for tk, tv in new_targets.items(): - if crt_data.has_key(tk) and (not tk in Target.__py_targets): + if crt_data.has_key(tk): raise Exception("Attempt to add target '%s' that already exists" % tk) + # Add target data to the internal target dictionary crt_data[tk] = tv - Target.__py_targets.add(tk) - # Then create the new instances and update global variables if needed - for tk, tv in new_targets.items(): - # Is the target already created? - old_target = Target.__target_map.get(tk, None) - # Instantiate this target. If it is public, update the data in - # in TARGETS, TARGET_MAP, TARGET_NAMES + # Create the new target and add it to the relevant data structures new_target = Target(tk) - if tv.get("public", True): - if old_target: # remove the old target from TARGETS and TARGET_NAMES - TARGETS.remove(old_target) - TARGET_NAMES.remove(tk) - # Add the new target - TARGETS.append(new_target) - TARGET_MAP[tk] = new_target - TARGET_NAMES.append(tk) - # Update the target cache - Target.__target_map[tk] = new_target + TARGETS.append(new_target) + TARGET_MAP[tk] = new_target + TARGET_NAMES.append(tk) # Return the target instance starting from the target name @staticmethod + @cached def get_target(name): - if not Target.__target_map.has_key(name): - Target.__target_map[name] = Target(name) - return Target.__target_map[name] + return Target(name) def __init__(self, name): self.name = name @@ -414,3 +402,15 @@ def get_target_detect_codes(): for detect_code in target.detect_code: result[detect_code] = target.name return result + +# Sets the location of the JSON file that contains the targets +def set_targets_json_location(location): + # First instruct Target about the new location + Target.set_targets_json_location(location) + # Then re-initialize TARGETS, TARGET_MAP and TARGET_NAMES + # The 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(name) for name, value in Target.get_json_target_data().items() if value.get("public", True)] + TARGET_MAP.clear() + TARGET_MAP.update(dict([(t.name, t) for t in TARGETS])) + TARGET_NAMES[:] = TARGET_MAP.keys() diff --git a/tools/test/config_test/config_test.py b/tools/test/config_test/config_test.py index 59c2b50c98d..d9f692e5bf8 100644 --- a/tools/test/config_test/config_test.py +++ b/tools/test/config_test/config_test.py @@ -16,6 +16,7 @@ """ from tools.build_api import get_config +from tools.targets import set_targets_json_location, Target from tools.config import ConfigException, Config import os, sys @@ -43,6 +44,8 @@ def test_tree(full_name, name): sys.stdout.flush() err_msg = None try: + # Use 'set_targets_json_location' to remove the previous custom targets from the target list + set_targets_json_location(Target._Target__targets_json_location) cfg, macros, features = get_config(full_name, target, "GCC_ARM") macros = Config.config_macros_to_macros(macros) except ConfigException as e: