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

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

Issue 1431343002: Changes semantics of analyzer (Closed) Base URL: https://chromium.googlesource.com/external/gyp@master
Patch Set: feedback Created 5 years, 1 month 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
« no previous file with comments | « no previous file | test/analyzer/gyptest-analyzer.py » ('j') | no next file with comments »
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 test_targets: unqualified target names to search for. Any target in this list
11 that depends upon a file in |files| is output regardless of the type of target
12 or chain of dependencies.
13 additional_compile_targets: Unqualified targets to search for in addition to
14 test_targets. Targets in the combined list that depend upon a file in |files|
15 are not necessarily output. For example, if the target is of type none then the
16 target is not output (but one of the descendants of the target will be).
11 17
12 The following is output: 18 The following is output:
13 error: only supplied if there is an error. 19 error: only supplied if there is an error.
14 build_targets: minimal set of targets that directly depend on the changed 20 compile_targets: minimal set of targets that directly or indirectly (for
15 files and need to be built. The expectation is this set of targets is passed 21 targets of type none) depend on the files in |files| and is one of the
16 into a build step. The returned values are either values in the supplied 22 supplied targets or a target that one of the supplied targets depends on.
17 targets, or have a dependency on one of the supplied targets. 23 The expectation is this set of targets is passed into a build step.
24 test_targets: set of targets from the supplied |test_targets| that either
25 directly or indirectly depend upon a file in |files|. This list if useful
26 if additional processing needs to be done for certain targets after the
27 build, such as running tests.
18 status: outputs one of three values: none of the supplied files were found, 28 status: outputs one of three values: none of the supplied files were found,
19 one of the include files changed so that it should be assumed everything 29 one of the include files changed so that it should be assumed everything
20 changed (in this case targets and build_targets are not output) or at 30 changed (in this case test_targets and compile_targets are not output) or at
21 least one file was found. 31 least one file was found.
22 invalid_targets: list of supplied targets thare were not found. 32 invalid_targets: list of supplied targets that were not found.
23 33
24 Example: 34 Example:
25 Consider a graph like the following: 35 Consider a graph like the following:
26 A D 36 A D
27 / \ 37 / \
28 B C 38 B C
29 A depends upon both B and C, A is of type none and B and C are executables. 39 A depends upon both B and C, A is of type none and B and C are executables.
30 D is an executable, has no dependencies and nothing depends on it. 40 D is an executable, has no dependencies and nothing depends on it.
31 If |targets| = ["A"] and files = ["b.cc", "d.cc"] (B depends upon b.cc and D 41 If |additional_compile_targets| = ["A"], |test_targets| = ["B", "C"] and
32 depends upon d.cc), then the following is output: 42 files = ["b.cc", "d.cc"] (B depends upon b.cc and D depends upon d.cc), then
33 |build_targets| = ["B"] B must built as it depends upon the changed file b.cc 43 the following is output:
44 |compile_targets| = ["B"] B must built as it depends upon the changed file b.cc
34 and the supplied target A depends upon it. A is not output as a build_target 45 and the supplied target A depends upon it. A is not output as a build_target
35 as it is of type none with no rules and actions. 46 as it is of type none with no rules and actions.
47 |test_targets| = ["B"] B directly depends upon the change file b.cc.
36 48
37 Even though the file d.cc, which D depends upon, has changed D is not output 49 Even though the file d.cc, which D depends upon, has changed D is not output
38 as none of the supplied targets (A) depend upon D. 50 as it was not supplied by way of |additional_compile_targets| or |test_targets|.
39 51
40 If the generator flag analyzer_output_path is specified, output is written 52 If the generator flag analyzer_output_path is specified, output is written
41 there. Otherwise output is written to stdout. 53 there. Otherwise output is written to stdout.
54
55 In Gyp the "all" target is shorthand for the root targets in the files passed
56 to gyp. For example, if file "a.gyp" contains targets "a1" and
57 "a2", and file "b.gyp" contains targets "b1" and "b2" and "a2" has a dependency
58 on "b2" and gyp is supplied "a.gyp" then "all" consists of "a1" and "a2".
59 Notice that "b1" and "b2" are not in the "all" target as "b.gyp" was not
60 directly supplied to gyp. OTOH if both "a.gyp" and "b.gyp" are supplied to gyp
61 then the "all" target includes "b1" and "b2".
42 """ 62 """
43 63
44 import gyp.common 64 import gyp.common
45 import gyp.ninja_syntax as ninja_syntax 65 import gyp.ninja_syntax as ninja_syntax
46 import json 66 import json
47 import os 67 import os
48 import posixpath 68 import posixpath
49 import sys 69 import sys
50 70
51 debug = False 71 debug = False
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 self.is_or_has_linked_ancestor = False 238 self.is_or_has_linked_ancestor = False
219 239
220 240
221 class Config(object): 241 class Config(object):
222 """Details what we're looking for 242 """Details what we're looking for
223 files: set of files to search for 243 files: set of files to search for
224 targets: see file description for details.""" 244 targets: see file description for details."""
225 def __init__(self): 245 def __init__(self):
226 self.files = [] 246 self.files = []
227 self.targets = set() 247 self.targets = set()
248 self.additional_compile_target_names = set()
249 self.test_target_names = set()
250 # Needed until recipes are updated.
251 self.deprecated_mode = False
228 252
229 def Init(self, params): 253 def Init(self, params):
230 """Initializes Config. This is a separate method as it raises an exception 254 """Initializes Config. This is a separate method as it raises an exception
231 if there is a parse error.""" 255 if there is a parse error."""
232 generator_flags = params.get('generator_flags', {}) 256 generator_flags = params.get('generator_flags', {})
233 config_path = generator_flags.get('config_path', None) 257 config_path = generator_flags.get('config_path', None)
234 if not config_path: 258 if not config_path:
235 return 259 return
236 try: 260 try:
237 f = open(config_path, 'r') 261 f = open(config_path, 'r')
238 config = json.load(f) 262 config = json.load(f)
239 f.close() 263 f.close()
240 except IOError: 264 except IOError:
241 raise Exception('Unable to open file ' + config_path) 265 raise Exception('Unable to open file ' + config_path)
242 except ValueError as e: 266 except ValueError as e:
243 raise Exception('Unable to parse config file ' + config_path + str(e)) 267 raise Exception('Unable to parse config file ' + config_path + str(e))
244 if not isinstance(config, dict): 268 if not isinstance(config, dict):
245 raise Exception('config_path must be a JSON file containing a dictionary') 269 raise Exception('config_path must be a JSON file containing a dictionary')
246 self.files = config.get('files', []) 270 self.files = config.get('files', [])
247 self.targets = set(config.get('targets', [])) 271 if config.get('targets'):
272 self.targets = set(config.get('targets'))
273 self.deprecated_mode = True
274 else:
275 self.additional_compile_target_names = set(
276 config.get('additional_compile_targets', []))
277 self.test_target_names = set(config.get('test_targets', []))
248 278
249 279
250 def _WasBuildFileModified(build_file, data, files, toplevel_dir): 280 def _WasBuildFileModified(build_file, data, files, toplevel_dir):
251 """Returns true if the build file |build_file| is either in |files| or 281 """Returns true if the build file |build_file| is either in |files| or
252 one of the files included by |build_file| is in |files|. |toplevel_dir| is 282 one of the files included by |build_file| is in |files|. |toplevel_dir| is
253 the root of the source tree.""" 283 the root of the source tree."""
254 if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files: 284 if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
255 if debug: 285 if debug:
256 print 'gyp file modified', build_file 286 print 'gyp file modified', build_file
257 return True 287 return True
(...skipping 30 matching lines...) Expand all
288 # If a 'none' target has rules or actions we assume it requires a build. 318 # If a 'none' target has rules or actions we assume it requires a build.
289 return bool(target_dict['type'] != 'none' or 319 return bool(target_dict['type'] != 'none' or
290 target_dict.get('actions') or target_dict.get('rules')) 320 target_dict.get('actions') or target_dict.get('rules'))
291 321
292 322
293 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, 323 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
294 build_files): 324 build_files):
295 """Returns a tuple of the following: 325 """Returns a tuple of the following:
296 . A dictionary mapping from fully qualified name to Target. 326 . A dictionary mapping from fully qualified name to Target.
297 . A list of the targets that have a source file in |files|. 327 . A list of the targets that have a source file in |files|.
298 . Set of root Targets reachable from the the files |build_files|. This 328 . Targets that constitute the 'all' target. See description at top of file
299 is the set of targets built by the 'all' target. 329 for details on the 'all' target.
300 This sets the |match_status| of the targets that contain any of the source 330 This sets the |match_status| of the targets that contain any of the source
301 files in |files| to MATCH_STATUS_MATCHES. 331 files in |files| to MATCH_STATUS_MATCHES.
302 |toplevel_dir| is the root of the source tree.""" 332 |toplevel_dir| is the root of the source tree."""
303 # Maps from target name to Target. 333 # Maps from target name to Target.
304 targets = {} 334 name_to_target = {}
305 335
306 # Targets that matched. 336 # Targets that matched.
307 matching_targets = [] 337 matching_targets = []
308 338
309 # Queue of targets to visit. 339 # Queue of targets to visit.
310 targets_to_visit = target_list[:] 340 targets_to_visit = target_list[:]
311 341
312 # Maps from build file to a boolean indicating whether the build file is in 342 # Maps from build file to a boolean indicating whether the build file is in
313 # |files|. 343 # |files|.
314 build_file_in_files = {} 344 build_file_in_files = {}
315 345
316 # Root targets across all files. 346 # Root targets across all files.
317 roots = set() 347 roots = set()
318 348
319 # Set of Targets in |build_files|. 349 # Set of Targets in |build_files|.
320 build_file_targets = set() 350 build_file_targets = set()
321 351
322 while len(targets_to_visit) > 0: 352 while len(targets_to_visit) > 0:
323 target_name = targets_to_visit.pop() 353 target_name = targets_to_visit.pop()
324 created_target, target = _GetOrCreateTargetByName(targets, target_name) 354 created_target, target = _GetOrCreateTargetByName(name_to_target,
355 target_name)
325 if created_target: 356 if created_target:
326 roots.add(target) 357 roots.add(target)
327 elif target.visited: 358 elif target.visited:
328 continue 359 continue
329 360
330 target.visited = True 361 target.visited = True
331 target.requires_build = _DoesTargetTypeRequireBuild( 362 target.requires_build = _DoesTargetTypeRequireBuild(
332 target_dicts[target_name]) 363 target_dicts[target_name])
333 target_type = target_dicts[target_name]['type'] 364 target_type = target_dicts[target_name]['type']
334 target.is_executable = target_type == 'executable' 365 target.is_executable = target_type == 'executable'
(...skipping 22 matching lines...) Expand all
357 if _ToGypPath(os.path.normpath(source)) in files: 388 if _ToGypPath(os.path.normpath(source)) in files:
358 print 'target', target_name, 'matches', source 389 print 'target', target_name, 'matches', source
359 target.match_status = MATCH_STATUS_MATCHES 390 target.match_status = MATCH_STATUS_MATCHES
360 matching_targets.append(target) 391 matching_targets.append(target)
361 break 392 break
362 393
363 # Add dependencies to visit as well as updating back pointers for deps. 394 # Add dependencies to visit as well as updating back pointers for deps.
364 for dep in target_dicts[target_name].get('dependencies', []): 395 for dep in target_dicts[target_name].get('dependencies', []):
365 targets_to_visit.append(dep) 396 targets_to_visit.append(dep)
366 397
367 created_dep_target, dep_target = _GetOrCreateTargetByName(targets, dep) 398 created_dep_target, dep_target = _GetOrCreateTargetByName(name_to_target,
399 dep)
368 if not created_dep_target: 400 if not created_dep_target:
369 roots.discard(dep_target) 401 roots.discard(dep_target)
370 402
371 target.deps.add(dep_target) 403 target.deps.add(dep_target)
372 dep_target.back_deps.add(target) 404 dep_target.back_deps.add(target)
373 405
374 return targets, matching_targets, roots & build_file_targets 406 return name_to_target, matching_targets, roots & build_file_targets
375 407
376 408
377 def _GetUnqualifiedToTargetMapping(all_targets, to_find): 409 def _GetUnqualifiedToTargetMapping(all_targets, to_find):
378 """Returns a mapping (dictionary) from unqualified name to Target for all the 410 """Returns a tuple of the following:
379 Targets in |to_find|.""" 411 . mapping (dictionary) from unqualified name to Target for all the
412 Targets in |to_find|.
413 . any target names not found. If this is empty all targets were found."""
380 result = {} 414 result = {}
381 if not to_find: 415 if not to_find:
382 return result 416 return {}, []
383 to_find = set(to_find) 417 to_find = set(to_find)
384 for target_name in all_targets.keys(): 418 for target_name in all_targets.keys():
385 extracted = gyp.common.ParseQualifiedTarget(target_name) 419 extracted = gyp.common.ParseQualifiedTarget(target_name)
386 if len(extracted) > 1 and extracted[1] in to_find: 420 if len(extracted) > 1 and extracted[1] in to_find:
387 to_find.remove(extracted[1]) 421 to_find.remove(extracted[1])
388 result[extracted[1]] = all_targets[target_name] 422 result[extracted[1]] = all_targets[target_name]
389 if not to_find: 423 if not to_find:
390 return result 424 return result, []
391 return result 425 return result, [x for x in to_find]
392 426
393 427
394 def _AddBuildTargets(target, roots, result): 428 def _AddBuildTargetsDeprecated(target, roots, result):
395 """Recurses through all targets that depend on |target|, adding all targets 429 """Recurses through all targets that depend on |target|, adding all targets
396 that need to be built (and are in |roots|) to |result|. 430 that need to be built (and are in |roots|) to |result|.
397 roots: set of root targets. 431 roots: set of root targets.
398 result: targets that need to be built are added here.""" 432 result: targets that need to be built are added here."""
399 if target.visited: 433 if target.visited:
400 return 434 return
401 435
402 target.visited = True 436 target.visited = True
403 target.in_roots = target in roots 437 target.in_roots = target in roots
404 438
405 for back_dep_target in target.back_deps: 439 for back_dep_target in target.back_deps:
406 _AddBuildTargets(back_dep_target, roots, result) 440 _AddBuildTargetsDeprecated(back_dep_target, roots, result)
407 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets 441 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
408 target.in_roots |= back_dep_target.in_roots 442 target.in_roots |= back_dep_target.in_roots
409 target.is_or_has_linked_ancestor |= ( 443 target.is_or_has_linked_ancestor |= (
410 back_dep_target.is_or_has_linked_ancestor) 444 back_dep_target.is_or_has_linked_ancestor)
411 445
412 # Always add 'executable' targets. Even though they may be built by other 446 # Always add 'executable' targets. Even though they may be built by other
413 # targets that depend upon them it makes detection of what is going to be 447 # targets that depend upon them it makes detection of what is going to be
414 # built easier. 448 # built easier.
415 # And always add static_libraries that have no dependencies on them from 449 # And always add static_libraries that have no dependencies on them from
416 # linkables. This is necessary as the other dependencies on them may be 450 # linkables. This is necessary as the other dependencies on them may be
417 # static libraries themselves, which are not compile time dependencies. 451 # static libraries themselves, which are not compile time dependencies.
418 if target.in_roots and \ 452 if target.in_roots and \
419 (target.is_executable or 453 (target.is_executable or
420 (not target.added_to_compile_targets and target.requires_build) or 454 (not target.added_to_compile_targets and target.requires_build) or
421 (target.is_static_library and not target.is_or_has_linked_ancestor)): 455 (target.is_static_library and not target.is_or_has_linked_ancestor)):
422 print '\t\tadding to build targets', target.name, 'executable', \ 456 print '\t\tadding to build targets', target.name, 'executable', \
423 target.is_executable, 'added_to_compile_targets', \ 457 target.is_executable, 'added_to_compile_targets', \
424 target.added_to_compile_targets, 'requires_build', \ 458 target.added_to_compile_targets, 'requires_build', \
425 target.requires_build, 'is_static_library', \ 459 target.requires_build, 'is_static_library', \
426 target.is_static_library, 'is_or_has_linked_ancestor', \ 460 target.is_static_library, 'is_or_has_linked_ancestor', \
427 target.is_or_has_linked_ancestor 461 target.is_or_has_linked_ancestor
428 result.add(target) 462 result.add(target)
429 target.added_to_compile_targets = True 463 target.added_to_compile_targets = True
430 464
431 465
432 def _GetBuildTargets(matching_targets, roots): 466 def _GetBuildTargetsDeprecated(matching_targets, roots):
433 """Returns the set of Targets that require a build. 467 """Returns the set of Targets that require a build.
434 matching_targets: targets that changed and need to be built. 468 matching_targets: targets that changed and need to be built.
435 roots: set of root targets in the build files to search from.""" 469 roots: set of root targets in the build files to search from."""
436 result = set() 470 result = set()
437 for target in matching_targets: 471 for target in matching_targets:
438 print '\tfinding build targets for match', target.name 472 print '\tfinding build targets for match', target.name
439 _AddBuildTargets(target, roots, result) 473 _AddBuildTargetsDeprecated(target, roots, result)
440 return result 474 return result
441 475
442 476
477 def _DoesTargetDependOnMatchingTargets(target):
478 """Returns true if |target| or any of its dependencies is one of the
479 targets containing the files supplied as input to analyzer. This updates
480 |matches| of the Targets as it recurses.
481 target: the Target to look for."""
482 if target.match_status == MATCH_STATUS_DOESNT_MATCH:
483 return False
484 if target.match_status == MATCH_STATUS_MATCHES or \
485 target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
486 return True
487 for dep in target.deps:
488 if _DoesTargetDependOnMatchingTargets(dep):
489 target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
490 print '\t', target.name, 'matches by dep', dep.name
491 return True
492 target.match_status = MATCH_STATUS_DOESNT_MATCH
493 return False
494
495
496 def _GetTargetsDependingOnMatchingTargets(possible_targets):
497 """Returns the list of Targets in |possible_targets| that depend (either
498 directly on indirectly) on at least one of the targets containing the files
499 supplied as input to analyzer.
500 possible_targets: targets to search from."""
501 found = []
502 print 'Targets that matched by dependency:'
503 for target in possible_targets:
504 if _DoesTargetDependOnMatchingTargets(target):
505 found.append(target)
506 return found
507
508
509 def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
510 """Recurses through all targets that depend on |target|, adding all targets
511 that need to be built (and are in |roots|) to |result|.
512 roots: set of root targets.
513 add_if_no_ancestor: If true and there are no ancestors of |target| then add
514 |target| to |result|. |target| must still be in |roots|.
515 result: targets that need to be built are added here."""
516 if target.visited:
517 return
518
519 target.visited = True
520 target.in_roots = target in roots
521
522 for back_dep_target in target.back_deps:
523 _AddCompileTargets(back_dep_target, roots, False, result)
524 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
525 target.in_roots |= back_dep_target.in_roots
526 target.is_or_has_linked_ancestor |= (
527 back_dep_target.is_or_has_linked_ancestor)
528
529 # Always add 'executable' targets. Even though they may be built by other
530 # targets that depend upon them it makes detection of what is going to be
531 # built easier.
532 # And always add static_libraries that have no dependencies on them from
533 # linkables. This is necessary as the other dependencies on them may be
534 # static libraries themselves, which are not compile time dependencies.
535 if target.in_roots and \
536 (target.is_executable or
537 (not target.added_to_compile_targets and
538 (add_if_no_ancestor or target.requires_build)) or
539 (target.is_static_library and add_if_no_ancestor and
540 not target.is_or_has_linked_ancestor)):
541 print '\t\tadding to compile targets', target.name, 'executable', \
542 target.is_executable, 'added_to_compile_targets', \
543 target.added_to_compile_targets, 'add_if_no_ancestor', \
544 add_if_no_ancestor, 'requires_build', target.requires_build, \
545 'is_static_library', target.is_static_library, \
546 'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor
547 result.add(target)
548 target.added_to_compile_targets = True
549
550
551 def _GetCompileTargets(matching_targets, supplied_targets):
552 """Returns the set of Targets that require a build.
553 matching_targets: targets that changed and need to be built.
554 supplied_targets: set of targets supplied to analyzer to search from."""
555 result = set()
556 for target in matching_targets:
557 print 'finding compile targets for match', target.name
558 _AddCompileTargets(target, supplied_targets, True, result)
559 return result
560
561
443 def _WriteOutput(params, **values): 562 def _WriteOutput(params, **values):
444 """Writes the output, either to stdout or a file is specified.""" 563 """Writes the output, either to stdout or a file is specified."""
445 if 'error' in values: 564 if 'error' in values:
446 print 'Error:', values['error'] 565 print 'Error:', values['error']
447 if 'status' in values: 566 if 'status' in values:
448 print values['status'] 567 print values['status']
449 if 'targets' in values: 568 if 'targets' in values:
450 values['targets'].sort() 569 values['targets'].sort()
451 print 'Supplied targets that depend on changed files:' 570 print 'Supplied targets that depend on changed files:'
452 for target in values['targets']: 571 for target in values['targets']:
453 print '\t', target 572 print '\t', target
454 if 'invalid_targets' in values: 573 if 'invalid_targets' in values:
455 values['invalid_targets'].sort() 574 values['invalid_targets'].sort()
456 print 'The following targets were not found:' 575 print 'The following targets were not found:'
457 for target in values['invalid_targets']: 576 for target in values['invalid_targets']:
458 print '\t', target 577 print '\t', target
459 if 'build_targets' in values: 578 if 'build_targets' in values:
460 values['build_targets'].sort() 579 values['build_targets'].sort()
461 print 'Targets that require a build:' 580 print 'Targets that require a build:'
462 for target in values['build_targets']: 581 for target in values['build_targets']:
463 print '\t', target 582 print '\t', target
583 if 'compile_targets' in values:
584 values['compile_targets'].sort()
585 print 'Targets that need to be built:'
586 for target in values['compile_targets']:
587 print '\t', target
588 if 'test_targets' in values:
589 values['test_targets'].sort()
590 print 'Test targets:'
591 for target in values['test_targets']:
592 print '\t', target
464 593
465 output_path = params.get('generator_flags', {}).get( 594 output_path = params.get('generator_flags', {}).get(
466 'analyzer_output_path', None) 595 'analyzer_output_path', None)
467 if not output_path: 596 if not output_path:
468 print json.dumps(values) 597 print json.dumps(values)
469 return 598 return
470 try: 599 try:
471 f = open(output_path, 'w') 600 f = open(output_path, 'w')
472 f.write(json.dumps(values) + '\n') 601 f.write(json.dumps(values) + '\n')
473 f.close() 602 f.close()
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 'generator_additional_path_sections', []) 642 'generator_additional_path_sections', [])
514 643
515 gyp.msvs_emulation.CalculateCommonVariables(default_variables, params) 644 gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
516 else: 645 else:
517 operating_system = flavor 646 operating_system = flavor
518 if flavor == 'android': 647 if flavor == 'android':
519 operating_system = 'linux' # Keep this legacy behavior for now. 648 operating_system = 'linux' # Keep this legacy behavior for now.
520 default_variables.setdefault('OS', operating_system) 649 default_variables.setdefault('OS', operating_system)
521 650
522 651
652 def _GenerateOutputDeprecated(target_list, target_dicts, data, params, config):
653 """Old deprecated behavior, will be nuked shortly."""
654 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
655
656 if _WasGypIncludeFileModified(params, config.files):
657 result_dict = { 'status': all_changed_string,
658 'targets': list(config.targets) }
659 _WriteOutput(params, **result_dict)
660 return
661
662 all_targets, matching_targets, root_targets = _GenerateTargets(
663 data, target_list, target_dicts, toplevel_dir, frozenset(config.files),
664 params['build_files'])
665
666 unqualified_mapping, invalid_targets = _GetUnqualifiedToTargetMapping(
667 all_targets, config.targets)
668
669 if matching_targets:
670 search_targets = _LookupTargets(config.targets, unqualified_mapping)
671 print 'supplied targets'
672 for target in config.targets:
673 print '\t', target
674 print 'expanded supplied targets'
675 for target in search_targets:
676 print '\t', target.name
677 # Reset the visited status for _GetBuildTargets.
678 for target in all_targets.itervalues():
679 target.visited = False
680 build_targets = _GetBuildTargetsDeprecated(matching_targets, search_targets)
681 build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
682 for target in build_targets]
683 else:
684 build_targets = []
685
686 result_dict = { 'targets': build_targets,
687 'status': found_dependency_string if matching_targets else
688 no_dependency_string,
689 'build_targets': build_targets}
690 if invalid_targets:
691 result_dict['invalid_targets'] = invalid_targets
692 _WriteOutput(params, **result_dict)
693
694
695 class TargetCalculator(object):
696 """Calculates the matching test_targets and matching compile_targets."""
697 def __init__(self, files, additional_compile_target_names, test_target_names,
698 data, target_list, target_dicts, toplevel_dir, build_files):
699 self._additional_compile_target_names = set(additional_compile_target_names)
700 self._test_target_names = set(test_target_names)
701 self._name_to_target, self._changed_targets, self._root_targets = (
702 _GenerateTargets(data, target_list, target_dicts, toplevel_dir,
703 frozenset(files), build_files))
704 self._unqualified_mapping, self.invalid_targets = (
705 _GetUnqualifiedToTargetMapping(self._name_to_target,
706 self._supplied_target_names_no_all()))
707
708 def _supplied_target_names(self):
709 return self._additional_compile_target_names | self._test_target_names
710
711 def _supplied_target_names_no_all(self):
712 """Returns the supplied test targets without 'all'."""
713 result = self._supplied_target_names();
714 result.discard('all')
715 return result
716
717 def is_build_impacted(self):
718 """Returns true if the supplied files impact the build at all."""
719 return self._changed_targets
720
721 def find_matching_test_target_names(self):
722 """Returns the set of output test targets."""
723 assert self.is_build_impacted()
724 # Find the test targets first. 'all' is special cased to mean all the
725 # root targets. To deal with all the supplied |test_targets| are expanded
726 # to include the root targets during lookup. If any of the root targets
727 # match, we remove it and replace it with 'all'.
728 test_target_names_no_all = set(self._test_target_names)
729 test_target_names_no_all.discard('all')
730 test_targets_no_all = _LookupTargets(test_target_names_no_all,
731 self._unqualified_mapping)
732 test_target_names_contains_all = 'all' in self._test_target_names
733 if test_target_names_contains_all:
734 test_targets = [x for x in (set(test_targets_no_all) |
735 set(self._root_targets))]
736 else:
737 test_targets = [x for x in test_targets_no_all]
738 print 'supplied test_targets'
739 for target_name in self._test_target_names:
740 print '\t', target_name
741 print 'found test_targets'
742 for target in test_targets:
743 print '\t', target.name
744 print 'searching for matching test targets'
745 matching_test_targets = _GetTargetsDependingOnMatchingTargets(test_targets)
746 matching_test_targets_contains_all = (test_target_names_contains_all and
747 set(matching_test_targets) &
748 set(self._root_targets))
749 if matching_test_targets_contains_all:
750 # Remove any of the targets for all that were not explicitly supplied,
751 # 'all' is subsequentely added to the matching names below.
752 matching_test_targets = [x for x in (set(matching_test_targets) &
753 set(test_targets_no_all))]
754 print 'matched test_targets'
755 for target in matching_test_targets:
756 print '\t', target.name
757 matching_target_names = [gyp.common.ParseQualifiedTarget(target.name)[1]
758 for target in matching_test_targets]
759 if matching_test_targets_contains_all:
760 matching_target_names.append('all')
761 print '\tall'
762 return matching_target_names
763
764 def find_matching_compile_target_names(self):
765 """Returns the set of output compile targets."""
766 assert self.is_build_impacted();
767 # Compile targets are found by searching up from changed targets.
768 # Reset the visited status for _GetBuildTargets.
769 for target in self._name_to_target.itervalues():
770 target.visited = False
771
772 supplied_targets = _LookupTargets(self._supplied_target_names_no_all(),
773 self._unqualified_mapping)
774 if 'all' in self._supplied_target_names():
775 supplied_targets = [x for x in (set(supplied_targets) |
776 set(self._root_targets))]
777 print 'Supplied test_targets & compile_targets'
778 for target in supplied_targets:
779 print '\t', target.name
780 print 'Finding compile targets'
781 compile_targets = _GetCompileTargets(self._changed_targets,
782 supplied_targets)
783 return [gyp.common.ParseQualifiedTarget(target.name)[1]
784 for target in compile_targets]
785
786
523 def GenerateOutput(target_list, target_dicts, data, params): 787 def GenerateOutput(target_list, target_dicts, data, params):
524 """Called by gyp as the final stage. Outputs results.""" 788 """Called by gyp as the final stage. Outputs results."""
525 config = Config() 789 config = Config()
526 try: 790 try:
527 config.Init(params) 791 config.Init(params)
792
528 if not config.files: 793 if not config.files:
529 raise Exception('Must specify files to analyze via config_path generator ' 794 raise Exception('Must specify files to analyze via config_path generator '
530 'flag') 795 'flag')
531 796
797 if config.deprecated_mode:
798 _GenerateOutputDeprecated(target_list, target_dicts, data, params,
799 config)
800 return
801
532 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir)) 802 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
533 if debug: 803 if debug:
534 print 'toplevel_dir', toplevel_dir 804 print 'toplevel_dir', toplevel_dir
535 805
536 if _WasGypIncludeFileModified(params, config.files): 806 if _WasGypIncludeFileModified(params, config.files):
537 result_dict = { 'status': all_changed_string, 807 result_dict = { 'status': all_changed_string,
538 'targets': list(config.targets) } 808 'test_targets': list(config.test_target_names),
809 'compile_targets': list(
810 config.additional_compile_target_names) }
Dirk Pranke 2015/11/12 03:29:04 Hm. Should we return the union of test_target_name
sky 2015/11/12 16:22:31 Done.
539 _WriteOutput(params, **result_dict) 811 _WriteOutput(params, **result_dict)
540 return 812 return
541 813
542 all_targets, matching_targets, _ = _GenerateTargets( 814 calculator = TargetCalculator(config.files,
543 data, target_list, target_dicts, toplevel_dir, frozenset(config.files), 815 config.additional_compile_target_names,
544 params['build_files']) 816 config.test_target_names, data,
817 target_list, target_dicts, toplevel_dir,
818 params['build_files'])
819 if not calculator.is_build_impacted():
820 _WriteOutput(params, test_targets=[], compile_targets=[],
821 status=no_dependency_string,
822 invalid_targets=calculator.invalid_targets)
823 return
545 824
546 unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets, 825 test_target_names = calculator.find_matching_test_target_names()
547 config.targets) 826 compile_target_names = calculator.find_matching_compile_target_names()
548 invalid_targets = None 827 found_at_least_one_target = compile_target_names or test_target_names
549 if len(unqualified_mapping) != len(config.targets): 828 result_dict = { 'test_targets': test_target_names,
550 invalid_targets = _NamesNotIn(config.targets, unqualified_mapping) 829 'status': found_dependency_string if
551 830 found_at_least_one_target else no_dependency_string,
552 if matching_targets: 831 'compile_targets': compile_target_names}
553 search_targets = _LookupTargets(config.targets, unqualified_mapping) 832 if calculator.invalid_targets:
554 print 'supplied targets' 833 result_dict['invalid_targets'] = calculator.invalid_targets
555 for target in config.targets:
556 print '\t', target
557 print 'expanded supplied targets'
558 for target in search_targets:
559 print '\t', target.name
560 # Reset the visited status for _GetBuildTargets.
561 for target in all_targets.itervalues():
562 target.visited = False
563 print 'Finding build targets'
564 build_targets = _GetBuildTargets(matching_targets, search_targets)
565 build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
566 for target in build_targets]
567 else:
568 build_targets = []
569
570 # TODO(sky): nuke 'targets'.
571 result_dict = { 'targets': build_targets,
572 'status': found_dependency_string if matching_targets else
573 no_dependency_string,
574 'build_targets': build_targets}
575 if invalid_targets:
576 result_dict['invalid_targets'] = invalid_targets
577 _WriteOutput(params, **result_dict) 834 _WriteOutput(params, **result_dict)
578 835
579 except Exception as e: 836 except Exception as e:
580 _WriteOutput(params, error=str(e)) 837 _WriteOutput(params, error=str(e))
OLDNEW
« no previous file with comments | « no previous file | test/analyzer/gyptest-analyzer.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698