37
37
import json
38
38
import inspect
39
39
import sys
40
-
40
+ from tools . utils import json_file_to_dict
41
41
42
42
########################################################################################################################
43
43
# Generic Target class that reads and interprets the data in targets.json
@@ -58,29 +58,19 @@ def wrapper(*args, **kwargs):
58
58
class Target :
59
59
# Cumulative attributes can have values appended to them, so they
60
60
# need to be computed differently than regular attributes
61
- __cumulative_attributes = ['extra_labels' , 'macros' , 'device_has' ]
61
+ __cumulative_attributes = ['extra_labels' , 'macros' , 'device_has' , 'features' ]
62
62
63
- # Utility function: traverse a dictionary and change all the strings in the dictionary to
64
- # ASCII from Unicode. Needed because the original mbed target definitions were written in
65
- # Python and used only ASCII strings, but the Python JSON decoder always returns Unicode
66
- # Based on http://stackoverflow.com/a/13105359
67
- @staticmethod
68
- def to_ascii (input ):
69
- if isinstance (input , dict ):
70
- return dict ([(Target .to_ascii (key ), Target .to_ascii (value )) for key , value in input .iteritems ()])
71
- elif isinstance (input , list ):
72
- return [Target .to_ascii (element ) for element in input ]
73
- elif isinstance (input , unicode ):
74
- return input .encode ('ascii' )
75
- else :
76
- return input
63
+ # {target_name: target_instance} map for all the targets in the system
64
+ __target_map = {}
65
+
66
+ # List of targets that were added dynamically using "add_py_targets" (see below)
67
+ __py_targets = set ()
77
68
78
69
# Load the description of JSON target data
79
70
@staticmethod
80
71
@cached
81
72
def get_json_target_data ():
82
- with open (os .path .join (os .path .dirname (os .path .abspath (__file__ )), "../hal/targets.json" ), "rt" ) as f :
83
- return Target .to_ascii (json .load (f ))
73
+ return json_file_to_dict (os .path .join (os .path .dirname (os .path .abspath (__file__ )), '..' , 'hal' , 'targets.json' ))
84
74
85
75
# Get the members of this module using Python's "inspect" module
86
76
@staticmethod
@@ -172,21 +162,58 @@ def __getattr_helper(self, attrname):
172
162
return v if attrname != "progen" else self .__add_paths_to_progen (v )
173
163
174
164
# Return the value of an attribute
175
- # This function only looks for the attribute's value in the cache, the real work of computing the
176
- # attribute's value is done in the function above (__getattr_helper)
165
+ # This function only computes the attribute's value once, then adds it to the instance attributes
166
+ # (in __dict__), so the next time it is returned directly
177
167
def __getattr__ (self , attrname ):
178
- if not self .attr_cache .has_key (attrname ):
179
- self .attr_cache [attrname ] = self .__getattr_helper (attrname )
180
- return self .attr_cache [attrname ]
168
+ v = self .__getattr_helper (attrname )
169
+ self .__dict__ [attrname ] = v
170
+ return v
171
+
172
+ # Add one or more new target(s) represented as a Python dictionary in 'new_targets'
173
+ # It it an error to add a target with a name that exists in "targets.json"
174
+ # However, it is OK to add a target that was previously added via "add_py_targets"
175
+ # (this makes testing easier without changing the regular semantics)
176
+ @staticmethod
177
+ def add_py_targets (new_targets ):
178
+ crt_data = Target .get_json_target_data ()
179
+ # First add all elemnts to the internal dictionary
180
+ for tk , tv in new_targets .items ():
181
+ if crt_data .has_key (tk ) and (not tk in Target .__py_targets ):
182
+ raise Exception ("Attempt to add target '%s' that already exists" % tk )
183
+ crt_data [tk ] = tv
184
+ Target .__py_targets .add (tk )
185
+ # Then create the new instances and update global variables if needed
186
+ for tk , tv in new_targets .items ():
187
+ # Is the target already created?
188
+ old_target = Target .__target_map .get (tk , None )
189
+ # Instantiate this target. If it is public, update the data in
190
+ # in TARGETS, TARGET_MAP, TARGET_NAMES
191
+ new_target = Target (tk )
192
+ if tv .get ("public" , True ):
193
+ if old_target : # remove the old target from TARGETS and TARGET_NAMES
194
+ TARGETS .remove (old_target )
195
+ TARGET_NAMES .remove (tk )
196
+ # Add the new target
197
+ TARGETS .append (new_target )
198
+ TARGET_MAP [tk ] = new_target
199
+ TARGET_NAMES .append (tk )
200
+ # Update the target cache
201
+ Target .__target_map [tk ] = new_target
202
+
203
+ # Return the target instance starting from the target name
204
+ @staticmethod
205
+ def get_target (name ):
206
+ if not Target .__target_map .has_key (name ):
207
+ Target .__target_map [name ] = Target (name )
208
+ return Target .__target_map [name ]
181
209
182
210
def __init__ (self , name ):
183
211
self .name = name
184
212
185
213
# Compute resolution order once (it will be used later in __getattr__)
186
214
self .resolution_order = self .__get_resolution_order (self .name , [])
187
-
188
- # Attribute cache: once an attribute's value is computed, don't compute it again
189
- self .attr_cache = {}
215
+ # Create also a list with only the names of the targets in the resolution order
216
+ self .resolution_order_names = [t [0 ] for t in self .resolution_order ]
190
217
191
218
def program_cycle_s (self ):
192
219
try :
@@ -195,7 +222,12 @@ def program_cycle_s(self):
195
222
return 4 if self .is_disk_virtual else 1.5
196
223
197
224
def get_labels (self ):
198
- return [self .name ] + CORE_LABELS [self .core ] + self .extra_labels
225
+ labels = [self .name ] + CORE_LABELS [self .core ] + self .extra_labels
226
+ # Automatically define UVISOR_UNSUPPORTED if the target doesn't specifically
227
+ # define UVISOR_SUPPORTED
228
+ if not "UVISOR_SUPPORTED" in labels :
229
+ labels .append ("UVISOR_UNSUPPORTED" )
230
+ return labels
199
231
200
232
# For now, this function only allows "post binary" hooks (hooks that are executed after
201
233
# the binary image is extracted from the executable file)
@@ -364,7 +396,7 @@ def binary_hook(t_self, resources, elf, binf):
364
396
########################################################################################################################
365
397
366
398
# Instantiate all public targets
367
- TARGETS = [Target (name ) for name , value in Target .get_json_target_data ().items () if value .get ("public" , True )]
399
+ TARGETS = [Target . get_target (name ) for name , value in Target .get_json_target_data ().items () if value .get ("public" , True )]
368
400
369
401
# Map each target name to its unique instance
370
402
TARGET_MAP = dict ([(t .name , t ) for t in TARGETS ])
0 commit comments