Give it a slightly bigger chance to work for non-MUON libs as well
[u/mrichter/AliRoot.git] / MUON / checkDeps.py
1 #!/usr/bin/python
2
3 import sys
4 import os
5 import re
6 import string
7 import getopt
8
9 """
10 Given a directory, will look into lib*.pkg files to produce a dependency graph
11  of libraries (and DA if there are some)
12 """
13
14 __author__ = "L. Aphecetche aphecetc_at_in2p3_dot_fr"
15 __version__ = "$Id$"
16
17 #_______________________________________________________________________________
18 def usage():
19   """Describe usage of script
20   """
21   print "Usage: %s [-h | --help] [-d | --debug] [--noda] directory_to_scan" % sys.argv[0]
22   sys.exit(1)
23   
24 #_______________________________________________________________________________
25 def getSourceFiles(lib):
26   """Extract the list of classes from a libXXX.pkg file
27   """
28
29   f = open(lib)
30   sourcefiles = []
31   for line in f:
32     l = line.strip()
33     if re.search('Ali',l) and re.search('.cxx',l):
34       l = re.sub('SRCS',' ',l)
35       l = re.sub(':=',' ',l)
36       l = re.sub('=',' ',l)
37       l = re.sub("\\\\",' ',l)
38       l = re.sub(".cxx",' ',l)
39       for i in l.split():
40         sourcefiles.append(i)
41   f.close()
42   return sourcefiles
43   
44 #_______________________________________________________________________________
45 def getIncludeFiles(srcfile):
46   """Extract the list of included classes from a class
47   """
48
49   includes = []
50
51   try:
52     f = open("%s.cxx" % srcfile)
53   except:
54     print "Could not open file %s.cxx" % srcfile
55     return includes
56     
57   for line in f:
58     line = line.strip()
59     if re.search("^#",line) and re.search("#include",line) and re.search('Ali',line):
60       line = re.sub("#include",' ',line)
61       i = line.index(".h")
62       line = line[:i]
63       line = re.sub("\"",' ',line)
64       line = line.strip()
65       includes.append(line)
66   f.close()
67   return includes
68   
69 #_______________________________________________________________________________
70 def unique(list):
71   """Extract a unique list from list
72   """
73   d = {}
74   for l in list:
75     d[l] = 1
76   return d.keys()
77   
78 #_______________________________________________________________________________
79 def findLibrary(file,allfiles):
80   """Find in which library a given class is defined
81   """
82   for k,v in allfiles.items():
83     for f in v:
84       a,f = os.path.split(f)
85       if file == f:
86         return k
87   return "external"
88   
89 #_______________________________________________________________________________
90 def shorten(libname):
91   """From libYYYxxx.pkg to YYYxxx
92   """
93   s = libname
94   if re.search("lib",libname):
95     s = re.sub("lib","",s)
96     s = re.sub("\.pkg","",s)
97   return s
98   
99 #_______________________________________________________________________________
100 #_______________________________________________________________________________
101 #_______________________________________________________________________________
102 def main():
103
104   debug = False
105   noda = False
106   
107   try:
108     opts, args = getopt.getopt(sys.argv[1:],"hd",["help", "debug","noda"])
109   except getopt.GetoptError:
110     print "Error in options"
111     usage()
112
113   for o, a in opts:
114     if o in ( "-d","--debug" ):
115       debug = True
116     elif o in ( "-h","--help" ):
117       usage()
118       sys.exit()
119     elif o == "--noda":
120       noda = True
121     else:
122       assert False, "unhandled option"
123
124   dir = args[0]
125   
126   # find the libraries defined in this directory (looking for libXXXX.pkg files)  
127   libraries = []
128   
129   for file in os.listdir(dir):
130     if re.search('^lib',file) and re.search('.pkg$',file):
131       libraries.append(file)
132
133   # append fake libraries for DAs
134   if not noda:
135     libraries.append("libMUONTRKda.pkg")
136     libraries.append("libMUONTRGda.pkg")
137   
138   # srcfiles is a dictionary :
139   # srcfiles[libXXX.pkg] -> { list of classes (inferred from list of .cxx files) }
140   #
141   srcfiles = {}
142   
143   # allfiles is a dictonary :
144   # allfiles[libXXX.pkg] -> { list of all included files of that library }
145   allfiles = {}
146   
147   for lib in libraries:
148     if not re.search("da",lib):
149       # handle the special case of DAs which are not part of libs, really
150       srcfiles[lib] = getSourceFiles(lib)
151     else:
152       l = lib
153       l = re.sub("lib","",l)
154       l = re.sub("\.pkg","",l)
155       srcfiles[lib] = [ l ]
156     files = []
157     for src in srcfiles[lib]:
158       files.extend(getIncludeFiles(src))
159     allfiles[lib] = unique(files)
160   
161   if debug:
162     for lib in libraries:
163       print lib
164       for f in allfiles[lib]:
165         l = findLibrary(f,srcfiles)
166         print "   ",f,"(",l,")"
167       print
168       
169   # deps is a dictionary
170   # deps[libXXX.pkg] -> { list of libraries libXXX.pkg directly depends upon }
171   
172   deps = {}
173   
174   for lib,files in allfiles.items():
175     d = []
176     for f in files:
177       l = findLibrary(f,srcfiles)
178       if l != lib:
179         d.append(l)
180     deps[lib] = unique(d)
181   
182   if debug:
183     for lib in deps:
184       print lib, " depends on "
185       for l in deps[lib]:
186         print "   ",l
187       print
188         
189   ofile = "%s.dot" % os.path.splitext(os.path.basename(sys.argv[0]))[0]
190   
191   f = open(ofile,"w")
192   
193   f.write("digraph G {")
194   f.write("rankdir=BT;")
195
196   for l,d in deps.items():
197     for dl in d:
198       if re.search("MUON",dl):
199         f.write("node [shape=box,style=filled,fillcolor=yellow];")
200       else:
201         f.write("node [shape=ellipse,style=filled,fillcolor=lightgray];")
202       f.write("%s -> %s;\n" %(shorten(l),shorten(dl)))
203       
204   f.write("}")
205     
206   print "You should now do :"
207   print "tred %s > %s.bis" % ( ofile, ofile )
208   print "dot -Tpng %s.bis > %s.png" % (ofile,ofile)
209   
210 if __name__ == "__main__":
211   main()
212