1#!/usr/bin/env python 2# Copyright 2020 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6 7""" 8Finds unreachable gn targets by analysing --ide=json output 9from gn gen. 10 11Usage: 12# Generate json file with targets info, will be located at out/project.json: 13gn gen out --ide=json 14# Lists all targets that are not reachable from //:all or //ci:test_all: 15find_unreachable.py --from //:all --from //ci:test_all --json-file out/project.json 16# Lists targets unreachable from //:all that aren't referenced by any other target: 17find_unreachable.py --from //:all --json-file out/project.json --no-refs 18""" 19 20import argparse 21import json 22import sys 23 24 25def find_reachable_targets(known, graph): 26 reachable = set() 27 to_visit = known 28 while to_visit: 29 next = to_visit.pop() 30 if next in reachable: 31 continue 32 reachable.add(next) 33 to_visit += graph[next]['deps'] 34 return reachable 35 36 37def find_source_targets_from(targets, graph): 38 source_targets = set(targets) 39 for target in targets: 40 source_targets -= set(graph[target]['deps']) 41 return source_targets 42 43 44def main(): 45 parser = argparse.ArgumentParser(description=''' 46 Tool to find unreachable targets. 47 This can be useful to inspect forgotten targets, 48 for example tests or intermediate targets in templates 49 that are no longer needed. 50 ''') 51 parser.add_argument( 52 '--json-file', required=True, 53 help='JSON file from gn gen with --ide=json option') 54 parser.add_argument( 55 '--from', action='append', dest='roots', 56 help='Known "root" targets. Can be multiple. Those targets \ 57 and all their recursive dependencies are considered reachable.\ 58 Examples: //:all, //ci:test_all') 59 parser.add_argument( 60 '--no-refs', action='store_true', 61 help='Show only targets that aren\'t referenced by any other target') 62 cmd_args = parser.parse_args() 63 64 with open(cmd_args.json_file) as json_file: 65 targets_graph = json.load(json_file)['targets'] 66 67 reachable = find_reachable_targets(cmd_args.roots, targets_graph) 68 all = set(targets_graph.keys()) 69 unreachable = all - reachable 70 71 result = find_source_targets_from(unreachable, targets_graph) \ 72 if cmd_args.no_refs else unreachable 73 74 print '\n'.join(sorted(result)) 75 76 77if __name__ == '__main__': 78 sys.exit(main()) 79