| #!/usr/bin/env python3 |
| # Copyright 2020 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| |
| """ |
| Finds unreachable gn targets by analysing --ide=json output |
| from gn gen. |
| |
| Usage: |
| # Generate json file with targets info, will be located at out/project.json: |
| gn gen out --ide=json |
| # Lists all targets that are not reachable from //:all or //ci:test_all: |
| find_unreachable.py --from //:all --from //ci:test_all --json-file out/project.json |
| # Lists targets unreachable from //:all that aren't referenced by any other target: |
| find_unreachable.py --from //:all --json-file out/project.json --no-refs |
| """ |
| |
| import argparse |
| import json |
| import sys |
| |
| |
| def find_reachable_targets(known, graph): |
| reachable = set() |
| to_visit = known |
| while to_visit: |
| next = to_visit.pop() |
| if next in reachable: |
| continue |
| reachable.add(next) |
| to_visit += graph[next]['deps'] |
| return reachable |
| |
| |
| def find_source_targets_from(targets, graph): |
| source_targets = set(targets) |
| for target in targets: |
| source_targets -= set(graph[target]['deps']) |
| return source_targets |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=''' |
| Tool to find unreachable targets. |
| This can be useful to inspect forgotten targets, |
| for example tests or intermediate targets in templates |
| that are no longer needed. |
| ''') |
| parser.add_argument( |
| '--json-file', required=True, |
| help='JSON file from gn gen with --ide=json option') |
| parser.add_argument( |
| '--from', action='append', dest='roots', |
| help='Known "root" targets. Can be multiple. Those targets \ |
| and all their recursive dependencies are considered reachable.\ |
| Examples: //:all, //ci:test_all') |
| parser.add_argument( |
| '--no-refs', action='store_true', |
| help='Show only targets that aren\'t referenced by any other target') |
| cmd_args = parser.parse_args() |
| |
| with open(cmd_args.json_file) as json_file: |
| targets_graph = json.load(json_file)['targets'] |
| |
| reachable = find_reachable_targets(cmd_args.roots, targets_graph) |
| all = set(targets_graph.keys()) |
| unreachable = all - reachable |
| |
| result = find_source_targets_from(unreachable, targets_graph) \ |
| if cmd_args.no_refs else unreachable |
| |
| print('\n'.join(sorted(result))) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |