Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: pylib/gyp/generator/analyzer.py

Issue 481433003: Makes the analyzer output the set of targets needing a build (Closed) Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: cleanup Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | test/analyzer/gyptest-analyzer.py » ('j') | test/analyzer/gyptest-analyzer.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2014 Google Inc. All rights reserved. 1 # Copyright (c) 2014 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """ 5 """
6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of 6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of
7 the generator flag config_path) the path of a json file that dictates the files 7 the generator flag config_path) the path of a json file that dictates the files
8 and targets to search for. The following keys are supported: 8 and targets to search for. The following keys are supported:
9 files: list of paths (relative) of the files to search for. 9 files: list of paths (relative) of the files to search for.
10 targets: list of targets to search for. The target names are unqualified. 10 targets: list of targets to search for. The target names are unqualified.
11 11
12 The following is output: 12 The following is output:
13 error: only supplied if there is an error. 13 error: only supplied if there is an error.
14 warning: only supplied if there is a warning. 14 warning: only supplied if there is a warning.
15 targets: the set of targets passed in via targets that either directly or 15 targets: the set of targets passed in via targets that either directly or
16 indirectly depend upon the set of paths supplied in files. 16 indirectly depend upon the set of paths supplied in files.
17 status: indicates if any of the supplied files matched at least one target. 17 build_targets: minimal set of targets that directly depend on the changed
18 files and need to be built. The expectation is this set of targets is passed
19 into a build step.
20 status: outputs one of three values: none of the supplied files were found,
21 one of the include files changed so that it should be assumed everything
22 changed (in this case targets and build_targets are not output) or at
23 least one file was found.
18 24
19 If the generator flag analyzer_output_path is specified, output is written 25 If the generator flag analyzer_output_path is specified, output is written
20 there. Otherwise output is written to stdout. 26 there. Otherwise output is written to stdout.
21 """ 27 """
22 28
23 import gyp.common 29 import gyp.common
24 import gyp.ninja_syntax as ninja_syntax 30 import gyp.ninja_syntax as ninja_syntax
25 import json 31 import json
26 import os 32 import os
27 import posixpath 33 import posixpath
28 import sys 34 import sys
29 35
30 debug = False 36 debug = False
31 37
32 found_dependency_string = 'Found dependency' 38 found_dependency_string = 'Found dependency'
33 no_dependency_string = 'No dependencies' 39 no_dependency_string = 'No dependencies'
40 # Status when it should be assumed that everything has changed.
41 all_changed_string = 'Found dependency (all)'
34 42
35 # MatchStatus is used indicate if and how a target depends upon the supplied 43 # MatchStatus is used indicate if and how a target depends upon the supplied
36 # sources. 44 # sources.
37 # The target's sources contain one of the supplied paths. 45 # The target's sources contain one of the supplied paths.
38 MATCH_STATUS_MATCHES = 1 46 MATCH_STATUS_MATCHES = 1
39 # The target has a dependency on another target that contains one of the 47 # The target has a dependency on another target that contains one of the
40 # supplied paths. 48 # supplied paths.
41 MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2 49 MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2
42 # The target's sources weren't in the supplied paths and none of the target's 50 # The target's sources weren't in the supplied paths and none of the target's
43 # dependencies depend upon a target that matched. 51 # dependencies depend upon a target that matched.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 if len(base_path): 144 if len(base_path):
137 base_path += '/' 145 base_path += '/'
138 146
139 if debug: 147 if debug:
140 print 'ExtractSources', target, base_path 148 print 'ExtractSources', target, base_path
141 149
142 results = [] 150 results = []
143 if 'sources' in target_dict: 151 if 'sources' in target_dict:
144 _AddSources(target_dict['sources'], base_path, base_path_components, 152 _AddSources(target_dict['sources'], base_path, base_path_components,
145 results) 153 results)
146 # Include the inputs from any actions. Any changes to these effect the 154 # Include the inputs from any actions. Any changes to these affect the
147 # resulting output. 155 # resulting output.
148 if 'actions' in target_dict: 156 if 'actions' in target_dict:
149 for action in target_dict['actions']: 157 for action in target_dict['actions']:
150 _ExtractSourcesFromAction(action, base_path, base_path_components, 158 _ExtractSourcesFromAction(action, base_path, base_path_components,
151 results) 159 results)
152 if 'rules' in target_dict: 160 if 'rules' in target_dict:
153 for rule in target_dict['rules']: 161 for rule in target_dict['rules']:
154 _ExtractSourcesFromAction(rule, base_path, base_path_components, results) 162 _ExtractSourcesFromAction(rule, base_path, base_path_components, results)
155 163
156 return results 164 return results
157 165
158 166
159 class Target(object): 167 class Target(object):
160 """Holds information about a particular target: 168 """Holds information about a particular target:
161 deps: set of the names of direct dependent targets. 169 deps: set of Targets this Target depends upon. This is not recursive, only the
162 match_staus: one of the MatchStatus values""" 170 direct dependent Targets.
163 def __init__(self): 171 match_status: one of the MatchStatus values.
172 back_deps: set of Targets that have a dependency on this Target.
173 visited: used during iteration to indicate whether we've visited this target.
174 This is used for two iterations, once in building the set of Targets and
175 again in _GetBuildTargets().
176 name: fully qualified name of the target.
177 requires_build: True if the target type is such that it needs to be built.
178 See _DoesTargetTypeRequireBuild for details.
179 added_to_compile_targets: used when determining if the target was added to the
180 set of targets that needs to be built.
181 in_roots: true if this target is a descendant of one of the root nodes."""
182 def __init__(self, name):
164 self.deps = set() 183 self.deps = set()
165 self.match_status = MATCH_STATUS_TBD 184 self.match_status = MATCH_STATUS_TBD
185 self.back_deps = set()
186 self.name = name
187 # TODO(sky): I don't like hanging this off Target. This state is specific
188 # to certain functions and should be isolated there.
189 self.visited = False
190 self.requires_build = False
191 self.added_to_compile_targets = False
192 self.in_roots = False
166 193
167 194
168 class Config(object): 195 class Config(object):
169 """Details what we're looking for 196 """Details what we're looking for
170 files: set of files to search for 197 files: set of files to search for
171 targets: see file description for details""" 198 targets: see file description for details."""
172 def __init__(self): 199 def __init__(self):
173 self.files = [] 200 self.files = []
174 self.targets = [] 201 self.targets = set()
175 202
176 def Init(self, params): 203 def Init(self, params):
177 """Initializes Config. This is a separate method as it raises an exception 204 """Initializes Config. This is a separate method as it raises an exception
178 if there is a parse error.""" 205 if there is a parse error."""
179 generator_flags = params.get('generator_flags', {}) 206 generator_flags = params.get('generator_flags', {})
180 config_path = generator_flags.get('config_path', None) 207 config_path = generator_flags.get('config_path', None)
181 if not config_path: 208 if not config_path:
182 return 209 return
183 try: 210 try:
184 f = open(config_path, 'r') 211 f = open(config_path, 'r')
185 config = json.load(f) 212 config = json.load(f)
186 f.close() 213 f.close()
187 except IOError: 214 except IOError:
188 raise Exception('Unable to open file ' + config_path) 215 raise Exception('Unable to open file ' + config_path)
189 except ValueError as e: 216 except ValueError as e:
190 raise Exception('Unable to parse config file ' + config_path + str(e)) 217 raise Exception('Unable to parse config file ' + config_path + str(e))
191 if not isinstance(config, dict): 218 if not isinstance(config, dict):
192 raise Exception('config_path must be a JSON file containing a dictionary') 219 raise Exception('config_path must be a JSON file containing a dictionary')
193 self.files = config.get('files', []) 220 self.files = config.get('files', [])
194 # Coalesce duplicates 221 self.targets = set(config.get('targets', []))
195 self.targets = list(set(config.get('targets', [])))
196 222
197 223
198 def _WasBuildFileModified(build_file, data, files): 224 def _WasBuildFileModified(build_file, data, files):
199 """Returns true if the build file |build_file| is either in |files| or 225 """Returns true if the build file |build_file| is either in |files| or
200 one of the files included by |build_file| is in |files|.""" 226 one of the files included by |build_file| is in |files|."""
201 if _ToGypPath(build_file) in files: 227 if _ToGypPath(build_file) in files:
202 if debug: 228 if debug:
203 print 'gyp file modified', build_file 229 print 'gyp file modified', build_file
204 return True 230 return True
205 231
206 # First element of included_files is the file itself. 232 # First element of included_files is the file itself.
207 if len(data[build_file]['included_files']) <= 1: 233 if len(data[build_file]['included_files']) <= 1:
208 return False 234 return False
209 235
210 for include_file in data[build_file]['included_files'][1:]: 236 for include_file in data[build_file]['included_files'][1:]:
211 # |included_files| are relative to the directory of the |build_file|. 237 # |included_files| are relative to the directory of the |build_file|.
212 rel_include_file = \ 238 rel_include_file = \
213 _ToGypPath(gyp.common.UnrelativePath(include_file, build_file)) 239 _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
214 if rel_include_file in files: 240 if rel_include_file in files:
215 if debug: 241 if debug:
216 print 'included gyp file modified, gyp_file=', build_file, \ 242 print 'included gyp file modified, gyp_file=', build_file, \
217 'included file=', rel_include_file 243 'included file=', rel_include_file
218 return True 244 return True
219 return False 245 return False
220 246
221 247
222 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files): 248 def _GetOrCreateTargetByName(targets, target_name):
223 """Generates a dictionary with the key the name of a target and the value a 249 """Creates or returns the Target at targets[target_name]. If there is no
224 Target. |toplevel_dir| is the root of the source tree. If the sources of 250 Target for |target_name| one is created. Returns a tuple of whether a new
225 a target match that of |files|, then |target.matched| is set to True. 251 Target was created and the Target."""
226 This returns a tuple of the dictionary and whether at least one target's 252 if target_name in targets:
227 sources listed one of the paths in |files|.""" 253 return False, targets[target_name]
254 target = Target(target_name)
255 targets[target_name] = target
256 return True, target
257
258
259 def _DoesTargetTypeRequireBuild(target_dict):
260 """Returns true if the target type is such that it needs to be built."""
261 # If a 'none' target has rules or actions we assume it requires a build.
262 return target_dict['type'] != 'none' or \
263 (('actions' in target_dict and target_dict['actions']) or
scottmg 2014/08/18 19:48:16 this can just be target_dict.get('actions') I thin
sky 2014/08/18 20:06:33 Done.
264 ('rules' in target_dict and target_dict['rules']))
scottmg 2014/08/18 19:48:16 similar
sky 2014/08/18 20:06:33 Done.
265
266
267 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
268 build_files):
269 """Returns a tuple of the following:
270 . A dictionary mapping from fully qualified name to Target.
271 . A list of the targets that have a source file in |files|.
272 . Set of root Targets reachable from the the files |build_files|.
273 This sets the |match_status| of the targets that contain any of the source
274 files in |files| to MATCH_STATUS_MATCHES.
275 |toplevel_dir| is the root of the source tree."""
276 # Maps from target name to Target.
228 targets = {} 277 targets = {}
229 278
279 # Targets that matched.
280 matching_targets = []
281
230 # Queue of targets to visit. 282 # Queue of targets to visit.
231 targets_to_visit = target_list[:] 283 targets_to_visit = target_list[:]
232 284
233 matched = False
234
235 # Maps from build file to a boolean indicating whether the build file is in 285 # Maps from build file to a boolean indicating whether the build file is in
236 # |files|. 286 # |files|.
237 build_file_in_files = {} 287 build_file_in_files = {}
238 288
289 # Root targets across all files.
290 roots = set()
291
292 # Set of Targets in |build_files|.
293 build_file_targets = set()
294
239 while len(targets_to_visit) > 0: 295 while len(targets_to_visit) > 0:
240 target_name = targets_to_visit.pop() 296 target_name = targets_to_visit.pop()
241 if target_name in targets: 297 created_target, target = _GetOrCreateTargetByName(targets, target_name)
298 if created_target:
299 roots.add(target)
300 elif target.visited:
242 continue 301 continue
243 302
244 target = Target() 303 target.visited = True
245 targets[target_name] = target 304 target.requires_build = _DoesTargetTypeRequireBuild(
305 target_dicts[target_name])
246 306
247 build_file = gyp.common.ParseQualifiedTarget(target_name)[0] 307 build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
248 if not build_file in build_file_in_files: 308 if not build_file in build_file_in_files:
249 build_file_in_files[build_file] = \ 309 build_file_in_files[build_file] = \
250 _WasBuildFileModified(build_file, data, files) 310 _WasBuildFileModified(build_file, data, files)
251 311
312 if build_file in build_files:
313 build_file_targets.add(target)
314
252 # If a build file (or any of its included files) is modified we assume all 315 # If a build file (or any of its included files) is modified we assume all
253 # targets in the file are modified. 316 # targets in the file are modified.
254 if build_file_in_files[build_file]: 317 if build_file_in_files[build_file]:
318 print 'matching target from modified build file', target_name
255 target.match_status = MATCH_STATUS_MATCHES 319 target.match_status = MATCH_STATUS_MATCHES
256 matched = True 320 matching_targets.append(target)
257 else: 321 else:
258 sources = _ExtractSources(target_name, target_dicts[target_name], 322 sources = _ExtractSources(target_name, target_dicts[target_name],
259 toplevel_dir) 323 toplevel_dir)
260 for source in sources: 324 for source in sources:
261 if source in files: 325 if source in files:
326 print 'target', target_name, 'matches', source
262 target.match_status = MATCH_STATUS_MATCHES 327 target.match_status = MATCH_STATUS_MATCHES
263 matched = True 328 matching_targets.append(target)
264 break 329 break
265 330
331 # Add dependencies to visit as well as updating back pointers for deps.
266 for dep in target_dicts[target_name].get('dependencies', []): 332 for dep in target_dicts[target_name].get('dependencies', []):
267 targets[target_name].deps.add(dep)
268 targets_to_visit.append(dep) 333 targets_to_visit.append(dep)
269 334
270 return targets, matched 335 created_dep_target, dep_target = _GetOrCreateTargetByName(targets, dep)
336 if not created_dep_target:
337 roots.discard(dep_target)
338
339 target.deps.add(dep_target)
340 dep_target.back_deps.add(target)
341
342 return targets, matching_targets, roots & build_file_targets
271 343
272 344
273 def _GetUnqualifiedToQualifiedMapping(all_targets, to_find): 345 def _GetUnqualifiedToTargetMapping(all_targets, to_find):
274 """Returns a mapping (dictionary) from unqualified name to qualified name for 346 """Returns a mapping (dictionary) from unqualified name to Target for all the
275 all the targets in |to_find|.""" 347 Targets in |to_find|."""
276 result = {} 348 result = {}
277 if not to_find: 349 if not to_find:
278 return result 350 return result
279 to_find = set(to_find) 351 to_find = set(to_find)
280 for target_name in all_targets.keys(): 352 for target_name in all_targets.keys():
281 extracted = gyp.common.ParseQualifiedTarget(target_name) 353 extracted = gyp.common.ParseQualifiedTarget(target_name)
282 if len(extracted) > 1 and extracted[1] in to_find: 354 if len(extracted) > 1 and extracted[1] in to_find:
283 to_find.remove(extracted[1]) 355 to_find.remove(extracted[1])
284 result[extracted[1]] = target_name 356 result[extracted[1]] = all_targets[target_name]
285 if not to_find: 357 if not to_find:
286 return result 358 return result
287 return result 359 return result
288 360
289 361
290 def _DoesTargetDependOn(target, all_targets): 362 def _DoesTargetDependOn(target):
291 """Returns true if |target| or any of its dependencies matches the supplied 363 """Returns true if |target| or any of its dependencies matches the supplied
292 set of paths. This updates |matches| of the Targets as it recurses. 364 set of paths. This updates |matches| of the Targets as it recurses.
293 target: the Target to look for. 365 target: the Target to look for."""
294 all_targets: mapping from target name to Target.
295 matching_targets: set of targets looking for."""
296 if target.match_status == MATCH_STATUS_DOESNT_MATCH: 366 if target.match_status == MATCH_STATUS_DOESNT_MATCH:
297 return False 367 return False
298 if target.match_status == MATCH_STATUS_MATCHES or \ 368 if target.match_status == MATCH_STATUS_MATCHES or \
299 target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY: 369 target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
300 return True 370 return True
301 for dep_name in target.deps: 371 for dep in target.deps:
302 dep_target = all_targets[dep_name] 372 if _DoesTargetDependOn(dep):
303 if _DoesTargetDependOn(dep_target, all_targets): 373 target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
304 dep_target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
305 return True 374 return True
306 dep_target.match_status = MATCH_STATUS_DOESNT_MATCH 375 target.match_status = MATCH_STATUS_DOESNT_MATCH
307 return False 376 return False
308 377
309 378
310 def _GetTargetsDependingOn(all_targets, possible_targets): 379 def _GetTargetsDependingOn(possible_targets):
311 """Returns the list of targets in |possible_targets| that depend (either 380 """Returns the list of Targets in |possible_targets| that depend (either
312 directly on indirectly) on the matched files. 381 directly on indirectly) on the matched targets.
313 all_targets: mapping from target name to Target.
314 possible_targets: targets to search from.""" 382 possible_targets: targets to search from."""
315 found = [] 383 found = []
316 for target in possible_targets: 384 for target in possible_targets:
317 if _DoesTargetDependOn(all_targets[target], all_targets): 385 if _DoesTargetDependOn(target):
318 # possible_targets was initially unqualified, keep it unqualified. 386 found.append(target)
319 found.append(gyp.common.ParseQualifiedTarget(target)[1])
320 return found 387 return found
321 388
322 389
390 def _AddBuildTargets(target, roots, add_if_no_ancestor, result):
391 """Recurses through all targets that depend on |target|, adding all targets
392 that need to be built (and are in |roots|) to |result|.
393 roots: set of root targets.
394 add_if_no_ancestor: If true and there are no ancestors of |target| then add
395 |target| to |result|. |target| must still be in |roots|.
396 result: targets that need to be built are added here."""
397 if target.visited:
398 return
399
400 target.visited = True
401 target.in_roots = not target.back_deps and target in roots
402
403 for back_dep_target in target.back_deps:
404 _AddBuildTargets(back_dep_target, roots, False, result)
405 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
406 target.in_roots |= back_dep_target.in_roots
407
408 if not target.added_to_compile_targets and target.in_roots and \
409 (add_if_no_ancestor or target.requires_build):
410 result.add(target)
411 target.added_to_compile_targets = True
412
413
414 def _GetBuildTargets(matching_targets, roots):
415 """Returns the set of Targets that require a build.
416 matching_targets: targets that changed and need to be built.
417 roots: set of root targets in the build files to search from."""
418 result = set()
419 for target in matching_targets:
420 _AddBuildTargets(target, roots, True, result)
421 return result
422
423
323 def _WriteOutput(params, **values): 424 def _WriteOutput(params, **values):
324 """Writes the output, either to stdout or a file is specified.""" 425 """Writes the output, either to stdout or a file is specified."""
426 if 'error' in values:
427 print 'Error:', values['error']
428 if 'status' in values:
429 print values['status']
430 if 'targets' in values:
431 values['targets'].sort()
432 print 'Supplied targets that depend on changed files:'
433 for target in values['targets']:
434 print '\t', target
435 if 'build_targets' in values:
436 values['build_targets'].sort()
437 print 'Targets that require a build:'
438 for target in values['build_targets']:
439 print '\t', target
440
325 output_path = params.get('generator_flags', {}).get( 441 output_path = params.get('generator_flags', {}).get(
326 'analyzer_output_path', None) 442 'analyzer_output_path', None)
327 if not output_path: 443 if not output_path:
328 print json.dumps(values) 444 print json.dumps(values)
329 return 445 return
330 try: 446 try:
331 f = open(output_path, 'w') 447 f = open(output_path, 'w')
332 f.write(json.dumps(values) + '\n') 448 f.write(json.dumps(values) + '\n')
333 f.close() 449 f.close()
334 except IOError as e: 450 except IOError as e:
335 print 'Error writing to output file', output_path, str(e) 451 print 'Error writing to output file', output_path, str(e)
336 452
337 453
454 def _WasIncludeFileModified(params, files):
scottmg 2014/08/18 19:48:16 Could you make this _WasGypiFileModified (or _WasG
sky 2014/08/18 20:06:33 Done.
455 """Returns true if one of the files in |files| is in the set of included
456 files."""
457 if params['options'].includes:
458 for include in params['options'].includes:
459 if _ToGypPath(include) in files:
460 print 'Include file modified, assuming all changed', include
461 return True
462 return False
463
464
465 def _NamesNotIn(names, mapping):
466 """Returns a list of the values in |names| that are not in |mapping|."""
467 return [name for name in names if name not in mapping]
468
469
470 def _LookupTargets(names, mapping):
471 """Returns a list of the mapping[name] for each value in |names| that is in
472 |mapping|."""
473 return [mapping[name] for name in names if name in mapping]
474
475
338 def CalculateVariables(default_variables, params): 476 def CalculateVariables(default_variables, params):
339 """Calculate additional variables for use in the build (called by gyp).""" 477 """Calculate additional variables for use in the build (called by gyp)."""
340 flavor = gyp.common.GetFlavor(params) 478 flavor = gyp.common.GetFlavor(params)
341 if flavor == 'mac': 479 if flavor == 'mac':
342 default_variables.setdefault('OS', 'mac') 480 default_variables.setdefault('OS', 'mac')
343 elif flavor == 'win': 481 elif flavor == 'win':
344 default_variables.setdefault('OS', 'win') 482 default_variables.setdefault('OS', 'win')
345 # Copy additional generator configuration data from VS, which is shared 483 # Copy additional generator configuration data from VS, which is shared
346 # by the Windows Ninja generator. 484 # by the Windows Ninja generator.
347 import gyp.generator.msvs as msvs_generator 485 import gyp.generator.msvs as msvs_generator
(...skipping 16 matching lines...) Expand all
364 try: 502 try:
365 config.Init(params) 503 config.Init(params)
366 if not config.files: 504 if not config.files:
367 raise Exception('Must specify files to analyze via config_path generator ' 505 raise Exception('Must specify files to analyze via config_path generator '
368 'flag') 506 'flag')
369 507
370 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir)) 508 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
371 if debug: 509 if debug:
372 print 'toplevel_dir', toplevel_dir 510 print 'toplevel_dir', toplevel_dir
373 511
374 matched = False 512 if _WasIncludeFileModified(params, config.files):
375 matched_include = False 513 result_dict = { 'status': all_changed_string,
514 'targets': list(config.targets) }
515 _WriteOutput(params, **result_dict)
516 return
376 517
377 # If one of the modified files is an include file then everything is 518 all_targets, matching_targets, roots = _GenerateTargets(
378 # affected. 519 data, target_list, target_dicts, toplevel_dir, frozenset(config.files),
379 if params['options'].includes: 520 params['build_files'])
380 for include in params['options'].includes:
381 if _ToGypPath(include) in config.files:
382 if debug:
383 print 'include path modified', include
384 matched_include = True
385 matched = True
386 break
387
388 if not matched:
389 all_targets, matched = _GenerateTargets(data, target_list, target_dicts,
390 toplevel_dir,
391 frozenset(config.files))
392 521
393 warning = None 522 warning = None
394 if matched_include: 523 unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets,
395 output_targets = config.targets 524 config.targets)
396 elif matched: 525 if len(unqualified_mapping) != len(config.targets):
397 unqualified_mapping = _GetUnqualifiedToQualifiedMapping( 526 not_found = _NamesNotIn(config.targets, unqualified_mapping)
398 all_targets, config.targets) 527 warning = 'Unable to find all targets: ' + str(not_found)
399 if len(unqualified_mapping) != len(config.targets): 528
400 not_found = [] 529 if matching_targets:
401 for target in config.targets: 530 search_targets = _LookupTargets(config.targets, unqualified_mapping)
402 if not target in unqualified_mapping: 531 matched_search_targets = _GetTargetsDependingOn(search_targets)
403 not_found.append(target) 532 # Reset the visited status for _GetBuildTargets.
404 warning = 'Unable to find all targets: ' + str(not_found) 533 for target in all_targets.itervalues():
405 qualified_targets = [] 534 target.visited = False
406 for target in config.targets: 535 build_targets = _GetBuildTargets(matching_targets, roots)
407 if target in unqualified_mapping: 536 matched_search_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
408 qualified_targets.append(unqualified_mapping[target]) 537 for target in matched_search_targets]
409 output_targets = _GetTargetsDependingOn(all_targets, qualified_targets) 538 build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
539 for target in build_targets]
410 else: 540 else:
411 output_targets = [] 541 matched_search_targets = []
542 build_targets = []
412 543
413 result_dict = { 'targets': output_targets, 544 result_dict = { 'targets': matched_search_targets,
414 'status': found_dependency_string if matched else 545 'status': found_dependency_string if matching_targets else
415 no_dependency_string } 546 no_dependency_string,
547 'build_targets': build_targets}
416 if warning: 548 if warning:
417 result_dict['warning'] = warning 549 result_dict['warning'] = warning
418 _WriteOutput(params, **result_dict) 550 _WriteOutput(params, **result_dict)
419 551
420 except Exception as e: 552 except Exception as e:
421 _WriteOutput(params, error=str(e)) 553 _WriteOutput(params, error=str(e))
OLDNEW
« no previous file with comments | « no previous file | test/analyzer/gyptest-analyzer.py » ('j') | test/analyzer/gyptest-analyzer.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698