]> git.uio.no Git - u/mrichter/AliRoot.git/blame - MUON/checkDeps.py
reducing macro to minimum AliReconstruction functionality, disable QA and TriggerESD...
[u/mrichter/AliRoot.git] / MUON / checkDeps.py
CommitLineData
ea1f7807 1#!/usr/bin/python
2
3import sys
4import os
5import re
6import string
7import getopt
8
9"""
10Given a directory, will look into lib*.pkg files to produce a dependency graph
11 of libraries (and DA if there are some)
ea1f7807 12"""
13
14__author__ = "L. Aphecetche aphecetc_at_in2p3_dot_fr"
48739cf2 15__version__ = "$Id$"
ea1f7807 16
58e0ac49 17notassociatedfiles = {}
18
ea1f7807 19#_______________________________________________________________________________
20def usage():
21 """Describe usage of script
22 """
58e0ac49 23 print "Usage: %s [-h | --help] [-d | --debug] [--da] directory_to_scan" % sys.argv[0]
ea1f7807 24 sys.exit(1)
25
26#_______________________________________________________________________________
58e0ac49 27def append(list,a):
28 """ append a to list, if a not there yet
ea1f7807 29 """
58e0ac49 30 if not a in list:
31 list.append(a)
32
ea1f7807 33
58e0ac49 34#_______________________________________________________________________________
35def getSourceFiles(lib,rootsys,alice_root):
36 """Extract the list of files from a libXXX.pkg file
37 Return a pair of list (sourceFiles,einclude), where einclude
38 is the list of directories needed to be included compile the files.
39 """
40
41 # list of possible .pkg variables
42 pkgkeys = [ "SRCS","EINCLUDE","HDRS","FSRCS","DHDR","CSRCS","CHDRS","ELIBS","EDEFINE","PACKFFLAGS","PACKCXXFLAGS","PACKCFLAGS","PACKSOFLAGS","EXPORT","EHDRS" ]
43
44 keySRCS = pkgkeys[0]
45 keyEINCLUDE = pkgkeys[1]
46
ea1f7807 47 sourcefiles = []
58e0ac49 48 pkg = getLibPackage(lib)
49 einclude = [ "%s/include" % rootsys, "%s/STEER" % alice_root, "%s/%s" % (alice_root,pkg) ]
50
51 dir = os.path.dirname(lib)
52
53 try:
54 f = open(lib)
55 except:
56 print "getSourceFiles : could not open package file %s" % lib
57 return sourcefiles, einclude
58
59 src = False
60
ea1f7807 61 for line in f:
62 l = line.strip()
58e0ac49 63 key = False
64 for k in pkgkeys:
65 if re.search(k,l):
66 key = True
67 if key:
68 if re.search("^%s" % keySRCS,l):
69 src = True
70 else:
71 src = False
72 if re.search("^%s" % keyEINCLUDE,l):
73 l = re.sub(keyEINCLUDE,' ',l)
74 l = re.sub(':',' ',l)
75 l = re.sub('=',' ',l)
76 l = re.sub('\+',' ',l)
77 a = l.split()
78 for i in a:
79 append(einclude,os.path.join(alice_root,i))
80
81 if src:
82 if re.search('Ali',l) and ( re.search('.cxx',l) or re.search('.h',l) ):
83 l = re.sub(keySRCS,' ',l)
84 l = re.sub(':',' ',l)
85 l = re.sub('=',' ',l)
86 l = re.sub('\+',' ',l)
87 l = re.sub("\\\\",' ',l)
88 for i in l.split():
89 append(sourcefiles,os.path.join(dir,i))
90
ea1f7807 91 f.close()
58e0ac49 92 return sourcefiles,einclude
ea1f7807 93
94#_______________________________________________________________________________
58e0ac49 95def getIncludeFiles2(srcfile,alice_root,alice_target,rootsys):
96 """Extract the list of included classes from a class, using the dep
97 files generated in $ALICE_ROOT/package/tgt_ALICE_TARGET/*.d files
98 It is much faster than getIncludeFile, as it reuses the output of
99 previously preprocessing part. Drawback is that it will only work
100 on a compiled version of aliroot...
ea1f7807 101 """
102
103 includes = []
104
58e0ac49 105 package = getFilePackage(srcfile,alice_root)
106 file = re.sub("%s/%s" % (alice_root,package)," ",srcfile).strip()
107 if file[0] == '/':
108 file = file[1:]
109 depfile = "%s/%s/tgt_%s/%s" % (alice_root,package,alice_target,file)
110 depfile = re.sub("\.cxx",".d",depfile)
111
ea1f7807 112 try:
58e0ac49 113 f = open(depfile)
ea1f7807 114 except:
58e0ac49 115 print "Could not open file %s" % depfile
116 print "From",srcfile
ea1f7807 117 return includes
118
119 for line in f:
120 line = line.strip()
58e0ac49 121 i = line.find(":")
122 if i > 0:
123 line = line[i+1:]
124 parts = line.strip().split()
125 for p in parts:
126 if re.search(rootsys,p):
127 p = rootsys
128 else:
129 if p[0] != '/':
130 p = "%s/%s" % (alice_root,p)
131 p = re.sub("%s/include" % alice_root,"%s/STEER" % alice_root,p)
132 append(includes,p)
133
ea1f7807 134 f.close()
58e0ac49 135
136 return includes
137
138#_______________________________________________________________________________
139def getIncludeFiles(srcfile,eincludes,rootsys):
140 """Extract the list of included classes from a class, using :
141 gcc -MM srcfile -MG
142 and then parses the output...
143 This version is quite slow as we're (re-)doing the preprocessing of
144 all the files, but the advantage is that it'll work for a fresh checkout
145 of aliroot, i.e. even before compilation
146 """
147
148 includes = []
149
150# try:
151# f = open(srcfile)
152# except:
153# print "Could not open file %s" % srcfile
154# return includes
155#
156# f.close()
157
158
159 incdir = ""
160
161 for i in eincludes:
162 incdir = "%s -I%s" % (incdir,i)
163
164 cmd = "gcc %s -MM %s -MG" % (incdir,srcfile)
165
166 pre = os.popen(cmd)
167
168 for line in pre:
169 line = line.strip()
170 line = re.sub("\\\\"," ",line)
171 i = line.find(":")
172 if i > 0:
173 line = line[i+1:]
174 line = line.strip()
175 if len(line) > 0 and line != srcfile:
176 if line.find('/') < 0:
177 print "Got no path for file",srcfile," line=",line
178 print "cmd was",cmd
179 if re.search(rootsys,line):
180 line = rootsys
181 append(includes,line)
182 pre.close()
183
ea1f7807 184 return includes
185
186#_______________________________________________________________________________
187def unique(list):
188 """Extract a unique list from list
189 """
190 d = {}
191 for l in list:
192 d[l] = 1
193 return d.keys()
194
195#_______________________________________________________________________________
58e0ac49 196def libshorten(libname):
197 """From libYYYxxx.pkg to YYYxxx
ea1f7807 198 """
ea1f7807 199
58e0ac49 200 s = os.path.basename(libname)
201 if re.search("^lib",s):
202 s = re.sub("^lib","",s)
203 s = re.sub("\.pkg","",s)
204
205 return s
206
ea1f7807 207#_______________________________________________________________________________
58e0ac49 208def fileshorten(file,path):
209 """From path/toto/file to toto/file
ea1f7807 210 """
58e0ac49 211
212 s = re.sub(path," ",file).strip()
213 if s[0] == '/':
214 s = s[1:]
215
ea1f7807 216 return s
58e0ac49 217
218#_______________________________________________________________________________
219def getFilePackage(file,alice_root):
220 """ Get the package in which this file is defined
221 """
222
223 f = re.sub(alice_root,"/",file)
224 while f[0] == '/':
225 f = f[1:]
226 p = f.split('/')
227 return p[0]
228
229#_______________________________________________________________________________
230def getLibPackage(libname):
231 """ Get the package in which this library is defined
232 """
233
234 p = libname.split('/')
235 return p[len(p)-2]
236
237#_______________________________________________________________________________
238def tryRecover(f,inc2src,src2lib,alice_root):
239 """ This method should try to recover the "father" of file f (most probably
240 f is an include file
241 The idea would be to find a cxx file that *directly* includes f, and take
242 the lib of that cxx file as the source of f...
243 Would that work ?
244 Is it needed really ?
245 """
246
247 """
248 print "tryRecover:",f
249
250 if not f.find('\.h'):
251 return ""
252
253 p = getFilePackage(f,alice_root)
254
255 cxxfiles = inc2src.get(f,[])
256
257 for file in cxxfiles:
258 libs = src2lib.get(file,[])
259
260 for l in libs:
261 pl = getLibPackage(l)
262 print f,file,p,pl
263 """
264
265 return ""
ea1f7807 266
267#_______________________________________________________________________________
268#_______________________________________________________________________________
269#_______________________________________________________________________________
270def main():
271
58e0ac49 272 # we cannot work w/o those environement variables, so check them...
273 requiredVariables = [ "ROOTSYS", "ALICE_ROOT", "ALICE_TARGET" ]
274
275 for r in requiredVariables:
276 if not r in os.environ:
277 print "%s is not defined. Cannot work." % r
278 sys.exit(1)
279
280 alice_root = os.environ.get("ALICE_ROOT")
281 rootsys = os.environ.get("ROOTSYS")
282 alice_target = os.environ.get("ALICE_TARGET")
283
284 debug = 0
285 noda = True
ea1f7807 286
287 try:
58e0ac49 288 opts, args = getopt.getopt(sys.argv[1:],"hd",["help", "debug","da"])
ea1f7807 289 except getopt.GetoptError:
290 print "Error in options"
291 usage()
292
293 for o, a in opts:
294 if o in ( "-d","--debug" ):
58e0ac49 295 debug = debug + 1
ea1f7807 296 elif o in ( "-h","--help" ):
297 usage()
298 sys.exit()
58e0ac49 299 elif o == "--da":
300 noda = False
ea1f7807 301 else:
302 assert False, "unhandled option"
303
58e0ac49 304 dir = os.path.abspath(args[0])
305 dirs = []
306
307 for sd in os.listdir(dir):
308 ld = os.path.join(dir,sd)
309 if os.path.isdir(ld) and not os.path.islink(ld):
310 dirs.append(ld)
311
312 dirs.append(dir)
313
314 requestedPackages = [ "MUON", "STEER", "RAW", "ITS", "TRD", "VZERO", "TPC", "PHOS", "TOF", "ZDC", "EMCAL", "HMPID", "SHUTTLE", "ACORDE" ];
ea1f7807 315
316 # find the libraries defined in this directory (looking for libXXXX.pkg files)
317 libraries = []
318
58e0ac49 319 for d in dirs:
320 for f in os.listdir(d):
321 fulllib = os.path.join(d,f)
322 p = getLibPackage(fulllib)
323 if not p in requestedPackages:
324 continue
325 if re.search('^lib',f) and re.search('.pkg$',f):
326 libraries.append(fulllib)
327 if not noda and re.search('da.cxx',f) and not re.search('.svn',f):
328 # append fake libraries for DAs
329 tmp = re.sub("cxx","pkg",f)
330 tmp = "lib%s" % tmp
331 libraries.append(os.path.join(d,tmp))
332
333 # from list of library files (libXXXyyy.pkg), try to find back the list of
334 # "packages" = XXX
335 packages = {}
336
337 for l in libraries:
338 p = getLibPackage(l)
339 packages[p] = []
340
341 for l in libraries:
342 p = getLibPackage(l)
343 packages[p].append(l)
344
345 # src2inc[file.cxx] -> { all included files of that file }
346 src2inc = {}
347
348 # inc2src[file.h] -> { all files that include that one }
349 inc2src = {}
350
351 # lib2src[libXXX.pkg] -> { list of files of that library }
352 lib2src = {}
353
354 # src2lib[file.cxx] -> { list of libraries including that file }
355 src2lib = {}
356
357 # eincludes[libXXX.pkg] -> list of directories to be included to be able to compile the files
358 eincludes = {}
359
360 # lib2inc[libXXX.pkg] -> { list of all included files of that library }
361 lib2inc = {}
362
363 # inc2lib[file.h] -> { list of libraries that include that file }
364 inc2lib = {}
365
366 for p in packages:
367
368 print "Scanning ",p
369
370 for lib in packages[p]:
371
372 lib2inc[lib] = []
373
374 print " ",libshorten(lib),"..."
375
376 if not re.search("da.pkg",lib):
377 # handle the special case of DAs which are not part of libs, really
378 lib2src[lib], eincludes[lib] = getSourceFiles(lib,rootsys,alice_root)
379 else:
380 l = lib
381 l = re.sub("lib","",l)
382 l = re.sub("\.pkg","",l)
383 lib2src[lib] = [ "%s.cxx" % l ]
384 eincludes[lib] = []
385
386 files = []
ea1f7807 387
58e0ac49 388 for src in lib2src[lib]:
389# inc = getIncludeFiles(src,eincludes[lib],rootsys)
390 inc = getIncludeFiles2(src,alice_root,alice_target,rootsys)
391 src2inc[src] = inc
392
393 if not src in src2lib:
394 src2lib[src] = []
395
396 append(src2lib[src],lib)
397
398 for i in inc:
399 if not i in inc2src.keys():
400 inc2src[i] = []
401 append(inc2src[i],src)
402 append(lib2inc[lib],i)
403 if not i in inc2lib.keys():
404 inc2lib[i] = []
405 append(inc2lib[i],lib)
406
407 # some debug at this point...
ea1f7807 408
58e0ac49 409 if debug>=1:
410 for lib in libraries:
411 print lib," is made of "
412 for f in lib2src[lib]:
413 print " ",fileshorten(f,alice_root)
414 print " and includes "
415 for h in lib2inc[lib]:
416 print " ",fileshorten(h,alice_root)
417 if len(eincludes[lib]) > 0:
418 print " and needs the following directories to be compiled "
419 for f in eincludes[lib]:
420 print " ",f
421
422 if debug>=2:
423 print "src2lib relationship"
424 for src,lib in src2lib.items():
425 print fileshorten(src,alice_root),"(",
426 for l in lib:
427 print libshorten(l)," ",
428 print ")"
429
430 # now fills the ultimate array, lib2lib
431 # lib2lib[libXXX.pkg] -> { libYYY.pkg }, list of libraries that lib depends on
ea1f7807 432
58e0ac49 433 lib2lib = {}
ea1f7807 434
435 for lib in libraries:
58e0ac49 436
437 lib2lib[lib] = []
438
439 for hfile in lib2inc[lib]:
440
441 l = "external"
442
443 # start simple : is f contains ROOTSYS, it's ROOT.
444 if re.search(rootsys,hfile):
445 l = "ROOT"
446 else:
447 # not that simple, let's try to find out...
448 cxx = re.sub("\.h",".cxx",hfile)
449 dl = src2lib.get(cxx,[])
450 if len(dl)==1:
451 l = dl[0]
452 elif len(dl)>1:
453 print "Got several libs(",len(dl),"for ",hfile,":"
454 print dl
455
456 if l =="external":
457 notassociatedfiles[hfile] = 1
458 else:
459 append(lib2lib[lib],l)
460
461 ###################### Debug parts...
462 if debug>=1:
ea1f7807 463 for lib in libraries:
58e0ac49 464 print libshorten(lib),"depends on"
465 for f in lib2lib[lib]:
466 print " ",libshorten(f)
467
468 if debug>=2:
469 print
470 print "From source files to include files : "
471 for cxxfile, hfile in src2inc.items():
472 print fileshorten(cxxfile,alice_root)
473 for h in hfile:
474 print " ",fileshorten(h,alice_root)
475
476 if debug>=3:
ea1f7807 477 print
58e0ac49 478 print "From include files to source files : "
479 for i,sources in inc2src.items():
480 print fileshorten(i,alice_root), len(sources)
481 for s in sources:
482 print " ",fileshorten(s,alice_root),"(",
483 for l in src2lib[s]:
484 print libshorten(l),
485 print ")"
486 ######################
487
488 if len(notassociatedfiles) > 0:
489 print "The following files could not be associated with any library..."
490 for f in notassociatedfiles.keys():
491 print f,
492 t=tryRecover(f,inc2src,src2lib,alice_root)
493 print t
ea1f7807 494
58e0ac49 495 # output the dot file that will have to be processed by the dot program
496
ea1f7807 497 ofile = "%s.dot" % os.path.splitext(os.path.basename(sys.argv[0]))[0]
498
499 f = open(ofile,"w")
500
58e0ac49 501 f.write("digraph G {\n")
502 f.write("rankdir=BT;\n")
ea1f7807 503
58e0ac49 504 defaultcolor = "lightblue"
505
506 colors = {}
507
508 colors["MUON"] = "lightyellow"
509 colors["STEER"] = "lightgray"
510
511 for l,d in lib2lib.items():
ea1f7807 512 for dl in d:
58e0ac49 513 f.write("%s->%s;\n" %(libshorten(l),libshorten(dl)))
ea1f7807 514
58e0ac49 515 for p in packages:
516 f.write("subgraph cluster_%s {\n" % p.lower())
517 color = colors.get(p,defaultcolor)
518 f.write("style=filled;\n")
519 f.write("color=%s;\n" % color)
520 f.write('label="%s";\n' % p)
521 for lib in packages[p]:
522 f.write("%s\n" % libshorten(lib))
523 f.write("}\n")
524
525 f.write("}\n")
ea1f7807 526
527 print "You should now do :"
528 print "tred %s > %s.bis" % ( ofile, ofile )
58e0ac49 529 print "dot -Tpng %s.bis -o %s.png" % (ofile,ofile)
ea1f7807 530
531if __name__ == "__main__":
532 main()
533