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: 38253883Ssjg $Id: meta2deps.py,v 1.15 2013/07/29 20:41:23 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] 80253883Ssjg if len(path) > 0 and 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 """ 110253883Ssjg rpath = resolve(path, cwd, last_dir, debug, debug_out) 111253883Ssjg if rpath: 112253883Ssjg path = rpath 113253883Ssjg if (path.find('./') > 0 or 114253883Ssjg path.endswith('/..') or 115253883Ssjg os.path.islink(path)): 116246149Ssjg return os.path.realpath(path) 117246149Ssjg return path 118246149Ssjg 119246149Ssjgdef sort_unique(list, cmp=None, key=None, reverse=False): 120246149Ssjg list.sort(cmp, key, reverse) 121246149Ssjg nl = [] 122246149Ssjg le = None 123246149Ssjg for e in list: 124246149Ssjg if e == le: 125246149Ssjg continue 126246149Ssjg nl.append(e) 127246149Ssjg return nl 128246149Ssjg 129250837Ssjgdef add_trims(x): 130250837Ssjg return ['/' + x + '/', 131250837Ssjg '/' + x, 132250837Ssjg x + '/', 133250837Ssjg x] 134250837Ssjg 135246149Ssjgclass MetaFile: 136246149Ssjg """class to parse meta files generated by bmake.""" 137246149Ssjg 138246149Ssjg conf = None 139246149Ssjg dirdep_re = None 140246149Ssjg host_target = None 141246149Ssjg srctops = [] 142246149Ssjg objroots = [] 143246149Ssjg 144246149Ssjg seen = {} 145246149Ssjg obj_deps = [] 146246149Ssjg src_deps = [] 147246149Ssjg file_deps = [] 148246149Ssjg 149246149Ssjg def __init__(self, name, conf={}): 150246149Ssjg """if name is set we will parse it now. 151246149Ssjg conf can have the follwing keys: 152246149Ssjg 153246149Ssjg SRCTOPS list of tops of the src tree(s). 154246149Ssjg 155246149Ssjg CURDIR the src directory 'bmake' was run from. 156246149Ssjg 157246149Ssjg RELDIR the relative path from SRCTOP to CURDIR 158246149Ssjg 159246149Ssjg MACHINE the machine we built for. 160246149Ssjg set to 'none' if we are not cross-building. 161249033Ssjg More specifically if machine cannot be deduced from objdirs. 162246149Ssjg 163250837Ssjg TARGET_SPEC 164250837Ssjg Sometimes MACHINE isn't enough. 165250837Ssjg 166246149Ssjg HOST_TARGET 167246149Ssjg when we build for the psuedo machine 'host' 168246149Ssjg the object tree uses HOST_TARGET rather than MACHINE. 169246149Ssjg 170246149Ssjg OBJROOTS a list of the common prefix for all obj dirs it might 171246149Ssjg end in '/' or '-'. 172246149Ssjg 173246149Ssjg DPDEPS names an optional file to which per file dependencies 174246149Ssjg will be appended. 175246149Ssjg For example if 'some/path/foo.h' is read from SRCTOP 176246149Ssjg then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output. 177246149Ssjg This can allow 'bmake' to learn all the dirs within 178246149Ssjg the tree that depend on 'foo.h' 179246149Ssjg 180246149Ssjg debug desired debug level 181246149Ssjg 182246149Ssjg debug_out open file to send debug output to (sys.stderr) 183246149Ssjg 184246149Ssjg """ 185246149Ssjg 186246149Ssjg self.name = name 187246149Ssjg self.debug = getv(conf, 'debug', 0) 188246149Ssjg self.debug_out = getv(conf, 'debug_out', sys.stderr) 189246149Ssjg 190249033Ssjg self.machine = getv(conf, 'MACHINE', '') 191250837Ssjg self.machine_arch = getv(conf, 'MACHINE_ARCH', '') 192250837Ssjg self.target_spec = getv(conf, 'TARGET_SPEC', '') 193249033Ssjg self.curdir = getv(conf, 'CURDIR') 194249033Ssjg self.reldir = getv(conf, 'RELDIR') 195249033Ssjg self.dpdeps = getv(conf, 'DPDEPS') 196253883Ssjg self.line = 0 197249033Ssjg 198246149Ssjg if not self.conf: 199246149Ssjg # some of the steps below we want to do only once 200246149Ssjg self.conf = conf 201246149Ssjg self.host_target = getv(conf, 'HOST_TARGET') 202246149Ssjg for srctop in getv(conf, 'SRCTOPS', []): 203246149Ssjg if srctop[-1] != '/': 204246149Ssjg srctop += '/' 205246149Ssjg if not srctop in self.srctops: 206246149Ssjg self.srctops.append(srctop) 207246149Ssjg _srctop = os.path.realpath(srctop) 208246149Ssjg if _srctop[-1] != '/': 209246149Ssjg _srctop += '/' 210246149Ssjg if not _srctop in self.srctops: 211246149Ssjg self.srctops.append(_srctop) 212246149Ssjg 213250837Ssjg trim_list = add_trims(self.machine) 214249033Ssjg if self.machine == 'host': 215250837Ssjg trim_list += add_trims(self.host_target) 216250837Ssjg if self.target_spec: 217250837Ssjg trim_list += add_trims(self.target_spec) 218249033Ssjg 219246149Ssjg for objroot in getv(conf, 'OBJROOTS', []): 220249033Ssjg for e in trim_list: 221249033Ssjg if objroot.endswith(e): 222249033Ssjg # this is not what we want - fix it 223249033Ssjg objroot = objroot[0:-len(e)] 224249033Ssjg if e.endswith('/'): 225249033Ssjg objroot += '/' 226246149Ssjg if not objroot in self.objroots: 227246149Ssjg self.objroots.append(objroot) 228246149Ssjg _objroot = os.path.realpath(objroot) 229246149Ssjg if objroot[-1] == '/': 230246149Ssjg _objroot += '/' 231246149Ssjg if not _objroot in self.objroots: 232246149Ssjg self.objroots.append(_objroot) 233246149Ssjg 234249033Ssjg # we want the longest match 235249033Ssjg self.srctops.sort(reverse=True) 236249033Ssjg self.objroots.sort(reverse=True) 237249033Ssjg 238246149Ssjg if self.debug: 239246149Ssjg print >> self.debug_out, "host_target=", self.host_target 240246149Ssjg print >> self.debug_out, "srctops=", self.srctops 241246149Ssjg print >> self.debug_out, "objroots=", self.objroots 242246149Ssjg 243246149Ssjg self.dirdep_re = re.compile(r'([^/]+)/(.+)') 244246149Ssjg 245246149Ssjg if self.dpdeps and not self.reldir: 246246149Ssjg if self.debug: 247246149Ssjg print >> self.debug_out, "need reldir:", 248246149Ssjg if self.curdir: 249246149Ssjg srctop = self.find_top(self.curdir, self.srctops) 250246149Ssjg if srctop: 251246149Ssjg self.reldir = self.curdir.replace(srctop,'') 252246149Ssjg if self.debug: 253246149Ssjg print >> self.debug_out, self.reldir 254246149Ssjg if not self.reldir: 255246149Ssjg self.dpdeps = None # we cannot do it? 256246149Ssjg 257249033Ssjg self.cwd = os.getcwd() # make sure this is initialized 258249033Ssjg 259246149Ssjg if name: 260253883Ssjg self.try_parse() 261246149Ssjg 262246149Ssjg def reset(self): 263246149Ssjg """reset state if we are being passed meta files from multiple directories.""" 264246149Ssjg self.seen = {} 265246149Ssjg self.obj_deps = [] 266246149Ssjg self.src_deps = [] 267246149Ssjg self.file_deps = [] 268246149Ssjg 269246149Ssjg def dirdeps(self, sep='\n'): 270246149Ssjg """return DIRDEPS""" 271246149Ssjg return sep.strip() + sep.join(self.obj_deps) 272246149Ssjg 273246149Ssjg def src_dirdeps(self, sep='\n'): 274246149Ssjg """return SRC_DIRDEPS""" 275246149Ssjg return sep.strip() + sep.join(self.src_deps) 276246149Ssjg 277246149Ssjg def file_depends(self, out=None): 278246149Ssjg """Append DPDEPS_${file} += ${RELDIR} 279246149Ssjg for each file we saw, to the output file.""" 280246149Ssjg if not self.reldir: 281246149Ssjg return None 282246149Ssjg for f in sort_unique(self.file_deps): 283246149Ssjg print >> out, 'DPDEPS_%s += %s' % (f, self.reldir) 284246149Ssjg 285246149Ssjg def seenit(self, dir): 286246149Ssjg """rememer that we have seen dir.""" 287246149Ssjg self.seen[dir] = 1 288246149Ssjg 289246149Ssjg def add(self, list, data, clue=''): 290246149Ssjg """add data to list if it isn't already there.""" 291246149Ssjg if data not in list: 292246149Ssjg list.append(data) 293246149Ssjg if self.debug: 294246149Ssjg print >> self.debug_out, "%s: %sAdd: %s" % (self.name, clue, data) 295246149Ssjg 296246149Ssjg def find_top(self, path, list): 297246149Ssjg """the logical tree may be split accross multiple trees""" 298246149Ssjg for top in list: 299246149Ssjg if path.startswith(top): 300246149Ssjg if self.debug > 2: 301246149Ssjg print >> self.debug_out, "found in", top 302246149Ssjg return top 303246149Ssjg return None 304246149Ssjg 305246149Ssjg def find_obj(self, objroot, dir, path, input): 306246149Ssjg """return path within objroot, taking care of .dirdep files""" 307246149Ssjg ddep = None 308246149Ssjg for ddepf in [path + '.dirdep', dir + '/.dirdep']: 309246149Ssjg if not ddep and os.path.exists(ddepf): 310246149Ssjg ddep = open(ddepf, 'rb').readline().strip('# \n') 311246149Ssjg if self.debug > 1: 312246149Ssjg print >> self.debug_out, "found %s: %s\n" % (ddepf, ddep) 313246149Ssjg if ddep.endswith(self.machine): 314246149Ssjg ddep = ddep[0:-(1+len(self.machine))] 315250837Ssjg elif self.target_spec and ddep.endswith(self.target_spec): 316250837Ssjg ddep = ddep[0:-(1+len(self.target_spec))] 317246149Ssjg 318246149Ssjg if not ddep: 319246149Ssjg # no .dirdeps, so remember that we've seen the raw input 320246149Ssjg self.seenit(input) 321246149Ssjg self.seenit(dir) 322246149Ssjg if self.machine == 'none': 323246149Ssjg if dir.startswith(objroot): 324246149Ssjg return dir.replace(objroot,'') 325246149Ssjg return None 326246149Ssjg m = self.dirdep_re.match(dir.replace(objroot,'')) 327246149Ssjg if m: 328246149Ssjg ddep = m.group(2) 329246149Ssjg dmachine = m.group(1) 330246149Ssjg if dmachine != self.machine: 331246149Ssjg if not (self.machine == 'host' and 332246149Ssjg dmachine == self.host_target): 333246149Ssjg if self.debug > 2: 334246149Ssjg print >> self.debug_out, "adding .%s to %s" % (dmachine, ddep) 335246149Ssjg ddep += '.' + dmachine 336246149Ssjg 337246149Ssjg return ddep 338246149Ssjg 339253883Ssjg def try_parse(self, name=None, file=None): 340253883Ssjg """give file and line number causing exception""" 341253883Ssjg try: 342253883Ssjg self.parse(name, file) 343253883Ssjg except: 344253883Ssjg # give a useful clue 345253883Ssjg print >> sys.stderr, '{}:{}: '.format(self.name, self.line), 346253883Ssjg raise 347253883Ssjg 348246149Ssjg def parse(self, name=None, file=None): 349246149Ssjg """A meta file looks like: 350246149Ssjg 351246149Ssjg # Meta data file "path" 352246149Ssjg CMD "command-line" 353246149Ssjg CWD "cwd" 354246149Ssjg TARGET "target" 355246149Ssjg -- command output -- 356246149Ssjg -- filemon acquired metadata -- 357246149Ssjg # buildmon version 3 358246149Ssjg V 3 359246149Ssjg C "pid" "cwd" 360246149Ssjg E "pid" "path" 361246149Ssjg F "pid" "child" 362246149Ssjg R "pid" "path" 363246149Ssjg W "pid" "path" 364246149Ssjg X "pid" "status" 365246149Ssjg D "pid" "path" 366246149Ssjg L "pid" "src" "target" 367246149Ssjg M "pid" "old" "new" 368246149Ssjg S "pid" "path" 369246149Ssjg # Bye bye 370246149Ssjg 371246149Ssjg We go to some effort to avoid processing a dependency more than once. 372246149Ssjg Of the above record types only C,E,F,L,R,V and W are of interest. 373246149Ssjg """ 374246149Ssjg 375246149Ssjg version = 0 # unknown 376246149Ssjg if name: 377246149Ssjg self.name = name; 378246149Ssjg if file: 379246149Ssjg f = file 380246149Ssjg cwd = last_dir = self.cwd 381246149Ssjg else: 382246149Ssjg f = open(self.name, 'rb') 383246149Ssjg skip = True 384246149Ssjg pid_cwd = {} 385246149Ssjg pid_last_dir = {} 386246149Ssjg last_pid = 0 387246149Ssjg 388253883Ssjg self.line = 0 389246149Ssjg if self.curdir: 390246149Ssjg self.seenit(self.curdir) # we ignore this 391246149Ssjg 392246149Ssjg interesting = 'CEFLRV' 393246149Ssjg for line in f: 394253883Ssjg self.line += 1 395246149Ssjg # ignore anything we don't care about 396246149Ssjg if not line[0] in interesting: 397246149Ssjg continue 398246149Ssjg if self.debug > 2: 399246149Ssjg print >> self.debug_out, "input:", line, 400246149Ssjg w = line.split() 401246149Ssjg 402246149Ssjg if skip: 403246149Ssjg if w[0] == 'V': 404246149Ssjg skip = False 405246149Ssjg version = int(w[1]) 406246149Ssjg """ 407246149Ssjg if version < 4: 408246149Ssjg # we cannot ignore 'W' records 409246149Ssjg # as they may be 'rw' 410246149Ssjg interesting += 'W' 411246149Ssjg """ 412246149Ssjg elif w[0] == 'CWD': 413246149Ssjg self.cwd = cwd = last_dir = w[1] 414246149Ssjg self.seenit(cwd) # ignore this 415246149Ssjg if self.debug: 416246149Ssjg print >> self.debug_out, "%s: CWD=%s" % (self.name, cwd) 417246149Ssjg continue 418246149Ssjg 419246149Ssjg pid = int(w[1]) 420246149Ssjg if pid != last_pid: 421246149Ssjg if last_pid: 422246149Ssjg pid_cwd[last_pid] = cwd 423246149Ssjg pid_last_dir[last_pid] = last_dir 424246149Ssjg cwd = getv(pid_cwd, pid, self.cwd) 425246149Ssjg last_dir = getv(pid_last_dir, pid, self.cwd) 426246149Ssjg last_pid = pid 427246149Ssjg 428246149Ssjg # process operations 429246149Ssjg if w[0] == 'F': 430246149Ssjg npid = int(w[2]) 431246149Ssjg pid_cwd[npid] = cwd 432246149Ssjg pid_last_dir[npid] = cwd 433246149Ssjg last_pid = npid 434246149Ssjg continue 435246149Ssjg elif w[0] == 'C': 436246149Ssjg cwd = abspath(w[2], cwd, None, self.debug, self.debug_out) 437246149Ssjg if cwd.endswith('/.'): 438246149Ssjg cwd = cwd[0:-2] 439246149Ssjg last_dir = cwd 440246149Ssjg if self.debug > 1: 441246149Ssjg print >> self.debug_out, "cwd=", cwd 442246149Ssjg continue 443246149Ssjg 444246149Ssjg if w[2] in self.seen: 445246149Ssjg if self.debug > 2: 446246149Ssjg print >> self.debug_out, "seen:", w[2] 447246149Ssjg continue 448246149Ssjg # file operations 449246149Ssjg if w[0] in 'ML': 450246149Ssjg path = w[2].strip("'") 451246149Ssjg else: 452246149Ssjg path = w[2] 453246149Ssjg # we are never interested in .dirdep files as dependencies 454246149Ssjg if path.endswith('.dirdep'): 455246149Ssjg continue 456246149Ssjg # we don't want to resolve the last component if it is 457246149Ssjg # a symlink 458246149Ssjg path = resolve(path, cwd, last_dir, self.debug, self.debug_out) 459246149Ssjg if not path: 460246149Ssjg continue 461246149Ssjg dir,base = os.path.split(path) 462246149Ssjg if dir in self.seen: 463246149Ssjg if self.debug > 2: 464246149Ssjg print >> self.debug_out, "seen:", dir 465246149Ssjg continue 466246149Ssjg # we can have a path in an objdir which is a link 467246149Ssjg # to the src dir, we may need to add dependencies for each 468246149Ssjg rdir = dir 469246149Ssjg dir = abspath(dir, cwd, last_dir, self.debug, self.debug_out) 470246149Ssjg if rdir == dir or rdir.find('./') > 0: 471246149Ssjg rdir = None 472246149Ssjg # now put path back together 473246149Ssjg path = '/'.join([dir,base]) 474246149Ssjg if self.debug > 1: 475246149Ssjg print >> self.debug_out, "raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path) 476246149Ssjg if w[0] in 'SRWL': 477246149Ssjg if w[0] == 'W' and path.endswith('.dirdep'): 478246149Ssjg continue 479246149Ssjg if path in [last_dir, cwd, self.cwd, self.curdir]: 480246149Ssjg if self.debug > 1: 481246149Ssjg print >> self.debug_out, "skipping:", path 482246149Ssjg continue 483246149Ssjg if os.path.isdir(path): 484246149Ssjg if w[0] in 'RW': 485246149Ssjg last_dir = path; 486246149Ssjg if self.debug > 1: 487246149Ssjg print >> self.debug_out, "ldir=", last_dir 488246149Ssjg continue 489246149Ssjg 490246149Ssjg if w[0] in 'REWML': 491246149Ssjg # finally, we get down to it 492246149Ssjg if dir == self.cwd or dir == self.curdir: 493246149Ssjg continue 494246149Ssjg srctop = self.find_top(path, self.srctops) 495246149Ssjg if srctop: 496246149Ssjg if self.dpdeps: 497246149Ssjg self.add(self.file_deps, path.replace(srctop,''), 'file') 498246149Ssjg self.add(self.src_deps, dir.replace(srctop,''), 'src') 499246149Ssjg self.seenit(w[2]) 500246149Ssjg self.seenit(dir) 501246149Ssjg if rdir and not rdir.startswith(srctop): 502246149Ssjg dir = rdir # for below 503246149Ssjg rdir = None 504246149Ssjg else: 505246149Ssjg continue 506246149Ssjg 507246149Ssjg objroot = None 508246149Ssjg for dir in [dir,rdir]: 509246149Ssjg if not dir: 510246149Ssjg continue 511246149Ssjg objroot = self.find_top(dir, self.objroots) 512246149Ssjg if objroot: 513246149Ssjg break 514246149Ssjg if objroot: 515246149Ssjg ddep = self.find_obj(objroot, dir, path, w[2]) 516246149Ssjg if ddep: 517246149Ssjg self.add(self.obj_deps, ddep, 'obj') 518246149Ssjg else: 519246149Ssjg # don't waste time looking again 520246149Ssjg self.seenit(w[2]) 521246149Ssjg self.seenit(dir) 522246149Ssjg if not file: 523246149Ssjg f.close() 524246149Ssjg 525246149Ssjg 526246149Ssjgdef main(argv, klass=MetaFile, xopts='', xoptf=None): 527246149Ssjg """Simple driver for class MetaFile. 528246149Ssjg 529246149Ssjg Usage: 530246149Ssjg script [options] [key=value ...] "meta" ... 531246149Ssjg 532246149Ssjg Options and key=value pairs contribute to the 533246149Ssjg dictionary passed to MetaFile. 534246149Ssjg 535246149Ssjg -S "SRCTOP" 536246149Ssjg add "SRCTOP" to the "SRCTOPS" list. 537246149Ssjg 538246149Ssjg -C "CURDIR" 539246149Ssjg 540246149Ssjg -O "OBJROOT" 541246149Ssjg add "OBJROOT" to the "OBJROOTS" list. 542246149Ssjg 543246149Ssjg -m "MACHINE" 544246149Ssjg 545250837Ssjg -a "MACHINE_ARCH" 546250837Ssjg 547246149Ssjg -H "HOST_TARGET" 548246149Ssjg 549246149Ssjg -D "DPDEPS" 550246149Ssjg 551246149Ssjg -d bumps debug level 552246149Ssjg 553246149Ssjg """ 554246149Ssjg import getopt 555246149Ssjg 556246149Ssjg # import Psyco if we can 557246149Ssjg # it can speed things up quite a bit 558246149Ssjg have_psyco = 0 559246149Ssjg try: 560246149Ssjg import psyco 561246149Ssjg psyco.full() 562246149Ssjg have_psyco = 1 563246149Ssjg except: 564246149Ssjg pass 565246149Ssjg 566246149Ssjg conf = { 567246149Ssjg 'SRCTOPS': [], 568246149Ssjg 'OBJROOTS': [], 569246149Ssjg } 570246149Ssjg 571246149Ssjg try: 572246149Ssjg machine = os.environ['MACHINE'] 573246149Ssjg if machine: 574246149Ssjg conf['MACHINE'] = machine 575250837Ssjg machine_arch = os.environ['MACHINE_ARCH'] 576250837Ssjg if machine_arch: 577250837Ssjg conf['MACHINE_ARCH'] = machine_arch 578246149Ssjg srctop = os.environ['SB_SRC'] 579246149Ssjg if srctop: 580246149Ssjg conf['SRCTOPS'].append(srctop) 581246149Ssjg objroot = os.environ['SB_OBJROOT'] 582246149Ssjg if objroot: 583246149Ssjg conf['OBJROOTS'].append(objroot) 584246149Ssjg except: 585246149Ssjg pass 586246149Ssjg 587246149Ssjg debug = 0 588246149Ssjg output = True 589246149Ssjg 590250837Ssjg opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:' + xopts) 591246149Ssjg for o, a in opts: 592250837Ssjg if o == '-a': 593250837Ssjg conf['MACHINE_ARCH'] = a 594250837Ssjg elif o == '-d': 595246149Ssjg debug += 1 596246149Ssjg elif o == '-q': 597246149Ssjg output = False 598246149Ssjg elif o == '-H': 599246149Ssjg conf['HOST_TARGET'] = a 600246149Ssjg elif o == '-S': 601246149Ssjg if a not in conf['SRCTOPS']: 602246149Ssjg conf['SRCTOPS'].append(a) 603246149Ssjg elif o == '-C': 604246149Ssjg conf['CURDIR'] = a 605246149Ssjg elif o == '-O': 606246149Ssjg if a not in conf['OBJROOTS']: 607246149Ssjg conf['OBJROOTS'].append(a) 608246149Ssjg elif o == '-R': 609246149Ssjg conf['RELDIR'] = a 610246149Ssjg elif o == '-D': 611246149Ssjg conf['DPDEPS'] = a 612246149Ssjg elif o == '-m': 613246149Ssjg conf['MACHINE'] = a 614250837Ssjg elif o == '-T': 615250837Ssjg conf['TARGET_SPEC'] = a 616246149Ssjg elif xoptf: 617246149Ssjg xoptf(o, a, conf) 618246149Ssjg 619246149Ssjg conf['debug'] = debug 620246149Ssjg 621246149Ssjg # get any var=val assignments 622246149Ssjg eaten = [] 623246149Ssjg for a in args: 624246149Ssjg if a.find('=') > 0: 625246149Ssjg k,v = a.split('=') 626246149Ssjg if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']: 627246149Ssjg if k == 'SRCTOP': 628246149Ssjg k = 'SRCTOPS' 629246149Ssjg elif k == 'OBJROOT': 630246149Ssjg k = 'OBJROOTS' 631246149Ssjg if v not in conf[k]: 632246149Ssjg conf[k].append(v) 633246149Ssjg else: 634246149Ssjg conf[k] = v 635246149Ssjg eaten.append(a) 636246149Ssjg continue 637246149Ssjg break 638246149Ssjg 639246149Ssjg for a in eaten: 640246149Ssjg args.remove(a) 641246149Ssjg 642246149Ssjg debug_out = getv(conf, 'debug_out', sys.stderr) 643246149Ssjg 644246149Ssjg if debug: 645246149Ssjg print >> debug_out, "config:" 646246149Ssjg print >> debug_out, "psyco=", have_psyco 647246149Ssjg for k,v in conf.items(): 648246149Ssjg print >> debug_out, "%s=%s" % (k,v) 649246149Ssjg 650246149Ssjg for a in args: 651253883Ssjg if a.endswith('.meta'): 652253883Ssjg m = klass(a, conf) 653253883Ssjg elif a.startswith('@'): 654253883Ssjg # there can actually multiple files per line 655253883Ssjg for line in open(a[1:]): 656253883Ssjg for f in line.strip().split(): 657253883Ssjg m = klass(f, conf) 658246149Ssjg 659246149Ssjg if output: 660246149Ssjg print m.dirdeps() 661246149Ssjg 662246149Ssjg print m.src_dirdeps('\nsrc:') 663246149Ssjg 664246149Ssjg dpdeps = getv(conf, 'DPDEPS') 665246149Ssjg if dpdeps: 666246149Ssjg m.file_depends(open(dpdeps, 'wb')) 667246149Ssjg 668246149Ssjg return m 669246149Ssjg 670246149Ssjgif __name__ == '__main__': 671246149Ssjg try: 672246149Ssjg main(sys.argv) 673246149Ssjg except: 674246149Ssjg # yes, this goes to stdout 675246149Ssjg print "ERROR: ", sys.exc_info()[1] 676246149Ssjg raise 677246149Ssjg 678