meta2deps.py revision 268437
1246149Ssjg#!/usr/bin/env python 2246149Ssjg 3261212Ssjgfrom __future__ import print_function 4261212Ssjg 5246149Ssjg""" 6246149SsjgThis script parses each "meta" file and extracts the 7246149Ssjginformation needed to deduce build and src dependencies. 8246149Ssjg 9246149SsjgIt works much the same as the original shell script, but is 10246149Ssjg*much* more efficient. 11246149Ssjg 12246149SsjgThe parsing work is handled by the class MetaFile. 13246149SsjgWe only pay attention to a subset of the information in the 14246149Ssjg"meta" files. Specifically: 15246149Ssjg 16246149Ssjg'CWD' to initialize our notion. 17246149Ssjg 18246149Ssjg'C' to track chdir(2) on a per process basis 19246149Ssjg 20246149Ssjg'R' files read are what we really care about. 21246149Ssjg directories read, provide a clue to resolving 22246149Ssjg subsequent relative paths. That is if we cannot find 23246149Ssjg them relative to 'cwd', we check relative to the last 24246149Ssjg dir read. 25246149Ssjg 26246149Ssjg'W' files opened for write or read-write, 27246149Ssjg for filemon V3 and earlier. 28246149Ssjg 29246149Ssjg'E' files executed. 30246149Ssjg 31246149Ssjg'L' files linked 32246149Ssjg 33246149Ssjg'V' the filemon version, this record is used as a clue 34246149Ssjg that we have reached the interesting bit. 35246149Ssjg 36246149Ssjg""" 37246149Ssjg 38246149Ssjg""" 39246149SsjgRCSid: 40268437Ssjg $Id: meta2deps.py,v 1.17 2014/04/05 22:56:54 sjg Exp $ 41246149Ssjg 42249033Ssjg Copyright (c) 2011-2013, Juniper Networks, Inc. 43249033Ssjg All rights reserved. 44246149Ssjg 45246149Ssjg Redistribution and use in source and binary forms, with or without 46246149Ssjg modification, are permitted provided that the following conditions 47246149Ssjg are met: 48246149Ssjg 1. Redistributions of source code must retain the above copyright 49246149Ssjg notice, this list of conditions and the following disclaimer. 50246149Ssjg 2. Redistributions in binary form must reproduce the above copyright 51246149Ssjg notice, this list of conditions and the following disclaimer in the 52246149Ssjg documentation and/or other materials provided with the distribution. 53246149Ssjg 54246149Ssjg THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 55246149Ssjg "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 56246149Ssjg LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 57246149Ssjg A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 58246149Ssjg OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 59246149Ssjg SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 60246149Ssjg LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 61246149Ssjg DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 62246149Ssjg THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 63246149Ssjg (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 64246149Ssjg OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 65246149Ssjg 66246149Ssjg""" 67246149Ssjg 68246149Ssjgimport os, re, sys 69246149Ssjg 70246149Ssjgdef getv(dict, key, d=None): 71246149Ssjg """Lookup key in dict and return value or the supplied default.""" 72246149Ssjg if key in dict: 73246149Ssjg return dict[key] 74246149Ssjg return d 75246149Ssjg 76246149Ssjgdef resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr): 77246149Ssjg """ 78246149Ssjg Return an absolute path, resolving via cwd or last_dir if needed. 79246149Ssjg """ 80246149Ssjg if path.endswith('/.'): 81246149Ssjg path = path[0:-2] 82253883Ssjg if len(path) > 0 and path[0] == '/': 83246149Ssjg return path 84246149Ssjg if path == '.': 85246149Ssjg return cwd 86246149Ssjg if path.startswith('./'): 87246149Ssjg return cwd + path[1:] 88246149Ssjg if last_dir == cwd: 89246149Ssjg last_dir = None 90246149Ssjg for d in [last_dir, cwd]: 91246149Ssjg if not d: 92246149Ssjg continue 93246149Ssjg p = '/'.join([d,path]) 94246149Ssjg if debug > 2: 95261212Ssjg print("looking for:", p, end=' ', file=debug_out) 96246149Ssjg if not os.path.exists(p): 97246149Ssjg if debug > 2: 98261212Ssjg print("nope", file=debug_out) 99246149Ssjg p = None 100246149Ssjg continue 101246149Ssjg if debug > 2: 102261212Ssjg print("found:", p, file=debug_out) 103246149Ssjg return p 104246149Ssjg return None 105246149Ssjg 106246149Ssjgdef abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr): 107246149Ssjg """ 108246149Ssjg Return an absolute path, resolving via cwd or last_dir if needed. 109246149Ssjg this gets called a lot, so we try to avoid calling realpath 110246149Ssjg until we know we have something. 111246149Ssjg """ 112253883Ssjg rpath = resolve(path, cwd, last_dir, debug, debug_out) 113253883Ssjg if rpath: 114253883Ssjg path = rpath 115253883Ssjg if (path.find('./') > 0 or 116253883Ssjg path.endswith('/..') or 117253883Ssjg os.path.islink(path)): 118246149Ssjg return os.path.realpath(path) 119246149Ssjg return path 120246149Ssjg 121246149Ssjgdef sort_unique(list, cmp=None, key=None, reverse=False): 122246149Ssjg list.sort(cmp, key, reverse) 123246149Ssjg nl = [] 124246149Ssjg le = None 125246149Ssjg for e in list: 126246149Ssjg if e == le: 127246149Ssjg continue 128246149Ssjg nl.append(e) 129246149Ssjg return nl 130246149Ssjg 131250837Ssjgdef add_trims(x): 132250837Ssjg return ['/' + x + '/', 133250837Ssjg '/' + x, 134250837Ssjg x + '/', 135250837Ssjg x] 136250837Ssjg 137246149Ssjgclass MetaFile: 138246149Ssjg """class to parse meta files generated by bmake.""" 139246149Ssjg 140246149Ssjg conf = None 141246149Ssjg dirdep_re = None 142246149Ssjg host_target = None 143246149Ssjg srctops = [] 144246149Ssjg objroots = [] 145246149Ssjg 146246149Ssjg seen = {} 147246149Ssjg obj_deps = [] 148246149Ssjg src_deps = [] 149246149Ssjg file_deps = [] 150246149Ssjg 151246149Ssjg def __init__(self, name, conf={}): 152246149Ssjg """if name is set we will parse it now. 153246149Ssjg conf can have the follwing keys: 154246149Ssjg 155246149Ssjg SRCTOPS list of tops of the src tree(s). 156246149Ssjg 157246149Ssjg CURDIR the src directory 'bmake' was run from. 158246149Ssjg 159246149Ssjg RELDIR the relative path from SRCTOP to CURDIR 160246149Ssjg 161246149Ssjg MACHINE the machine we built for. 162246149Ssjg set to 'none' if we are not cross-building. 163249033Ssjg More specifically if machine cannot be deduced from objdirs. 164246149Ssjg 165250837Ssjg TARGET_SPEC 166250837Ssjg Sometimes MACHINE isn't enough. 167250837Ssjg 168246149Ssjg HOST_TARGET 169268437Ssjg when we build for the pseudo machine 'host' 170246149Ssjg the object tree uses HOST_TARGET rather than MACHINE. 171246149Ssjg 172246149Ssjg OBJROOTS a list of the common prefix for all obj dirs it might 173246149Ssjg end in '/' or '-'. 174246149Ssjg 175246149Ssjg DPDEPS names an optional file to which per file dependencies 176246149Ssjg will be appended. 177246149Ssjg For example if 'some/path/foo.h' is read from SRCTOP 178246149Ssjg then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output. 179246149Ssjg This can allow 'bmake' to learn all the dirs within 180246149Ssjg the tree that depend on 'foo.h' 181246149Ssjg 182246149Ssjg debug desired debug level 183246149Ssjg 184246149Ssjg debug_out open file to send debug output to (sys.stderr) 185246149Ssjg 186246149Ssjg """ 187246149Ssjg 188246149Ssjg self.name = name 189246149Ssjg self.debug = getv(conf, 'debug', 0) 190246149Ssjg self.debug_out = getv(conf, 'debug_out', sys.stderr) 191246149Ssjg 192249033Ssjg self.machine = getv(conf, 'MACHINE', '') 193250837Ssjg self.machine_arch = getv(conf, 'MACHINE_ARCH', '') 194250837Ssjg self.target_spec = getv(conf, 'TARGET_SPEC', '') 195249033Ssjg self.curdir = getv(conf, 'CURDIR') 196249033Ssjg self.reldir = getv(conf, 'RELDIR') 197249033Ssjg self.dpdeps = getv(conf, 'DPDEPS') 198253883Ssjg self.line = 0 199249033Ssjg 200246149Ssjg if not self.conf: 201246149Ssjg # some of the steps below we want to do only once 202246149Ssjg self.conf = conf 203246149Ssjg self.host_target = getv(conf, 'HOST_TARGET') 204246149Ssjg for srctop in getv(conf, 'SRCTOPS', []): 205246149Ssjg if srctop[-1] != '/': 206246149Ssjg srctop += '/' 207246149Ssjg if not srctop in self.srctops: 208246149Ssjg self.srctops.append(srctop) 209246149Ssjg _srctop = os.path.realpath(srctop) 210246149Ssjg if _srctop[-1] != '/': 211246149Ssjg _srctop += '/' 212246149Ssjg if not _srctop in self.srctops: 213246149Ssjg self.srctops.append(_srctop) 214246149Ssjg 215250837Ssjg trim_list = add_trims(self.machine) 216249033Ssjg if self.machine == 'host': 217250837Ssjg trim_list += add_trims(self.host_target) 218250837Ssjg if self.target_spec: 219250837Ssjg trim_list += add_trims(self.target_spec) 220249033Ssjg 221246149Ssjg for objroot in getv(conf, 'OBJROOTS', []): 222249033Ssjg for e in trim_list: 223249033Ssjg if objroot.endswith(e): 224249033Ssjg # this is not what we want - fix it 225249033Ssjg objroot = objroot[0:-len(e)] 226249033Ssjg if e.endswith('/'): 227249033Ssjg objroot += '/' 228246149Ssjg if not objroot in self.objroots: 229246149Ssjg self.objroots.append(objroot) 230246149Ssjg _objroot = os.path.realpath(objroot) 231246149Ssjg if objroot[-1] == '/': 232246149Ssjg _objroot += '/' 233246149Ssjg if not _objroot in self.objroots: 234246149Ssjg self.objroots.append(_objroot) 235246149Ssjg 236249033Ssjg # we want the longest match 237249033Ssjg self.srctops.sort(reverse=True) 238249033Ssjg self.objroots.sort(reverse=True) 239249033Ssjg 240246149Ssjg if self.debug: 241261212Ssjg print("host_target=", self.host_target, file=self.debug_out) 242261212Ssjg print("srctops=", self.srctops, file=self.debug_out) 243261212Ssjg print("objroots=", self.objroots, file=self.debug_out) 244246149Ssjg 245246149Ssjg self.dirdep_re = re.compile(r'([^/]+)/(.+)') 246246149Ssjg 247246149Ssjg if self.dpdeps and not self.reldir: 248246149Ssjg if self.debug: 249261212Ssjg print("need reldir:", end=' ', file=self.debug_out) 250246149Ssjg if self.curdir: 251246149Ssjg srctop = self.find_top(self.curdir, self.srctops) 252246149Ssjg if srctop: 253246149Ssjg self.reldir = self.curdir.replace(srctop,'') 254246149Ssjg if self.debug: 255261212Ssjg print(self.reldir, file=self.debug_out) 256246149Ssjg if not self.reldir: 257246149Ssjg self.dpdeps = None # we cannot do it? 258246149Ssjg 259249033Ssjg self.cwd = os.getcwd() # make sure this is initialized 260249033Ssjg 261246149Ssjg if name: 262253883Ssjg self.try_parse() 263246149Ssjg 264246149Ssjg def reset(self): 265246149Ssjg """reset state if we are being passed meta files from multiple directories.""" 266246149Ssjg self.seen = {} 267246149Ssjg self.obj_deps = [] 268246149Ssjg self.src_deps = [] 269246149Ssjg self.file_deps = [] 270246149Ssjg 271246149Ssjg def dirdeps(self, sep='\n'): 272246149Ssjg """return DIRDEPS""" 273246149Ssjg return sep.strip() + sep.join(self.obj_deps) 274246149Ssjg 275246149Ssjg def src_dirdeps(self, sep='\n'): 276246149Ssjg """return SRC_DIRDEPS""" 277246149Ssjg return sep.strip() + sep.join(self.src_deps) 278246149Ssjg 279246149Ssjg def file_depends(self, out=None): 280246149Ssjg """Append DPDEPS_${file} += ${RELDIR} 281246149Ssjg for each file we saw, to the output file.""" 282246149Ssjg if not self.reldir: 283246149Ssjg return None 284246149Ssjg for f in sort_unique(self.file_deps): 285261212Ssjg print('DPDEPS_%s += %s' % (f, self.reldir), file=out) 286246149Ssjg 287246149Ssjg def seenit(self, dir): 288246149Ssjg """rememer that we have seen dir.""" 289246149Ssjg self.seen[dir] = 1 290246149Ssjg 291246149Ssjg def add(self, list, data, clue=''): 292246149Ssjg """add data to list if it isn't already there.""" 293246149Ssjg if data not in list: 294246149Ssjg list.append(data) 295246149Ssjg if self.debug: 296261212Ssjg print("%s: %sAdd: %s" % (self.name, clue, data), file=self.debug_out) 297246149Ssjg 298246149Ssjg def find_top(self, path, list): 299268437Ssjg """the logical tree may be split across multiple trees""" 300246149Ssjg for top in list: 301246149Ssjg if path.startswith(top): 302246149Ssjg if self.debug > 2: 303261212Ssjg print("found in", top, file=self.debug_out) 304246149Ssjg return top 305246149Ssjg return None 306246149Ssjg 307246149Ssjg def find_obj(self, objroot, dir, path, input): 308246149Ssjg """return path within objroot, taking care of .dirdep files""" 309246149Ssjg ddep = None 310246149Ssjg for ddepf in [path + '.dirdep', dir + '/.dirdep']: 311246149Ssjg if not ddep and os.path.exists(ddepf): 312261212Ssjg ddep = open(ddepf, 'r').readline().strip('# \n') 313246149Ssjg if self.debug > 1: 314261212Ssjg print("found %s: %s\n" % (ddepf, ddep), file=self.debug_out) 315246149Ssjg if ddep.endswith(self.machine): 316246149Ssjg ddep = ddep[0:-(1+len(self.machine))] 317250837Ssjg elif self.target_spec and ddep.endswith(self.target_spec): 318250837Ssjg ddep = ddep[0:-(1+len(self.target_spec))] 319246149Ssjg 320246149Ssjg if not ddep: 321246149Ssjg # no .dirdeps, so remember that we've seen the raw input 322246149Ssjg self.seenit(input) 323246149Ssjg self.seenit(dir) 324246149Ssjg if self.machine == 'none': 325246149Ssjg if dir.startswith(objroot): 326246149Ssjg return dir.replace(objroot,'') 327246149Ssjg return None 328246149Ssjg m = self.dirdep_re.match(dir.replace(objroot,'')) 329246149Ssjg if m: 330246149Ssjg ddep = m.group(2) 331246149Ssjg dmachine = m.group(1) 332246149Ssjg if dmachine != self.machine: 333246149Ssjg if not (self.machine == 'host' and 334246149Ssjg dmachine == self.host_target): 335246149Ssjg if self.debug > 2: 336261212Ssjg print("adding .%s to %s" % (dmachine, ddep), file=self.debug_out) 337246149Ssjg ddep += '.' + dmachine 338246149Ssjg 339246149Ssjg return ddep 340246149Ssjg 341253883Ssjg def try_parse(self, name=None, file=None): 342253883Ssjg """give file and line number causing exception""" 343253883Ssjg try: 344253883Ssjg self.parse(name, file) 345253883Ssjg except: 346253883Ssjg # give a useful clue 347261212Ssjg print('{}:{}: '.format(self.name, self.line), end=' ', file=sys.stderr) 348253883Ssjg raise 349253883Ssjg 350246149Ssjg def parse(self, name=None, file=None): 351246149Ssjg """A meta file looks like: 352246149Ssjg 353246149Ssjg # Meta data file "path" 354246149Ssjg CMD "command-line" 355246149Ssjg CWD "cwd" 356246149Ssjg TARGET "target" 357246149Ssjg -- command output -- 358246149Ssjg -- filemon acquired metadata -- 359246149Ssjg # buildmon version 3 360246149Ssjg V 3 361246149Ssjg C "pid" "cwd" 362246149Ssjg E "pid" "path" 363246149Ssjg F "pid" "child" 364246149Ssjg R "pid" "path" 365246149Ssjg W "pid" "path" 366246149Ssjg X "pid" "status" 367246149Ssjg D "pid" "path" 368246149Ssjg L "pid" "src" "target" 369246149Ssjg M "pid" "old" "new" 370246149Ssjg S "pid" "path" 371246149Ssjg # Bye bye 372246149Ssjg 373246149Ssjg We go to some effort to avoid processing a dependency more than once. 374246149Ssjg Of the above record types only C,E,F,L,R,V and W are of interest. 375246149Ssjg """ 376246149Ssjg 377246149Ssjg version = 0 # unknown 378246149Ssjg if name: 379246149Ssjg self.name = name; 380246149Ssjg if file: 381246149Ssjg f = file 382246149Ssjg cwd = last_dir = self.cwd 383246149Ssjg else: 384261212Ssjg f = open(self.name, 'r') 385246149Ssjg skip = True 386246149Ssjg pid_cwd = {} 387246149Ssjg pid_last_dir = {} 388246149Ssjg last_pid = 0 389246149Ssjg 390253883Ssjg self.line = 0 391246149Ssjg if self.curdir: 392246149Ssjg self.seenit(self.curdir) # we ignore this 393246149Ssjg 394246149Ssjg interesting = 'CEFLRV' 395246149Ssjg for line in f: 396253883Ssjg self.line += 1 397246149Ssjg # ignore anything we don't care about 398246149Ssjg if not line[0] in interesting: 399246149Ssjg continue 400246149Ssjg if self.debug > 2: 401261212Ssjg print("input:", line, end=' ', file=self.debug_out) 402246149Ssjg w = line.split() 403246149Ssjg 404246149Ssjg if skip: 405246149Ssjg if w[0] == 'V': 406246149Ssjg skip = False 407246149Ssjg version = int(w[1]) 408246149Ssjg """ 409246149Ssjg if version < 4: 410246149Ssjg # we cannot ignore 'W' records 411246149Ssjg # as they may be 'rw' 412246149Ssjg interesting += 'W' 413246149Ssjg """ 414246149Ssjg elif w[0] == 'CWD': 415246149Ssjg self.cwd = cwd = last_dir = w[1] 416246149Ssjg self.seenit(cwd) # ignore this 417246149Ssjg if self.debug: 418261212Ssjg print("%s: CWD=%s" % (self.name, cwd), file=self.debug_out) 419246149Ssjg continue 420246149Ssjg 421246149Ssjg pid = int(w[1]) 422246149Ssjg if pid != last_pid: 423246149Ssjg if last_pid: 424246149Ssjg pid_cwd[last_pid] = cwd 425246149Ssjg pid_last_dir[last_pid] = last_dir 426246149Ssjg cwd = getv(pid_cwd, pid, self.cwd) 427246149Ssjg last_dir = getv(pid_last_dir, pid, self.cwd) 428246149Ssjg last_pid = pid 429246149Ssjg 430246149Ssjg # process operations 431246149Ssjg if w[0] == 'F': 432246149Ssjg npid = int(w[2]) 433246149Ssjg pid_cwd[npid] = cwd 434246149Ssjg pid_last_dir[npid] = cwd 435246149Ssjg last_pid = npid 436246149Ssjg continue 437246149Ssjg elif w[0] == 'C': 438246149Ssjg cwd = abspath(w[2], cwd, None, self.debug, self.debug_out) 439246149Ssjg if cwd.endswith('/.'): 440246149Ssjg cwd = cwd[0:-2] 441246149Ssjg last_dir = cwd 442246149Ssjg if self.debug > 1: 443261212Ssjg print("cwd=", cwd, file=self.debug_out) 444246149Ssjg continue 445246149Ssjg 446246149Ssjg if w[2] in self.seen: 447246149Ssjg if self.debug > 2: 448261212Ssjg print("seen:", w[2], file=self.debug_out) 449246149Ssjg continue 450246149Ssjg # file operations 451246149Ssjg if w[0] in 'ML': 452246149Ssjg path = w[2].strip("'") 453246149Ssjg else: 454246149Ssjg path = w[2] 455246149Ssjg # we are never interested in .dirdep files as dependencies 456246149Ssjg if path.endswith('.dirdep'): 457246149Ssjg continue 458246149Ssjg # we don't want to resolve the last component if it is 459246149Ssjg # a symlink 460246149Ssjg path = resolve(path, cwd, last_dir, self.debug, self.debug_out) 461246149Ssjg if not path: 462246149Ssjg continue 463246149Ssjg dir,base = os.path.split(path) 464246149Ssjg if dir in self.seen: 465246149Ssjg if self.debug > 2: 466261212Ssjg print("seen:", dir, file=self.debug_out) 467246149Ssjg continue 468246149Ssjg # we can have a path in an objdir which is a link 469246149Ssjg # to the src dir, we may need to add dependencies for each 470246149Ssjg rdir = dir 471246149Ssjg dir = abspath(dir, cwd, last_dir, self.debug, self.debug_out) 472246149Ssjg if rdir == dir or rdir.find('./') > 0: 473246149Ssjg rdir = None 474246149Ssjg # now put path back together 475246149Ssjg path = '/'.join([dir,base]) 476246149Ssjg if self.debug > 1: 477261212Ssjg print("raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path), file=self.debug_out) 478246149Ssjg if w[0] in 'SRWL': 479246149Ssjg if w[0] == 'W' and path.endswith('.dirdep'): 480246149Ssjg continue 481246149Ssjg if path in [last_dir, cwd, self.cwd, self.curdir]: 482246149Ssjg if self.debug > 1: 483261212Ssjg print("skipping:", path, file=self.debug_out) 484246149Ssjg continue 485246149Ssjg if os.path.isdir(path): 486246149Ssjg if w[0] in 'RW': 487246149Ssjg last_dir = path; 488246149Ssjg if self.debug > 1: 489261212Ssjg print("ldir=", last_dir, file=self.debug_out) 490246149Ssjg continue 491246149Ssjg 492246149Ssjg if w[0] in 'REWML': 493246149Ssjg # finally, we get down to it 494246149Ssjg if dir == self.cwd or dir == self.curdir: 495246149Ssjg continue 496246149Ssjg srctop = self.find_top(path, self.srctops) 497246149Ssjg if srctop: 498246149Ssjg if self.dpdeps: 499246149Ssjg self.add(self.file_deps, path.replace(srctop,''), 'file') 500246149Ssjg self.add(self.src_deps, dir.replace(srctop,''), 'src') 501246149Ssjg self.seenit(w[2]) 502246149Ssjg self.seenit(dir) 503246149Ssjg if rdir and not rdir.startswith(srctop): 504246149Ssjg dir = rdir # for below 505246149Ssjg rdir = None 506246149Ssjg else: 507246149Ssjg continue 508246149Ssjg 509246149Ssjg objroot = None 510246149Ssjg for dir in [dir,rdir]: 511246149Ssjg if not dir: 512246149Ssjg continue 513246149Ssjg objroot = self.find_top(dir, self.objroots) 514246149Ssjg if objroot: 515246149Ssjg break 516246149Ssjg if objroot: 517246149Ssjg ddep = self.find_obj(objroot, dir, path, w[2]) 518246149Ssjg if ddep: 519246149Ssjg self.add(self.obj_deps, ddep, 'obj') 520246149Ssjg else: 521246149Ssjg # don't waste time looking again 522246149Ssjg self.seenit(w[2]) 523246149Ssjg self.seenit(dir) 524246149Ssjg if not file: 525246149Ssjg f.close() 526246149Ssjg 527246149Ssjg 528246149Ssjgdef main(argv, klass=MetaFile, xopts='', xoptf=None): 529246149Ssjg """Simple driver for class MetaFile. 530246149Ssjg 531246149Ssjg Usage: 532246149Ssjg script [options] [key=value ...] "meta" ... 533246149Ssjg 534246149Ssjg Options and key=value pairs contribute to the 535246149Ssjg dictionary passed to MetaFile. 536246149Ssjg 537246149Ssjg -S "SRCTOP" 538246149Ssjg add "SRCTOP" to the "SRCTOPS" list. 539246149Ssjg 540246149Ssjg -C "CURDIR" 541246149Ssjg 542246149Ssjg -O "OBJROOT" 543246149Ssjg add "OBJROOT" to the "OBJROOTS" list. 544246149Ssjg 545246149Ssjg -m "MACHINE" 546246149Ssjg 547250837Ssjg -a "MACHINE_ARCH" 548250837Ssjg 549246149Ssjg -H "HOST_TARGET" 550246149Ssjg 551246149Ssjg -D "DPDEPS" 552246149Ssjg 553246149Ssjg -d bumps debug level 554246149Ssjg 555246149Ssjg """ 556246149Ssjg import getopt 557246149Ssjg 558246149Ssjg # import Psyco if we can 559246149Ssjg # it can speed things up quite a bit 560246149Ssjg have_psyco = 0 561246149Ssjg try: 562246149Ssjg import psyco 563246149Ssjg psyco.full() 564246149Ssjg have_psyco = 1 565246149Ssjg except: 566246149Ssjg pass 567246149Ssjg 568246149Ssjg conf = { 569246149Ssjg 'SRCTOPS': [], 570246149Ssjg 'OBJROOTS': [], 571246149Ssjg } 572246149Ssjg 573246149Ssjg try: 574246149Ssjg machine = os.environ['MACHINE'] 575246149Ssjg if machine: 576246149Ssjg conf['MACHINE'] = machine 577250837Ssjg machine_arch = os.environ['MACHINE_ARCH'] 578250837Ssjg if machine_arch: 579250837Ssjg conf['MACHINE_ARCH'] = machine_arch 580246149Ssjg srctop = os.environ['SB_SRC'] 581246149Ssjg if srctop: 582246149Ssjg conf['SRCTOPS'].append(srctop) 583246149Ssjg objroot = os.environ['SB_OBJROOT'] 584246149Ssjg if objroot: 585246149Ssjg conf['OBJROOTS'].append(objroot) 586246149Ssjg except: 587246149Ssjg pass 588246149Ssjg 589246149Ssjg debug = 0 590246149Ssjg output = True 591246149Ssjg 592250837Ssjg opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:' + xopts) 593246149Ssjg for o, a in opts: 594250837Ssjg if o == '-a': 595250837Ssjg conf['MACHINE_ARCH'] = a 596250837Ssjg elif o == '-d': 597246149Ssjg debug += 1 598246149Ssjg elif o == '-q': 599246149Ssjg output = False 600246149Ssjg elif o == '-H': 601246149Ssjg conf['HOST_TARGET'] = a 602246149Ssjg elif o == '-S': 603246149Ssjg if a not in conf['SRCTOPS']: 604246149Ssjg conf['SRCTOPS'].append(a) 605246149Ssjg elif o == '-C': 606246149Ssjg conf['CURDIR'] = a 607246149Ssjg elif o == '-O': 608246149Ssjg if a not in conf['OBJROOTS']: 609246149Ssjg conf['OBJROOTS'].append(a) 610246149Ssjg elif o == '-R': 611246149Ssjg conf['RELDIR'] = a 612246149Ssjg elif o == '-D': 613246149Ssjg conf['DPDEPS'] = a 614246149Ssjg elif o == '-m': 615246149Ssjg conf['MACHINE'] = a 616250837Ssjg elif o == '-T': 617250837Ssjg conf['TARGET_SPEC'] = a 618246149Ssjg elif xoptf: 619246149Ssjg xoptf(o, a, conf) 620246149Ssjg 621246149Ssjg conf['debug'] = debug 622246149Ssjg 623246149Ssjg # get any var=val assignments 624246149Ssjg eaten = [] 625246149Ssjg for a in args: 626246149Ssjg if a.find('=') > 0: 627246149Ssjg k,v = a.split('=') 628246149Ssjg if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']: 629246149Ssjg if k == 'SRCTOP': 630246149Ssjg k = 'SRCTOPS' 631246149Ssjg elif k == 'OBJROOT': 632246149Ssjg k = 'OBJROOTS' 633246149Ssjg if v not in conf[k]: 634246149Ssjg conf[k].append(v) 635246149Ssjg else: 636246149Ssjg conf[k] = v 637246149Ssjg eaten.append(a) 638246149Ssjg continue 639246149Ssjg break 640246149Ssjg 641246149Ssjg for a in eaten: 642246149Ssjg args.remove(a) 643246149Ssjg 644246149Ssjg debug_out = getv(conf, 'debug_out', sys.stderr) 645246149Ssjg 646246149Ssjg if debug: 647261212Ssjg print("config:", file=debug_out) 648261212Ssjg print("psyco=", have_psyco, file=debug_out) 649261212Ssjg for k,v in list(conf.items()): 650261212Ssjg print("%s=%s" % (k,v), file=debug_out) 651246149Ssjg 652246149Ssjg for a in args: 653253883Ssjg if a.endswith('.meta'): 654253883Ssjg m = klass(a, conf) 655253883Ssjg elif a.startswith('@'): 656253883Ssjg # there can actually multiple files per line 657253883Ssjg for line in open(a[1:]): 658253883Ssjg for f in line.strip().split(): 659253883Ssjg m = klass(f, conf) 660246149Ssjg 661246149Ssjg if output: 662261212Ssjg print(m.dirdeps()) 663246149Ssjg 664261212Ssjg print(m.src_dirdeps('\nsrc:')) 665246149Ssjg 666246149Ssjg dpdeps = getv(conf, 'DPDEPS') 667246149Ssjg if dpdeps: 668246149Ssjg m.file_depends(open(dpdeps, 'wb')) 669246149Ssjg 670246149Ssjg return m 671246149Ssjg 672246149Ssjgif __name__ == '__main__': 673246149Ssjg try: 674246149Ssjg main(sys.argv) 675246149Ssjg except: 676246149Ssjg # yes, this goes to stdout 677261212Ssjg print("ERROR: ", sys.exc_info()[1]) 678246149Ssjg raise 679246149Ssjg 680