meta2deps.py revision 249033
1246149Ssjg#!/usr/bin/env python 2246149Ssjg 3246149Ssjg""" 4246149SsjgThis script parses each "meta" file and extracts the 5246149Ssjginformation needed to deduce build and src dependencies. 6246149Ssjg 7246149SsjgIt works much the same as the original shell script, but is 8246149Ssjg*much* more efficient. 9246149Ssjg 10246149SsjgThe parsing work is handled by the class MetaFile. 11246149SsjgWe only pay attention to a subset of the information in the 12246149Ssjg"meta" files. Specifically: 13246149Ssjg 14246149Ssjg'CWD' to initialize our notion. 15246149Ssjg 16246149Ssjg'C' to track chdir(2) on a per process basis 17246149Ssjg 18246149Ssjg'R' files read are what we really care about. 19246149Ssjg directories read, provide a clue to resolving 20246149Ssjg subsequent relative paths. That is if we cannot find 21246149Ssjg them relative to 'cwd', we check relative to the last 22246149Ssjg dir read. 23246149Ssjg 24246149Ssjg'W' files opened for write or read-write, 25246149Ssjg for filemon V3 and earlier. 26246149Ssjg 27246149Ssjg'E' files executed. 28246149Ssjg 29246149Ssjg'L' files linked 30246149Ssjg 31246149Ssjg'V' the filemon version, this record is used as a clue 32246149Ssjg that we have reached the interesting bit. 33246149Ssjg 34246149Ssjg""" 35246149Ssjg 36246149Ssjg""" 37246149SsjgRCSid: 38249033Ssjg $Id: meta2deps.py,v 1.12 2013/03/31 22:31:59 sjg Exp $ 39246149Ssjg 40249033Ssjg Copyright (c) 2011-2013, Juniper Networks, Inc. 41249033Ssjg All rights reserved. 42246149Ssjg 43246149Ssjg Redistribution and use in source and binary forms, with or without 44246149Ssjg modification, are permitted provided that the following conditions 45246149Ssjg are met: 46246149Ssjg 1. Redistributions of source code must retain the above copyright 47246149Ssjg notice, this list of conditions and the following disclaimer. 48246149Ssjg 2. Redistributions in binary form must reproduce the above copyright 49246149Ssjg notice, this list of conditions and the following disclaimer in the 50246149Ssjg documentation and/or other materials provided with the distribution. 51246149Ssjg 52246149Ssjg THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53246149Ssjg "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54246149Ssjg LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55246149Ssjg A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56246149Ssjg OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57246149Ssjg SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 58246149Ssjg LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59246149Ssjg DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60246149Ssjg THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61246149Ssjg (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62246149Ssjg OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63246149Ssjg 64246149Ssjg""" 65246149Ssjg 66246149Ssjgimport os, re, sys 67246149Ssjg 68246149Ssjgdef getv(dict, key, d=None): 69246149Ssjg """Lookup key in dict and return value or the supplied default.""" 70246149Ssjg if key in dict: 71246149Ssjg return dict[key] 72246149Ssjg return d 73246149Ssjg 74246149Ssjgdef resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr): 75246149Ssjg """ 76246149Ssjg Return an absolute path, resolving via cwd or last_dir if needed. 77246149Ssjg """ 78246149Ssjg if path.endswith('/.'): 79246149Ssjg path = path[0:-2] 80246149Ssjg if path[0] == '/': 81246149Ssjg return path 82246149Ssjg if path == '.': 83246149Ssjg return cwd 84246149Ssjg if path.startswith('./'): 85246149Ssjg return cwd + path[1:] 86246149Ssjg if last_dir == cwd: 87246149Ssjg last_dir = None 88246149Ssjg for d in [last_dir, cwd]: 89246149Ssjg if not d: 90246149Ssjg continue 91246149Ssjg p = '/'.join([d,path]) 92246149Ssjg if debug > 2: 93246149Ssjg print >> debug_out, "looking for:", p, 94246149Ssjg if not os.path.exists(p): 95246149Ssjg if debug > 2: 96246149Ssjg print >> debug_out, "nope" 97246149Ssjg p = None 98246149Ssjg continue 99246149Ssjg if debug > 2: 100246149Ssjg print >> debug_out, "found:", p 101246149Ssjg return p 102246149Ssjg return None 103246149Ssjg 104246149Ssjgdef abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr): 105246149Ssjg """ 106246149Ssjg Return an absolute path, resolving via cwd or last_dir if needed. 107246149Ssjg this gets called a lot, so we try to avoid calling realpath 108246149Ssjg until we know we have something. 109246149Ssjg """ 110246149Ssjg path = resolve(path, cwd, last_dir, debug, debug_out) 111246149Ssjg if path and (path.find('./') > 0 or 112246149Ssjg path.endswith('/..') or 113246149Ssjg os.path.islink(path)): 114246149Ssjg return os.path.realpath(path) 115246149Ssjg return path 116246149Ssjg 117246149Ssjgdef sort_unique(list, cmp=None, key=None, reverse=False): 118246149Ssjg list.sort(cmp, key, reverse) 119246149Ssjg nl = [] 120246149Ssjg le = None 121246149Ssjg for e in list: 122246149Ssjg if e == le: 123246149Ssjg continue 124246149Ssjg nl.append(e) 125246149Ssjg return nl 126246149Ssjg 127246149Ssjgclass MetaFile: 128246149Ssjg """class to parse meta files generated by bmake.""" 129246149Ssjg 130246149Ssjg conf = None 131246149Ssjg dirdep_re = None 132246149Ssjg host_target = None 133246149Ssjg srctops = [] 134246149Ssjg objroots = [] 135246149Ssjg 136246149Ssjg seen = {} 137246149Ssjg obj_deps = [] 138246149Ssjg src_deps = [] 139246149Ssjg file_deps = [] 140246149Ssjg 141246149Ssjg def __init__(self, name, conf={}): 142246149Ssjg """if name is set we will parse it now. 143246149Ssjg conf can have the follwing keys: 144246149Ssjg 145246149Ssjg SRCTOPS list of tops of the src tree(s). 146246149Ssjg 147246149Ssjg CURDIR the src directory 'bmake' was run from. 148246149Ssjg 149246149Ssjg RELDIR the relative path from SRCTOP to CURDIR 150246149Ssjg 151246149Ssjg MACHINE the machine we built for. 152246149Ssjg set to 'none' if we are not cross-building. 153249033Ssjg More specifically if machine cannot be deduced from objdirs. 154246149Ssjg 155246149Ssjg HOST_TARGET 156246149Ssjg when we build for the psuedo machine 'host' 157246149Ssjg the object tree uses HOST_TARGET rather than MACHINE. 158246149Ssjg 159246149Ssjg OBJROOTS a list of the common prefix for all obj dirs it might 160246149Ssjg end in '/' or '-'. 161246149Ssjg 162246149Ssjg DPDEPS names an optional file to which per file dependencies 163246149Ssjg will be appended. 164246149Ssjg For example if 'some/path/foo.h' is read from SRCTOP 165246149Ssjg then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output. 166246149Ssjg This can allow 'bmake' to learn all the dirs within 167246149Ssjg the tree that depend on 'foo.h' 168246149Ssjg 169246149Ssjg debug desired debug level 170246149Ssjg 171246149Ssjg debug_out open file to send debug output to (sys.stderr) 172246149Ssjg 173246149Ssjg """ 174246149Ssjg 175246149Ssjg self.name = name 176246149Ssjg self.debug = getv(conf, 'debug', 0) 177246149Ssjg self.debug_out = getv(conf, 'debug_out', sys.stderr) 178246149Ssjg 179249033Ssjg self.machine = getv(conf, 'MACHINE', '') 180249033Ssjg self.curdir = getv(conf, 'CURDIR') 181249033Ssjg self.reldir = getv(conf, 'RELDIR') 182249033Ssjg self.dpdeps = getv(conf, 'DPDEPS') 183249033Ssjg 184246149Ssjg if not self.conf: 185246149Ssjg # some of the steps below we want to do only once 186246149Ssjg self.conf = conf 187246149Ssjg self.host_target = getv(conf, 'HOST_TARGET') 188246149Ssjg for srctop in getv(conf, 'SRCTOPS', []): 189246149Ssjg if srctop[-1] != '/': 190246149Ssjg srctop += '/' 191246149Ssjg if not srctop in self.srctops: 192246149Ssjg self.srctops.append(srctop) 193246149Ssjg _srctop = os.path.realpath(srctop) 194246149Ssjg if _srctop[-1] != '/': 195246149Ssjg _srctop += '/' 196246149Ssjg if not _srctop in self.srctops: 197246149Ssjg self.srctops.append(_srctop) 198246149Ssjg 199249033Ssjg trim_list = ['/' + self.machine + '/', 200249033Ssjg '/' + self.machine, 201249033Ssjg self.machine + '/', 202249033Ssjg self.machine] 203249033Ssjg 204249033Ssjg if self.machine == 'host': 205249033Ssjg trim_list += ['/' + self.host_target + '/', 206249033Ssjg '/' + self.host_target, 207249033Ssjg self.host_target + '/', 208249033Ssjg self.host_target] 209249033Ssjg 210246149Ssjg for objroot in getv(conf, 'OBJROOTS', []): 211249033Ssjg for e in trim_list: 212249033Ssjg if objroot.endswith(e): 213249033Ssjg # this is not what we want - fix it 214249033Ssjg objroot = objroot[0:-len(e)] 215249033Ssjg if e.endswith('/'): 216249033Ssjg objroot += '/' 217246149Ssjg if not objroot in self.objroots: 218246149Ssjg self.objroots.append(objroot) 219246149Ssjg _objroot = os.path.realpath(objroot) 220246149Ssjg if objroot[-1] == '/': 221246149Ssjg _objroot += '/' 222246149Ssjg if not _objroot in self.objroots: 223246149Ssjg self.objroots.append(_objroot) 224246149Ssjg 225249033Ssjg # we want the longest match 226249033Ssjg self.srctops.sort(reverse=True) 227249033Ssjg self.objroots.sort(reverse=True) 228249033Ssjg 229246149Ssjg if self.debug: 230246149Ssjg print >> self.debug_out, "host_target=", self.host_target 231246149Ssjg print >> self.debug_out, "srctops=", self.srctops 232246149Ssjg print >> self.debug_out, "objroots=", self.objroots 233246149Ssjg 234246149Ssjg self.dirdep_re = re.compile(r'([^/]+)/(.+)') 235246149Ssjg 236246149Ssjg if self.dpdeps and not self.reldir: 237246149Ssjg if self.debug: 238246149Ssjg print >> self.debug_out, "need reldir:", 239246149Ssjg if self.curdir: 240246149Ssjg srctop = self.find_top(self.curdir, self.srctops) 241246149Ssjg if srctop: 242246149Ssjg self.reldir = self.curdir.replace(srctop,'') 243246149Ssjg if self.debug: 244246149Ssjg print >> self.debug_out, self.reldir 245246149Ssjg if not self.reldir: 246246149Ssjg self.dpdeps = None # we cannot do it? 247246149Ssjg 248249033Ssjg self.cwd = os.getcwd() # make sure this is initialized 249249033Ssjg 250246149Ssjg if name: 251246149Ssjg self.parse() 252246149Ssjg 253246149Ssjg def reset(self): 254246149Ssjg """reset state if we are being passed meta files from multiple directories.""" 255246149Ssjg self.seen = {} 256246149Ssjg self.obj_deps = [] 257246149Ssjg self.src_deps = [] 258246149Ssjg self.file_deps = [] 259246149Ssjg 260246149Ssjg def dirdeps(self, sep='\n'): 261246149Ssjg """return DIRDEPS""" 262246149Ssjg return sep.strip() + sep.join(self.obj_deps) 263246149Ssjg 264246149Ssjg def src_dirdeps(self, sep='\n'): 265246149Ssjg """return SRC_DIRDEPS""" 266246149Ssjg return sep.strip() + sep.join(self.src_deps) 267246149Ssjg 268246149Ssjg def file_depends(self, out=None): 269246149Ssjg """Append DPDEPS_${file} += ${RELDIR} 270246149Ssjg for each file we saw, to the output file.""" 271246149Ssjg if not self.reldir: 272246149Ssjg return None 273246149Ssjg for f in sort_unique(self.file_deps): 274246149Ssjg print >> out, 'DPDEPS_%s += %s' % (f, self.reldir) 275246149Ssjg 276246149Ssjg def seenit(self, dir): 277246149Ssjg """rememer that we have seen dir.""" 278246149Ssjg self.seen[dir] = 1 279246149Ssjg 280246149Ssjg def add(self, list, data, clue=''): 281246149Ssjg """add data to list if it isn't already there.""" 282246149Ssjg if data not in list: 283246149Ssjg list.append(data) 284246149Ssjg if self.debug: 285246149Ssjg print >> self.debug_out, "%s: %sAdd: %s" % (self.name, clue, data) 286246149Ssjg 287246149Ssjg def find_top(self, path, list): 288246149Ssjg """the logical tree may be split accross multiple trees""" 289246149Ssjg for top in list: 290246149Ssjg if path.startswith(top): 291246149Ssjg if self.debug > 2: 292246149Ssjg print >> self.debug_out, "found in", top 293246149Ssjg return top 294246149Ssjg return None 295246149Ssjg 296246149Ssjg def find_obj(self, objroot, dir, path, input): 297246149Ssjg """return path within objroot, taking care of .dirdep files""" 298246149Ssjg ddep = None 299246149Ssjg for ddepf in [path + '.dirdep', dir + '/.dirdep']: 300246149Ssjg if not ddep and os.path.exists(ddepf): 301246149Ssjg ddep = open(ddepf, 'rb').readline().strip('# \n') 302246149Ssjg if self.debug > 1: 303246149Ssjg print >> self.debug_out, "found %s: %s\n" % (ddepf, ddep) 304246149Ssjg if ddep.endswith(self.machine): 305246149Ssjg ddep = ddep[0:-(1+len(self.machine))] 306246149Ssjg 307246149Ssjg if not ddep: 308246149Ssjg # no .dirdeps, so remember that we've seen the raw input 309246149Ssjg self.seenit(input) 310246149Ssjg self.seenit(dir) 311246149Ssjg if self.machine == 'none': 312246149Ssjg if dir.startswith(objroot): 313246149Ssjg return dir.replace(objroot,'') 314246149Ssjg return None 315246149Ssjg m = self.dirdep_re.match(dir.replace(objroot,'')) 316246149Ssjg if m: 317246149Ssjg ddep = m.group(2) 318246149Ssjg dmachine = m.group(1) 319246149Ssjg if dmachine != self.machine: 320246149Ssjg if not (self.machine == 'host' and 321246149Ssjg dmachine == self.host_target): 322246149Ssjg if self.debug > 2: 323246149Ssjg print >> self.debug_out, "adding .%s to %s" % (dmachine, ddep) 324246149Ssjg ddep += '.' + dmachine 325246149Ssjg 326246149Ssjg return ddep 327246149Ssjg 328246149Ssjg def parse(self, name=None, file=None): 329246149Ssjg """A meta file looks like: 330246149Ssjg 331246149Ssjg # Meta data file "path" 332246149Ssjg CMD "command-line" 333246149Ssjg CWD "cwd" 334246149Ssjg TARGET "target" 335246149Ssjg -- command output -- 336246149Ssjg -- filemon acquired metadata -- 337246149Ssjg # buildmon version 3 338246149Ssjg V 3 339246149Ssjg C "pid" "cwd" 340246149Ssjg E "pid" "path" 341246149Ssjg F "pid" "child" 342246149Ssjg R "pid" "path" 343246149Ssjg W "pid" "path" 344246149Ssjg X "pid" "status" 345246149Ssjg D "pid" "path" 346246149Ssjg L "pid" "src" "target" 347246149Ssjg M "pid" "old" "new" 348246149Ssjg S "pid" "path" 349246149Ssjg # Bye bye 350246149Ssjg 351246149Ssjg We go to some effort to avoid processing a dependency more than once. 352246149Ssjg Of the above record types only C,E,F,L,R,V and W are of interest. 353246149Ssjg """ 354246149Ssjg 355246149Ssjg version = 0 # unknown 356246149Ssjg if name: 357246149Ssjg self.name = name; 358246149Ssjg if file: 359246149Ssjg f = file 360246149Ssjg cwd = last_dir = self.cwd 361246149Ssjg else: 362246149Ssjg f = open(self.name, 'rb') 363246149Ssjg skip = True 364246149Ssjg pid_cwd = {} 365246149Ssjg pid_last_dir = {} 366246149Ssjg last_pid = 0 367246149Ssjg 368246149Ssjg if self.curdir: 369246149Ssjg self.seenit(self.curdir) # we ignore this 370246149Ssjg 371246149Ssjg interesting = 'CEFLRV' 372246149Ssjg for line in f: 373246149Ssjg # ignore anything we don't care about 374246149Ssjg if not line[0] in interesting: 375246149Ssjg continue 376246149Ssjg if self.debug > 2: 377246149Ssjg print >> self.debug_out, "input:", line, 378246149Ssjg w = line.split() 379246149Ssjg 380246149Ssjg if skip: 381246149Ssjg if w[0] == 'V': 382246149Ssjg skip = False 383246149Ssjg version = int(w[1]) 384246149Ssjg """ 385246149Ssjg if version < 4: 386246149Ssjg # we cannot ignore 'W' records 387246149Ssjg # as they may be 'rw' 388246149Ssjg interesting += 'W' 389246149Ssjg """ 390246149Ssjg elif w[0] == 'CWD': 391246149Ssjg self.cwd = cwd = last_dir = w[1] 392246149Ssjg self.seenit(cwd) # ignore this 393246149Ssjg if self.debug: 394246149Ssjg print >> self.debug_out, "%s: CWD=%s" % (self.name, cwd) 395246149Ssjg continue 396246149Ssjg 397246149Ssjg pid = int(w[1]) 398246149Ssjg if pid != last_pid: 399246149Ssjg if last_pid: 400246149Ssjg pid_cwd[last_pid] = cwd 401246149Ssjg pid_last_dir[last_pid] = last_dir 402246149Ssjg cwd = getv(pid_cwd, pid, self.cwd) 403246149Ssjg last_dir = getv(pid_last_dir, pid, self.cwd) 404246149Ssjg last_pid = pid 405246149Ssjg 406246149Ssjg # process operations 407246149Ssjg if w[0] == 'F': 408246149Ssjg npid = int(w[2]) 409246149Ssjg pid_cwd[npid] = cwd 410246149Ssjg pid_last_dir[npid] = cwd 411246149Ssjg last_pid = npid 412246149Ssjg continue 413246149Ssjg elif w[0] == 'C': 414246149Ssjg cwd = abspath(w[2], cwd, None, self.debug, self.debug_out) 415246149Ssjg if cwd.endswith('/.'): 416246149Ssjg cwd = cwd[0:-2] 417246149Ssjg last_dir = cwd 418246149Ssjg if self.debug > 1: 419246149Ssjg print >> self.debug_out, "cwd=", cwd 420246149Ssjg continue 421246149Ssjg 422246149Ssjg if w[2] in self.seen: 423246149Ssjg if self.debug > 2: 424246149Ssjg print >> self.debug_out, "seen:", w[2] 425246149Ssjg continue 426246149Ssjg # file operations 427246149Ssjg if w[0] in 'ML': 428246149Ssjg path = w[2].strip("'") 429246149Ssjg else: 430246149Ssjg path = w[2] 431246149Ssjg # we are never interested in .dirdep files as dependencies 432246149Ssjg if path.endswith('.dirdep'): 433246149Ssjg continue 434246149Ssjg # we don't want to resolve the last component if it is 435246149Ssjg # a symlink 436246149Ssjg path = resolve(path, cwd, last_dir, self.debug, self.debug_out) 437246149Ssjg if not path: 438246149Ssjg continue 439246149Ssjg dir,base = os.path.split(path) 440246149Ssjg if dir in self.seen: 441246149Ssjg if self.debug > 2: 442246149Ssjg print >> self.debug_out, "seen:", dir 443246149Ssjg continue 444246149Ssjg # we can have a path in an objdir which is a link 445246149Ssjg # to the src dir, we may need to add dependencies for each 446246149Ssjg rdir = dir 447246149Ssjg dir = abspath(dir, cwd, last_dir, self.debug, self.debug_out) 448246149Ssjg if rdir == dir or rdir.find('./') > 0: 449246149Ssjg rdir = None 450246149Ssjg # now put path back together 451246149Ssjg path = '/'.join([dir,base]) 452246149Ssjg if self.debug > 1: 453246149Ssjg print >> self.debug_out, "raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path) 454246149Ssjg if w[0] in 'SRWL': 455246149Ssjg if w[0] == 'W' and path.endswith('.dirdep'): 456246149Ssjg continue 457246149Ssjg if path in [last_dir, cwd, self.cwd, self.curdir]: 458246149Ssjg if self.debug > 1: 459246149Ssjg print >> self.debug_out, "skipping:", path 460246149Ssjg continue 461246149Ssjg if os.path.isdir(path): 462246149Ssjg if w[0] in 'RW': 463246149Ssjg last_dir = path; 464246149Ssjg if self.debug > 1: 465246149Ssjg print >> self.debug_out, "ldir=", last_dir 466246149Ssjg continue 467246149Ssjg 468246149Ssjg if w[0] in 'REWML': 469246149Ssjg # finally, we get down to it 470246149Ssjg if dir == self.cwd or dir == self.curdir: 471246149Ssjg continue 472246149Ssjg srctop = self.find_top(path, self.srctops) 473246149Ssjg if srctop: 474246149Ssjg if self.dpdeps: 475246149Ssjg self.add(self.file_deps, path.replace(srctop,''), 'file') 476246149Ssjg self.add(self.src_deps, dir.replace(srctop,''), 'src') 477246149Ssjg self.seenit(w[2]) 478246149Ssjg self.seenit(dir) 479246149Ssjg if rdir and not rdir.startswith(srctop): 480246149Ssjg dir = rdir # for below 481246149Ssjg rdir = None 482246149Ssjg else: 483246149Ssjg continue 484246149Ssjg 485246149Ssjg objroot = None 486246149Ssjg for dir in [dir,rdir]: 487246149Ssjg if not dir: 488246149Ssjg continue 489246149Ssjg objroot = self.find_top(dir, self.objroots) 490246149Ssjg if objroot: 491246149Ssjg break 492246149Ssjg if objroot: 493246149Ssjg ddep = self.find_obj(objroot, dir, path, w[2]) 494246149Ssjg if ddep: 495246149Ssjg self.add(self.obj_deps, ddep, 'obj') 496246149Ssjg else: 497246149Ssjg # don't waste time looking again 498246149Ssjg self.seenit(w[2]) 499246149Ssjg self.seenit(dir) 500246149Ssjg if not file: 501246149Ssjg f.close() 502246149Ssjg 503246149Ssjg 504246149Ssjgdef main(argv, klass=MetaFile, xopts='', xoptf=None): 505246149Ssjg """Simple driver for class MetaFile. 506246149Ssjg 507246149Ssjg Usage: 508246149Ssjg script [options] [key=value ...] "meta" ... 509246149Ssjg 510246149Ssjg Options and key=value pairs contribute to the 511246149Ssjg dictionary passed to MetaFile. 512246149Ssjg 513246149Ssjg -S "SRCTOP" 514246149Ssjg add "SRCTOP" to the "SRCTOPS" list. 515246149Ssjg 516246149Ssjg -C "CURDIR" 517246149Ssjg 518246149Ssjg -O "OBJROOT" 519246149Ssjg add "OBJROOT" to the "OBJROOTS" list. 520246149Ssjg 521246149Ssjg -m "MACHINE" 522246149Ssjg 523246149Ssjg -H "HOST_TARGET" 524246149Ssjg 525246149Ssjg -D "DPDEPS" 526246149Ssjg 527246149Ssjg -d bumps debug level 528246149Ssjg 529246149Ssjg """ 530246149Ssjg import getopt 531246149Ssjg 532246149Ssjg # import Psyco if we can 533246149Ssjg # it can speed things up quite a bit 534246149Ssjg have_psyco = 0 535246149Ssjg try: 536246149Ssjg import psyco 537246149Ssjg psyco.full() 538246149Ssjg have_psyco = 1 539246149Ssjg except: 540246149Ssjg pass 541246149Ssjg 542246149Ssjg conf = { 543246149Ssjg 'SRCTOPS': [], 544246149Ssjg 'OBJROOTS': [], 545246149Ssjg } 546246149Ssjg 547246149Ssjg try: 548246149Ssjg machine = os.environ['MACHINE'] 549246149Ssjg if machine: 550246149Ssjg conf['MACHINE'] = machine 551246149Ssjg srctop = os.environ['SB_SRC'] 552246149Ssjg if srctop: 553246149Ssjg conf['SRCTOPS'].append(srctop) 554246149Ssjg objroot = os.environ['SB_OBJROOT'] 555246149Ssjg if objroot: 556246149Ssjg conf['OBJROOTS'].append(objroot) 557246149Ssjg except: 558246149Ssjg pass 559246149Ssjg 560246149Ssjg debug = 0 561246149Ssjg output = True 562246149Ssjg 563246149Ssjg opts, args = getopt.getopt(argv[1:], 'dS:C:O:R:m:D:H:q' + xopts) 564246149Ssjg for o, a in opts: 565246149Ssjg if o == '-d': 566246149Ssjg debug += 1 567246149Ssjg elif o == '-q': 568246149Ssjg output = False 569246149Ssjg elif o == '-H': 570246149Ssjg conf['HOST_TARGET'] = a 571246149Ssjg elif o == '-S': 572246149Ssjg if a not in conf['SRCTOPS']: 573246149Ssjg conf['SRCTOPS'].append(a) 574246149Ssjg elif o == '-C': 575246149Ssjg conf['CURDIR'] = a 576246149Ssjg elif o == '-O': 577246149Ssjg if a not in conf['OBJROOTS']: 578246149Ssjg conf['OBJROOTS'].append(a) 579246149Ssjg elif o == '-R': 580246149Ssjg conf['RELDIR'] = a 581246149Ssjg elif o == '-D': 582246149Ssjg conf['DPDEPS'] = a 583246149Ssjg elif o == '-m': 584246149Ssjg conf['MACHINE'] = a 585246149Ssjg elif xoptf: 586246149Ssjg xoptf(o, a, conf) 587246149Ssjg 588246149Ssjg conf['debug'] = debug 589246149Ssjg 590246149Ssjg # get any var=val assignments 591246149Ssjg eaten = [] 592246149Ssjg for a in args: 593246149Ssjg if a.find('=') > 0: 594246149Ssjg k,v = a.split('=') 595246149Ssjg if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']: 596246149Ssjg if k == 'SRCTOP': 597246149Ssjg k = 'SRCTOPS' 598246149Ssjg elif k == 'OBJROOT': 599246149Ssjg k = 'OBJROOTS' 600246149Ssjg if v not in conf[k]: 601246149Ssjg conf[k].append(v) 602246149Ssjg else: 603246149Ssjg conf[k] = v 604246149Ssjg eaten.append(a) 605246149Ssjg continue 606246149Ssjg break 607246149Ssjg 608246149Ssjg for a in eaten: 609246149Ssjg args.remove(a) 610246149Ssjg 611246149Ssjg debug_out = getv(conf, 'debug_out', sys.stderr) 612246149Ssjg 613246149Ssjg if debug: 614246149Ssjg print >> debug_out, "config:" 615246149Ssjg print >> debug_out, "psyco=", have_psyco 616246149Ssjg for k,v in conf.items(): 617246149Ssjg print >> debug_out, "%s=%s" % (k,v) 618246149Ssjg 619246149Ssjg for a in args: 620246149Ssjg m = klass(a, conf) 621246149Ssjg 622246149Ssjg if output: 623246149Ssjg print m.dirdeps() 624246149Ssjg 625246149Ssjg print m.src_dirdeps('\nsrc:') 626246149Ssjg 627246149Ssjg dpdeps = getv(conf, 'DPDEPS') 628246149Ssjg if dpdeps: 629246149Ssjg m.file_depends(open(dpdeps, 'wb')) 630246149Ssjg 631246149Ssjg return m 632246149Ssjg 633246149Ssjgif __name__ == '__main__': 634246149Ssjg try: 635246149Ssjg main(sys.argv) 636246149Ssjg except: 637246149Ssjg # yes, this goes to stdout 638246149Ssjg print "ERROR: ", sys.exc_info()[1] 639246149Ssjg raise 640246149Ssjg 641