1#!/usr/bin/env python3 2 3"""List all transitive build rules of a target.""" 4 5import argparse 6import itertools 7import posixpath 8import re 9 10try: 11 import cPickle as pickle # Python 2 12except ImportError: 13 import pickle # Python 3 14 15import ninja 16 17 18def _parse_args(): 19 """Parse the command line arguments.""" 20 21 parser = argparse.ArgumentParser() 22 23 # Ninja input file options 24 parser.add_argument('input_file', help='input ninja file') 25 parser.add_argument('--ninja-deps', help='.ninja_deps file') 26 parser.add_argument('--cwd', help='working directory for ninja') 27 parser.add_argument('--encoding', default='utf-8', 28 help='ninja file encoding') 29 30 # Options 31 parser.add_argument('target', help='build target') 32 33 return parser.parse_args() 34 35 36def collect_build_targets(graph, target): 37 """Collect the transitive build targets.""" 38 39 # Search for the first target 40 build = graph[target] 41 42 # Collect all source files 43 dfs = [build] 44 45 visited = {build} 46 stack = [build] 47 while stack: 48 build = stack.pop() 49 for dep in itertools.chain(build.explicit_ins, build.implicit_ins, 50 build.depfile_implicit_ins): 51 dep = graph.get(dep) 52 if not dep: 53 continue 54 if dep not in visited: 55 visited.add(dep) 56 dfs.append(dep) 57 stack.append(dep) 58 59 return dfs 60 61 62def main(): 63 args = _parse_args() 64 65 # Build lookup map 66 manifest = ninja.load_manifest_from_args(args) 67 graph = {} 68 for build in manifest.builds: 69 for path in build.explicit_outs: 70 graph[path] = build 71 for path in build.implicit_outs: 72 graph[path] = build 73 74 # List all transitive targets 75 try: 76 builds = collect_build_targets(graph, args.target) 77 except KeyError: 78 print('error: Failed to find the target {}'.format(arg.target), 79 file=sys.stderr) 80 sys.exit(1) 81 82 # Print all targets 83 for build in builds: 84 print('build') 85 for path in build.explicit_outs: 86 print(' explicit_out:', path) 87 for path in build.implicit_outs: 88 print(' implicit_out:', path) 89 for path in build.explicit_ins: 90 print(' explicit_in:', path) 91 for path in build.implicit_ins: 92 print(' implicit_in:', path) 93 for path in build.prerequisites: 94 print(' prerequisites:', path) 95 for path in build.depfile_implicit_ins: 96 print(' depfile_implicit_in:', path) 97 98 99if __name__ == '__main__': 100 main() 101