forked from devsisters/libquic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
getdep.py
146 lines (117 loc) · 4.38 KB
/
getdep.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python
# Dependency Tracker for C++ source tree
# Warning: This program do not understand any preprocessors and macros.
# And this program cannot track the dependendy if the header's name and source's name are different.
# (net_util.h <-\-> net_util_posix.cc)
#
# You may use `exclude` option to leave out unwanted dependency.
from __future__ import print_function
import os
import argparse
class DependencyTree(object):
def __init__(self, root, excludes, debug=False):
self.root = root
self.excludes = set(excludes) if excludes else set()
self.debug = debug
def get_dependencies(self, target):
depmap = {}
wherefrom = {}
q = []
vis = set()
def enq(new, now):
if new not in vis and new not in self.excludes:
vis.add(new)
q.append(new)
depmap[new] = []
wherefrom[new] = now
enq(target, None)
while q:
now = q.pop(0)
if self.debug:
n = now
print(" [ ", end=" ")
while n:
print(n, " => ", end=" ")
n = wherefrom[n]
print(" ]")
if now.endswith(".h") and os.path.exists(self.realpath(now[:-1] + 'cc')):
enq(now[:-1] + 'cc', now)
depmap[now].append(now[:-1] + 'cc')
for dependency in self.parse_cc(now):
enq(dependency, now)
# print now, dependency
depmap[now].append(dependency)
return depmap
def critical_node(self, target):
depmap = self.get_dependencies(target)
N = len(depmap)
M = sum(map(len, depmap.values()))
results = []
origin_nodes = set(depmap.keys())
original_exc = self.excludes
for key in depmap.keys():
if key.endswith(".h"):
self.excludes = original_exc.copy()
self.excludes.add(key)
self.excludes.add(key[:-1] + "cc")
depmap_cut = self.get_dependencies(target)
results.append((N - len(depmap_cut), M - sum(map(len, depmap_cut.values())), key,
origin_nodes - set(depmap_cut.keys())))
results.sort()
print(N, M)
return results
def realpath(self, path):
return os.path.join(self.root, path)
def parse_cc(self, source):
r = []
with open(self.realpath(source), "r") as f:
for line in f:
line = line.strip()
if line.startswith("#include") and '"' in line:
fname = line.split('"')[1]
r.append(fname)
return r
def main():
parser = argparse.ArgumentParser(description="C++ Dependency Tracker for chromium")
parser.add_argument("srcroot", type=str)
parser.add_argument("target", type=str)
parser.add_argument("--exclude", action="append")
parser.add_argument("--dot", action="store_true")
parser.add_argument("--cmd", action="store_true")
parser.add_argument("--debug", action="store_true")
args = parser.parse_args()
tree = DependencyTree(args.srcroot, args.exclude, args.debug)
depmap = tree.get_dependencies(args.target)
if args.dot:
print("""\
digraph "source tree" {
overlap=scale;
size="8,10";
ratio="fill";
fontsize="16";
fontname="Helvetica";
clusterrank="local";
""")
for node in depmap.keys():
if "quic" in node:
node1 = node.rstrip(".cc").rstrip(".h")
print(' "{0}" [label="{0}", style="filled", color="red"]'.format(node1))
vis = set()
for f, deps in depmap.iteritems():
for dep in deps:
f1 = f.rstrip(".cc").rstrip(".h")
dep1 = dep.rstrip(".cc").rstrip(".h")
if (f1, dep1) not in vis:
vis.add((f1, dep1))
print(" \"{}\" -> \"{}\"".format(f1, dep1))
print("}")
if args.cmd:
dirs = set()
for node in depmap.keys():
dirpath = os.path.join("src", os.path.dirname(node))
if dirpath not in dirs:
print("mkdir -p {}".format(dirpath))
dirs.add(dirpath)
print("cp {} src/{}".format(tree.realpath(node), node))
if __name__ == "__main__":
main()