1ccfb9654SSimon J. Gerraty# $FreeBSD$ 27750ad47SMarcel Moolenaar#!/usr/bin/env python 37750ad47SMarcel Moolenaar 410ea6facSSimon J. Gerratyfrom __future__ import print_function 510ea6facSSimon J. Gerraty 67750ad47SMarcel Moolenaar""" 77750ad47SMarcel MoolenaarThis script parses each "meta" file and extracts the 87750ad47SMarcel Moolenaarinformation needed to deduce build and src dependencies. 97750ad47SMarcel Moolenaar 107750ad47SMarcel MoolenaarIt works much the same as the original shell script, but is 117750ad47SMarcel Moolenaar*much* more efficient. 127750ad47SMarcel Moolenaar 137750ad47SMarcel MoolenaarThe parsing work is handled by the class MetaFile. 147750ad47SMarcel MoolenaarWe only pay attention to a subset of the information in the 157750ad47SMarcel Moolenaar"meta" files. Specifically: 167750ad47SMarcel Moolenaar 177750ad47SMarcel Moolenaar'CWD' to initialize our notion. 187750ad47SMarcel Moolenaar 197750ad47SMarcel Moolenaar'C' to track chdir(2) on a per process basis 207750ad47SMarcel Moolenaar 217750ad47SMarcel Moolenaar'R' files read are what we really care about. 227750ad47SMarcel Moolenaar directories read, provide a clue to resolving 237750ad47SMarcel Moolenaar subsequent relative paths. That is if we cannot find 247750ad47SMarcel Moolenaar them relative to 'cwd', we check relative to the last 257750ad47SMarcel Moolenaar dir read. 267750ad47SMarcel Moolenaar 277750ad47SMarcel Moolenaar'W' files opened for write or read-write, 287750ad47SMarcel Moolenaar for filemon V3 and earlier. 297750ad47SMarcel Moolenaar 307750ad47SMarcel Moolenaar'E' files executed. 317750ad47SMarcel Moolenaar 327750ad47SMarcel Moolenaar'L' files linked 337750ad47SMarcel Moolenaar 347750ad47SMarcel Moolenaar'V' the filemon version, this record is used as a clue 357750ad47SMarcel Moolenaar that we have reached the interesting bit. 367750ad47SMarcel Moolenaar 377750ad47SMarcel Moolenaar""" 387750ad47SMarcel Moolenaar 397750ad47SMarcel Moolenaar""" 407750ad47SMarcel MoolenaarRCSid: 41*e1dfa657SBryan Drewery $Id: meta2deps.py,v 1.19 2016/04/02 20:45:40 sjg Exp $ 427750ad47SMarcel Moolenaar 434ed4429cSSimon J. Gerraty Copyright (c) 2011-2013, Juniper Networks, Inc. 444ed4429cSSimon J. Gerraty All rights reserved. 457750ad47SMarcel Moolenaar 467750ad47SMarcel Moolenaar Redistribution and use in source and binary forms, with or without 477750ad47SMarcel Moolenaar modification, are permitted provided that the following conditions 487750ad47SMarcel Moolenaar are met: 497750ad47SMarcel Moolenaar 1. Redistributions of source code must retain the above copyright 507750ad47SMarcel Moolenaar notice, this list of conditions and the following disclaimer. 517750ad47SMarcel Moolenaar 2. Redistributions in binary form must reproduce the above copyright 527750ad47SMarcel Moolenaar notice, this list of conditions and the following disclaimer in the 537750ad47SMarcel Moolenaar documentation and/or other materials provided with the distribution. 547750ad47SMarcel Moolenaar 557750ad47SMarcel Moolenaar THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 567750ad47SMarcel Moolenaar "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 577750ad47SMarcel Moolenaar LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 587750ad47SMarcel Moolenaar A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 597750ad47SMarcel Moolenaar OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 607750ad47SMarcel Moolenaar SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 617750ad47SMarcel Moolenaar LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 627750ad47SMarcel Moolenaar DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 637750ad47SMarcel Moolenaar THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 647750ad47SMarcel Moolenaar (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 657750ad47SMarcel Moolenaar OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 667750ad47SMarcel Moolenaar 677750ad47SMarcel Moolenaar""" 687750ad47SMarcel Moolenaar 697750ad47SMarcel Moolenaarimport os, re, sys 707750ad47SMarcel Moolenaar 717750ad47SMarcel Moolenaardef getv(dict, key, d=None): 727750ad47SMarcel Moolenaar """Lookup key in dict and return value or the supplied default.""" 737750ad47SMarcel Moolenaar if key in dict: 747750ad47SMarcel Moolenaar return dict[key] 757750ad47SMarcel Moolenaar return d 767750ad47SMarcel Moolenaar 777750ad47SMarcel Moolenaardef resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr): 787750ad47SMarcel Moolenaar """ 797750ad47SMarcel Moolenaar Return an absolute path, resolving via cwd or last_dir if needed. 807750ad47SMarcel Moolenaar """ 817750ad47SMarcel Moolenaar if path.endswith('/.'): 827750ad47SMarcel Moolenaar path = path[0:-2] 83d5ddb276SSimon J. Gerraty if len(path) > 0 and path[0] == '/': 847750ad47SMarcel Moolenaar return path 857750ad47SMarcel Moolenaar if path == '.': 867750ad47SMarcel Moolenaar return cwd 877750ad47SMarcel Moolenaar if path.startswith('./'): 887750ad47SMarcel Moolenaar return cwd + path[1:] 897750ad47SMarcel Moolenaar if last_dir == cwd: 907750ad47SMarcel Moolenaar last_dir = None 917750ad47SMarcel Moolenaar for d in [last_dir, cwd]: 927750ad47SMarcel Moolenaar if not d: 937750ad47SMarcel Moolenaar continue 947750ad47SMarcel Moolenaar p = '/'.join([d,path]) 957750ad47SMarcel Moolenaar if debug > 2: 9610ea6facSSimon J. Gerraty print("looking for:", p, end=' ', file=debug_out) 977750ad47SMarcel Moolenaar if not os.path.exists(p): 987750ad47SMarcel Moolenaar if debug > 2: 9910ea6facSSimon J. Gerraty print("nope", file=debug_out) 1007750ad47SMarcel Moolenaar p = None 1017750ad47SMarcel Moolenaar continue 1027750ad47SMarcel Moolenaar if debug > 2: 10310ea6facSSimon J. Gerraty print("found:", p, file=debug_out) 1047750ad47SMarcel Moolenaar return p 1057750ad47SMarcel Moolenaar return None 1067750ad47SMarcel Moolenaar 1077750ad47SMarcel Moolenaardef abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr): 1087750ad47SMarcel Moolenaar """ 1097750ad47SMarcel Moolenaar Return an absolute path, resolving via cwd or last_dir if needed. 1107750ad47SMarcel Moolenaar this gets called a lot, so we try to avoid calling realpath 1117750ad47SMarcel Moolenaar until we know we have something. 1127750ad47SMarcel Moolenaar """ 113d5ddb276SSimon J. Gerraty rpath = resolve(path, cwd, last_dir, debug, debug_out) 114d5ddb276SSimon J. Gerraty if rpath: 115d5ddb276SSimon J. Gerraty path = rpath 116ccfb9654SSimon J. Gerraty if (path.find('/') < 0 or 117ccfb9654SSimon J. Gerraty path.find('./') > 0 or 1187750ad47SMarcel Moolenaar path.endswith('/..') or 1197750ad47SMarcel Moolenaar os.path.islink(path)): 1207750ad47SMarcel Moolenaar return os.path.realpath(path) 1217750ad47SMarcel Moolenaar return path 1227750ad47SMarcel Moolenaar 1237750ad47SMarcel Moolenaardef sort_unique(list, cmp=None, key=None, reverse=False): 1247750ad47SMarcel Moolenaar list.sort(cmp, key, reverse) 1257750ad47SMarcel Moolenaar nl = [] 1267750ad47SMarcel Moolenaar le = None 1277750ad47SMarcel Moolenaar for e in list: 1287750ad47SMarcel Moolenaar if e == le: 1297750ad47SMarcel Moolenaar continue 1307750ad47SMarcel Moolenaar nl.append(e) 1317750ad47SMarcel Moolenaar return nl 1327750ad47SMarcel Moolenaar 133bf062775SSimon J. Gerratydef add_trims(x): 134bf062775SSimon J. Gerraty return ['/' + x + '/', 135bf062775SSimon J. Gerraty '/' + x, 136bf062775SSimon J. Gerraty x + '/', 137bf062775SSimon J. Gerraty x] 138bf062775SSimon J. Gerraty 1397750ad47SMarcel Moolenaarclass MetaFile: 1407750ad47SMarcel Moolenaar """class to parse meta files generated by bmake.""" 1417750ad47SMarcel Moolenaar 1427750ad47SMarcel Moolenaar conf = None 1437750ad47SMarcel Moolenaar dirdep_re = None 1447750ad47SMarcel Moolenaar host_target = None 1457750ad47SMarcel Moolenaar srctops = [] 1467750ad47SMarcel Moolenaar objroots = [] 147ccfb9654SSimon J. Gerraty excludes = [] 1487750ad47SMarcel Moolenaar seen = {} 1497750ad47SMarcel Moolenaar obj_deps = [] 1507750ad47SMarcel Moolenaar src_deps = [] 1517750ad47SMarcel Moolenaar file_deps = [] 1527750ad47SMarcel Moolenaar 1537750ad47SMarcel Moolenaar def __init__(self, name, conf={}): 1547750ad47SMarcel Moolenaar """if name is set we will parse it now. 1557750ad47SMarcel Moolenaar conf can have the follwing keys: 1567750ad47SMarcel Moolenaar 1577750ad47SMarcel Moolenaar SRCTOPS list of tops of the src tree(s). 1587750ad47SMarcel Moolenaar 1597750ad47SMarcel Moolenaar CURDIR the src directory 'bmake' was run from. 1607750ad47SMarcel Moolenaar 1617750ad47SMarcel Moolenaar RELDIR the relative path from SRCTOP to CURDIR 1627750ad47SMarcel Moolenaar 1637750ad47SMarcel Moolenaar MACHINE the machine we built for. 1647750ad47SMarcel Moolenaar set to 'none' if we are not cross-building. 16551048477SSimon J. Gerraty More specifically if machine cannot be deduced from objdirs. 1667750ad47SMarcel Moolenaar 167bf062775SSimon J. Gerraty TARGET_SPEC 168bf062775SSimon J. Gerraty Sometimes MACHINE isn't enough. 169bf062775SSimon J. Gerraty 1707750ad47SMarcel Moolenaar HOST_TARGET 171ccfb9654SSimon J. Gerraty when we build for the pseudo machine 'host' 1727750ad47SMarcel Moolenaar the object tree uses HOST_TARGET rather than MACHINE. 1737750ad47SMarcel Moolenaar 1747750ad47SMarcel Moolenaar OBJROOTS a list of the common prefix for all obj dirs it might 1757750ad47SMarcel Moolenaar end in '/' or '-'. 1767750ad47SMarcel Moolenaar 1777750ad47SMarcel Moolenaar DPDEPS names an optional file to which per file dependencies 1787750ad47SMarcel Moolenaar will be appended. 1797750ad47SMarcel Moolenaar For example if 'some/path/foo.h' is read from SRCTOP 1807750ad47SMarcel Moolenaar then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output. 1817750ad47SMarcel Moolenaar This can allow 'bmake' to learn all the dirs within 1827750ad47SMarcel Moolenaar the tree that depend on 'foo.h' 1837750ad47SMarcel Moolenaar 184ccfb9654SSimon J. Gerraty EXCLUDES 185ccfb9654SSimon J. Gerraty A list of paths to ignore. 186ccfb9654SSimon J. Gerraty ccache(1) can otherwise be trouble. 187ccfb9654SSimon J. Gerraty 1887750ad47SMarcel Moolenaar debug desired debug level 1897750ad47SMarcel Moolenaar 1907750ad47SMarcel Moolenaar debug_out open file to send debug output to (sys.stderr) 1917750ad47SMarcel Moolenaar 1927750ad47SMarcel Moolenaar """ 1937750ad47SMarcel Moolenaar 1947750ad47SMarcel Moolenaar self.name = name 1957750ad47SMarcel Moolenaar self.debug = getv(conf, 'debug', 0) 1967750ad47SMarcel Moolenaar self.debug_out = getv(conf, 'debug_out', sys.stderr) 1977750ad47SMarcel Moolenaar 1984ed4429cSSimon J. Gerraty self.machine = getv(conf, 'MACHINE', '') 199bf062775SSimon J. Gerraty self.machine_arch = getv(conf, 'MACHINE_ARCH', '') 200bf062775SSimon J. Gerraty self.target_spec = getv(conf, 'TARGET_SPEC', '') 20151048477SSimon J. Gerraty self.curdir = getv(conf, 'CURDIR') 20251048477SSimon J. Gerraty self.reldir = getv(conf, 'RELDIR') 20351048477SSimon J. Gerraty self.dpdeps = getv(conf, 'DPDEPS') 204d5ddb276SSimon J. Gerraty self.line = 0 2054ed4429cSSimon J. Gerraty 2067750ad47SMarcel Moolenaar if not self.conf: 2077750ad47SMarcel Moolenaar # some of the steps below we want to do only once 2087750ad47SMarcel Moolenaar self.conf = conf 2097750ad47SMarcel Moolenaar self.host_target = getv(conf, 'HOST_TARGET') 2107750ad47SMarcel Moolenaar for srctop in getv(conf, 'SRCTOPS', []): 2117750ad47SMarcel Moolenaar if srctop[-1] != '/': 2127750ad47SMarcel Moolenaar srctop += '/' 2137750ad47SMarcel Moolenaar if not srctop in self.srctops: 2147750ad47SMarcel Moolenaar self.srctops.append(srctop) 215fbc1b149SSimon J. Gerraty _srctop = os.path.realpath(srctop) 216fbc1b149SSimon J. Gerraty if _srctop[-1] != '/': 217fbc1b149SSimon J. Gerraty _srctop += '/' 218fbc1b149SSimon J. Gerraty if not _srctop in self.srctops: 219fbc1b149SSimon J. Gerraty self.srctops.append(_srctop) 2207750ad47SMarcel Moolenaar 221bf062775SSimon J. Gerraty trim_list = add_trims(self.machine) 2228c95c434SSimon J. Gerraty if self.machine == 'host': 223bf062775SSimon J. Gerraty trim_list += add_trims(self.host_target) 224bf062775SSimon J. Gerraty if self.target_spec: 225bf062775SSimon J. Gerraty trim_list += add_trims(self.target_spec) 226876336c8SSimon J. Gerraty 2277750ad47SMarcel Moolenaar for objroot in getv(conf, 'OBJROOTS', []): 2288c95c434SSimon J. Gerraty for e in trim_list: 2294ed4429cSSimon J. Gerraty if objroot.endswith(e): 2304ed4429cSSimon J. Gerraty # this is not what we want - fix it 2314ed4429cSSimon J. Gerraty objroot = objroot[0:-len(e)] 2324ed4429cSSimon J. Gerraty if e.endswith('/'): 2334ed4429cSSimon J. Gerraty objroot += '/' 2347750ad47SMarcel Moolenaar if not objroot in self.objroots: 2357750ad47SMarcel Moolenaar self.objroots.append(objroot) 2367750ad47SMarcel Moolenaar _objroot = os.path.realpath(objroot) 2377750ad47SMarcel Moolenaar if objroot[-1] == '/': 2387750ad47SMarcel Moolenaar _objroot += '/' 2397750ad47SMarcel Moolenaar if not _objroot in self.objroots: 2407750ad47SMarcel Moolenaar self.objroots.append(_objroot) 2417750ad47SMarcel Moolenaar 2424ed4429cSSimon J. Gerraty # we want the longest match 2434ed4429cSSimon J. Gerraty self.srctops.sort(reverse=True) 2444ed4429cSSimon J. Gerraty self.objroots.sort(reverse=True) 2454ed4429cSSimon J. Gerraty 246ccfb9654SSimon J. Gerraty self.excludes = getv(conf, 'EXCLUDES', []) 247ccfb9654SSimon J. Gerraty 2487750ad47SMarcel Moolenaar if self.debug: 24910ea6facSSimon J. Gerraty print("host_target=", self.host_target, file=self.debug_out) 25010ea6facSSimon J. Gerraty print("srctops=", self.srctops, file=self.debug_out) 25110ea6facSSimon J. Gerraty print("objroots=", self.objroots, file=self.debug_out) 252ccfb9654SSimon J. Gerraty print("excludes=", self.excludes, file=self.debug_out) 2537750ad47SMarcel Moolenaar 2547750ad47SMarcel Moolenaar self.dirdep_re = re.compile(r'([^/]+)/(.+)') 2557750ad47SMarcel Moolenaar 2567750ad47SMarcel Moolenaar if self.dpdeps and not self.reldir: 2577750ad47SMarcel Moolenaar if self.debug: 25810ea6facSSimon J. Gerraty print("need reldir:", end=' ', file=self.debug_out) 2597750ad47SMarcel Moolenaar if self.curdir: 2607750ad47SMarcel Moolenaar srctop = self.find_top(self.curdir, self.srctops) 2617750ad47SMarcel Moolenaar if srctop: 2627750ad47SMarcel Moolenaar self.reldir = self.curdir.replace(srctop,'') 2637750ad47SMarcel Moolenaar if self.debug: 26410ea6facSSimon J. Gerraty print(self.reldir, file=self.debug_out) 2657750ad47SMarcel Moolenaar if not self.reldir: 2667750ad47SMarcel Moolenaar self.dpdeps = None # we cannot do it? 2677750ad47SMarcel Moolenaar 268876336c8SSimon J. Gerraty self.cwd = os.getcwd() # make sure this is initialized 269ccfb9654SSimon J. Gerraty self.last_dir = self.cwd 270876336c8SSimon J. Gerraty 2717750ad47SMarcel Moolenaar if name: 272d5ddb276SSimon J. Gerraty self.try_parse() 2737750ad47SMarcel Moolenaar 2747750ad47SMarcel Moolenaar def reset(self): 2757750ad47SMarcel Moolenaar """reset state if we are being passed meta files from multiple directories.""" 2767750ad47SMarcel Moolenaar self.seen = {} 2777750ad47SMarcel Moolenaar self.obj_deps = [] 2787750ad47SMarcel Moolenaar self.src_deps = [] 2797750ad47SMarcel Moolenaar self.file_deps = [] 2807750ad47SMarcel Moolenaar 2817750ad47SMarcel Moolenaar def dirdeps(self, sep='\n'): 2827750ad47SMarcel Moolenaar """return DIRDEPS""" 2837750ad47SMarcel Moolenaar return sep.strip() + sep.join(self.obj_deps) 2847750ad47SMarcel Moolenaar 2857750ad47SMarcel Moolenaar def src_dirdeps(self, sep='\n'): 2867750ad47SMarcel Moolenaar """return SRC_DIRDEPS""" 2877750ad47SMarcel Moolenaar return sep.strip() + sep.join(self.src_deps) 2887750ad47SMarcel Moolenaar 2897750ad47SMarcel Moolenaar def file_depends(self, out=None): 2907750ad47SMarcel Moolenaar """Append DPDEPS_${file} += ${RELDIR} 2917750ad47SMarcel Moolenaar for each file we saw, to the output file.""" 2927750ad47SMarcel Moolenaar if not self.reldir: 2937750ad47SMarcel Moolenaar return None 2947750ad47SMarcel Moolenaar for f in sort_unique(self.file_deps): 29510ea6facSSimon J. Gerraty print('DPDEPS_%s += %s' % (f, self.reldir), file=out) 2967750ad47SMarcel Moolenaar 2977750ad47SMarcel Moolenaar def seenit(self, dir): 2987750ad47SMarcel Moolenaar """rememer that we have seen dir.""" 2997750ad47SMarcel Moolenaar self.seen[dir] = 1 3007750ad47SMarcel Moolenaar 3017750ad47SMarcel Moolenaar def add(self, list, data, clue=''): 3027750ad47SMarcel Moolenaar """add data to list if it isn't already there.""" 3037750ad47SMarcel Moolenaar if data not in list: 3047750ad47SMarcel Moolenaar list.append(data) 3057750ad47SMarcel Moolenaar if self.debug: 30610ea6facSSimon J. Gerraty print("%s: %sAdd: %s" % (self.name, clue, data), file=self.debug_out) 3077750ad47SMarcel Moolenaar 3087750ad47SMarcel Moolenaar def find_top(self, path, list): 309ccfb9654SSimon J. Gerraty """the logical tree may be split across multiple trees""" 3107750ad47SMarcel Moolenaar for top in list: 3117750ad47SMarcel Moolenaar if path.startswith(top): 3127750ad47SMarcel Moolenaar if self.debug > 2: 31310ea6facSSimon J. Gerraty print("found in", top, file=self.debug_out) 3147750ad47SMarcel Moolenaar return top 3157750ad47SMarcel Moolenaar return None 3167750ad47SMarcel Moolenaar 3177750ad47SMarcel Moolenaar def find_obj(self, objroot, dir, path, input): 3187750ad47SMarcel Moolenaar """return path within objroot, taking care of .dirdep files""" 3197750ad47SMarcel Moolenaar ddep = None 3207750ad47SMarcel Moolenaar for ddepf in [path + '.dirdep', dir + '/.dirdep']: 3217750ad47SMarcel Moolenaar if not ddep and os.path.exists(ddepf): 32210ea6facSSimon J. Gerraty ddep = open(ddepf, 'r').readline().strip('# \n') 3237750ad47SMarcel Moolenaar if self.debug > 1: 32410ea6facSSimon J. Gerraty print("found %s: %s\n" % (ddepf, ddep), file=self.debug_out) 3257750ad47SMarcel Moolenaar if ddep.endswith(self.machine): 3267750ad47SMarcel Moolenaar ddep = ddep[0:-(1+len(self.machine))] 327bf062775SSimon J. Gerraty elif self.target_spec and ddep.endswith(self.target_spec): 328bf062775SSimon J. Gerraty ddep = ddep[0:-(1+len(self.target_spec))] 3297750ad47SMarcel Moolenaar 3307750ad47SMarcel Moolenaar if not ddep: 3317750ad47SMarcel Moolenaar # no .dirdeps, so remember that we've seen the raw input 3327750ad47SMarcel Moolenaar self.seenit(input) 3337750ad47SMarcel Moolenaar self.seenit(dir) 3347750ad47SMarcel Moolenaar if self.machine == 'none': 3357750ad47SMarcel Moolenaar if dir.startswith(objroot): 3367750ad47SMarcel Moolenaar return dir.replace(objroot,'') 3377750ad47SMarcel Moolenaar return None 3387750ad47SMarcel Moolenaar m = self.dirdep_re.match(dir.replace(objroot,'')) 3397750ad47SMarcel Moolenaar if m: 3407750ad47SMarcel Moolenaar ddep = m.group(2) 3417750ad47SMarcel Moolenaar dmachine = m.group(1) 3427750ad47SMarcel Moolenaar if dmachine != self.machine: 3437750ad47SMarcel Moolenaar if not (self.machine == 'host' and 3447750ad47SMarcel Moolenaar dmachine == self.host_target): 3457750ad47SMarcel Moolenaar if self.debug > 2: 34610ea6facSSimon J. Gerraty print("adding .%s to %s" % (dmachine, ddep), file=self.debug_out) 3477750ad47SMarcel Moolenaar ddep += '.' + dmachine 3487750ad47SMarcel Moolenaar 3497750ad47SMarcel Moolenaar return ddep 3507750ad47SMarcel Moolenaar 351d5ddb276SSimon J. Gerraty def try_parse(self, name=None, file=None): 352d5ddb276SSimon J. Gerraty """give file and line number causing exception""" 353d5ddb276SSimon J. Gerraty try: 354d5ddb276SSimon J. Gerraty self.parse(name, file) 355d5ddb276SSimon J. Gerraty except: 356d5ddb276SSimon J. Gerraty # give a useful clue 35710ea6facSSimon J. Gerraty print('{}:{}: '.format(self.name, self.line), end=' ', file=sys.stderr) 358d5ddb276SSimon J. Gerraty raise 359d5ddb276SSimon J. Gerraty 3607750ad47SMarcel Moolenaar def parse(self, name=None, file=None): 3617750ad47SMarcel Moolenaar """A meta file looks like: 3627750ad47SMarcel Moolenaar 3637750ad47SMarcel Moolenaar # Meta data file "path" 3647750ad47SMarcel Moolenaar CMD "command-line" 3657750ad47SMarcel Moolenaar CWD "cwd" 3667750ad47SMarcel Moolenaar TARGET "target" 3677750ad47SMarcel Moolenaar -- command output -- 3687750ad47SMarcel Moolenaar -- filemon acquired metadata -- 3697750ad47SMarcel Moolenaar # buildmon version 3 3707750ad47SMarcel Moolenaar V 3 3717750ad47SMarcel Moolenaar C "pid" "cwd" 3727750ad47SMarcel Moolenaar E "pid" "path" 3737750ad47SMarcel Moolenaar F "pid" "child" 3747750ad47SMarcel Moolenaar R "pid" "path" 3757750ad47SMarcel Moolenaar W "pid" "path" 3767750ad47SMarcel Moolenaar X "pid" "status" 3777750ad47SMarcel Moolenaar D "pid" "path" 3787750ad47SMarcel Moolenaar L "pid" "src" "target" 3797750ad47SMarcel Moolenaar M "pid" "old" "new" 3807750ad47SMarcel Moolenaar S "pid" "path" 3817750ad47SMarcel Moolenaar # Bye bye 3827750ad47SMarcel Moolenaar 3837750ad47SMarcel Moolenaar We go to some effort to avoid processing a dependency more than once. 3847750ad47SMarcel Moolenaar Of the above record types only C,E,F,L,R,V and W are of interest. 3857750ad47SMarcel Moolenaar """ 3867750ad47SMarcel Moolenaar 3877750ad47SMarcel Moolenaar version = 0 # unknown 3887750ad47SMarcel Moolenaar if name: 3897750ad47SMarcel Moolenaar self.name = name; 3907750ad47SMarcel Moolenaar if file: 3917750ad47SMarcel Moolenaar f = file 392ccfb9654SSimon J. Gerraty cwd = self.last_dir = self.cwd 3937750ad47SMarcel Moolenaar else: 39410ea6facSSimon J. Gerraty f = open(self.name, 'r') 3957750ad47SMarcel Moolenaar skip = True 3967750ad47SMarcel Moolenaar pid_cwd = {} 3977750ad47SMarcel Moolenaar pid_last_dir = {} 3987750ad47SMarcel Moolenaar last_pid = 0 3997750ad47SMarcel Moolenaar 400d5ddb276SSimon J. Gerraty self.line = 0 4017750ad47SMarcel Moolenaar if self.curdir: 4027750ad47SMarcel Moolenaar self.seenit(self.curdir) # we ignore this 4037750ad47SMarcel Moolenaar 4047750ad47SMarcel Moolenaar interesting = 'CEFLRV' 4057750ad47SMarcel Moolenaar for line in f: 406d5ddb276SSimon J. Gerraty self.line += 1 4077750ad47SMarcel Moolenaar # ignore anything we don't care about 4087750ad47SMarcel Moolenaar if not line[0] in interesting: 4097750ad47SMarcel Moolenaar continue 4107750ad47SMarcel Moolenaar if self.debug > 2: 41110ea6facSSimon J. Gerraty print("input:", line, end=' ', file=self.debug_out) 4127750ad47SMarcel Moolenaar w = line.split() 4137750ad47SMarcel Moolenaar 4147750ad47SMarcel Moolenaar if skip: 4157750ad47SMarcel Moolenaar if w[0] == 'V': 4167750ad47SMarcel Moolenaar skip = False 4177750ad47SMarcel Moolenaar version = int(w[1]) 4187750ad47SMarcel Moolenaar """ 4197750ad47SMarcel Moolenaar if version < 4: 4207750ad47SMarcel Moolenaar # we cannot ignore 'W' records 4217750ad47SMarcel Moolenaar # as they may be 'rw' 4227750ad47SMarcel Moolenaar interesting += 'W' 4237750ad47SMarcel Moolenaar """ 4247750ad47SMarcel Moolenaar elif w[0] == 'CWD': 425ccfb9654SSimon J. Gerraty self.cwd = cwd = self.last_dir = w[1] 4267750ad47SMarcel Moolenaar self.seenit(cwd) # ignore this 4277750ad47SMarcel Moolenaar if self.debug: 42810ea6facSSimon J. Gerraty print("%s: CWD=%s" % (self.name, cwd), file=self.debug_out) 4297750ad47SMarcel Moolenaar continue 4307750ad47SMarcel Moolenaar 4317750ad47SMarcel Moolenaar pid = int(w[1]) 4327750ad47SMarcel Moolenaar if pid != last_pid: 4337750ad47SMarcel Moolenaar if last_pid: 4347750ad47SMarcel Moolenaar pid_cwd[last_pid] = cwd 435ccfb9654SSimon J. Gerraty pid_last_dir[last_pid] = self.last_dir 4367750ad47SMarcel Moolenaar cwd = getv(pid_cwd, pid, self.cwd) 437ccfb9654SSimon J. Gerraty self.last_dir = getv(pid_last_dir, pid, self.cwd) 4387750ad47SMarcel Moolenaar last_pid = pid 4397750ad47SMarcel Moolenaar 4407750ad47SMarcel Moolenaar # process operations 4417750ad47SMarcel Moolenaar if w[0] == 'F': 4427750ad47SMarcel Moolenaar npid = int(w[2]) 4437750ad47SMarcel Moolenaar pid_cwd[npid] = cwd 4447750ad47SMarcel Moolenaar pid_last_dir[npid] = cwd 4457750ad47SMarcel Moolenaar last_pid = npid 4467750ad47SMarcel Moolenaar continue 4477750ad47SMarcel Moolenaar elif w[0] == 'C': 4487750ad47SMarcel Moolenaar cwd = abspath(w[2], cwd, None, self.debug, self.debug_out) 4497750ad47SMarcel Moolenaar if cwd.endswith('/.'): 4507750ad47SMarcel Moolenaar cwd = cwd[0:-2] 451ccfb9654SSimon J. Gerraty self.last_dir = cwd 4527750ad47SMarcel Moolenaar if self.debug > 1: 45310ea6facSSimon J. Gerraty print("cwd=", cwd, file=self.debug_out) 4547750ad47SMarcel Moolenaar continue 4557750ad47SMarcel Moolenaar 4567750ad47SMarcel Moolenaar if w[2] in self.seen: 4577750ad47SMarcel Moolenaar if self.debug > 2: 45810ea6facSSimon J. Gerraty print("seen:", w[2], file=self.debug_out) 4597750ad47SMarcel Moolenaar continue 4607750ad47SMarcel Moolenaar # file operations 4617750ad47SMarcel Moolenaar if w[0] in 'ML': 462ccfb9654SSimon J. Gerraty # these are special, tread src as read and 463ccfb9654SSimon J. Gerraty # target as write 464ccfb9654SSimon J. Gerraty self.parse_path(w[1].strip("'"), cwd, 'R', w) 465ccfb9654SSimon J. Gerraty self.parse_path(w[2].strip("'"), cwd, 'W', w) 466ccfb9654SSimon J. Gerraty continue 467ccfb9654SSimon J. Gerraty elif w[0] in 'ERWS': 4687750ad47SMarcel Moolenaar path = w[2] 469ccfb9654SSimon J. Gerraty self.parse_path(path, cwd, w[0], w) 470ccfb9654SSimon J. Gerraty 471ccfb9654SSimon J. Gerraty if not file: 472ccfb9654SSimon J. Gerraty f.close() 473ccfb9654SSimon J. Gerraty 474ccfb9654SSimon J. Gerraty def parse_path(self, path, cwd, op=None, w=[]): 475ccfb9654SSimon J. Gerraty """look at a path for the op specified""" 476ccfb9654SSimon J. Gerraty 477ccfb9654SSimon J. Gerraty if not op: 478ccfb9654SSimon J. Gerraty op = w[0] 479ccfb9654SSimon J. Gerraty 480fbc1b149SSimon J. Gerraty # we are never interested in .dirdep files as dependencies 481fbc1b149SSimon J. Gerraty if path.endswith('.dirdep'): 482ccfb9654SSimon J. Gerraty return 483ccfb9654SSimon J. Gerraty for p in self.excludes: 484ccfb9654SSimon J. Gerraty if p and path.startswith(p): 485ccfb9654SSimon J. Gerraty if self.debug > 2: 486*e1dfa657SBryan Drewery print("exclude:", p, path, file=self.debug_out) 487ccfb9654SSimon J. Gerraty return 4887750ad47SMarcel Moolenaar # we don't want to resolve the last component if it is 4897750ad47SMarcel Moolenaar # a symlink 490ccfb9654SSimon J. Gerraty path = resolve(path, cwd, self.last_dir, self.debug, self.debug_out) 4917750ad47SMarcel Moolenaar if not path: 492ccfb9654SSimon J. Gerraty return 4937750ad47SMarcel Moolenaar dir,base = os.path.split(path) 4947750ad47SMarcel Moolenaar if dir in self.seen: 4957750ad47SMarcel Moolenaar if self.debug > 2: 49610ea6facSSimon J. Gerraty print("seen:", dir, file=self.debug_out) 497ccfb9654SSimon J. Gerraty return 4987750ad47SMarcel Moolenaar # we can have a path in an objdir which is a link 4997750ad47SMarcel Moolenaar # to the src dir, we may need to add dependencies for each 5007750ad47SMarcel Moolenaar rdir = dir 501ccfb9654SSimon J. Gerraty dir = abspath(dir, cwd, self.last_dir, self.debug, self.debug_out) 5027750ad47SMarcel Moolenaar if rdir == dir or rdir.find('./') > 0: 5037750ad47SMarcel Moolenaar rdir = None 5047750ad47SMarcel Moolenaar # now put path back together 5057750ad47SMarcel Moolenaar path = '/'.join([dir,base]) 5067750ad47SMarcel Moolenaar if self.debug > 1: 50710ea6facSSimon J. Gerraty print("raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path), file=self.debug_out) 508ccfb9654SSimon J. Gerraty if op in 'RWS': 509ccfb9654SSimon J. Gerraty if path in [self.last_dir, cwd, self.cwd, self.curdir]: 5107750ad47SMarcel Moolenaar if self.debug > 1: 51110ea6facSSimon J. Gerraty print("skipping:", path, file=self.debug_out) 512ccfb9654SSimon J. Gerraty return 5137750ad47SMarcel Moolenaar if os.path.isdir(path): 514ccfb9654SSimon J. Gerraty if op in 'RW': 515ccfb9654SSimon J. Gerraty self.last_dir = path; 5167750ad47SMarcel Moolenaar if self.debug > 1: 517ccfb9654SSimon J. Gerraty print("ldir=", self.last_dir, file=self.debug_out) 518ccfb9654SSimon J. Gerraty return 5197750ad47SMarcel Moolenaar 520ccfb9654SSimon J. Gerraty if op in 'ERW': 5217750ad47SMarcel Moolenaar # finally, we get down to it 5227750ad47SMarcel Moolenaar if dir == self.cwd or dir == self.curdir: 523ccfb9654SSimon J. Gerraty return 5247750ad47SMarcel Moolenaar srctop = self.find_top(path, self.srctops) 5257750ad47SMarcel Moolenaar if srctop: 5267750ad47SMarcel Moolenaar if self.dpdeps: 5277750ad47SMarcel Moolenaar self.add(self.file_deps, path.replace(srctop,''), 'file') 5287750ad47SMarcel Moolenaar self.add(self.src_deps, dir.replace(srctop,''), 'src') 5297750ad47SMarcel Moolenaar self.seenit(w[2]) 5307750ad47SMarcel Moolenaar self.seenit(dir) 5317750ad47SMarcel Moolenaar if rdir and not rdir.startswith(srctop): 5327750ad47SMarcel Moolenaar dir = rdir # for below 5337750ad47SMarcel Moolenaar rdir = None 5347750ad47SMarcel Moolenaar else: 535ccfb9654SSimon J. Gerraty return 5367750ad47SMarcel Moolenaar 5377750ad47SMarcel Moolenaar objroot = None 5387750ad47SMarcel Moolenaar for dir in [dir,rdir]: 5397750ad47SMarcel Moolenaar if not dir: 5407750ad47SMarcel Moolenaar continue 5417750ad47SMarcel Moolenaar objroot = self.find_top(dir, self.objroots) 5427750ad47SMarcel Moolenaar if objroot: 5437750ad47SMarcel Moolenaar break 5447750ad47SMarcel Moolenaar if objroot: 5457750ad47SMarcel Moolenaar ddep = self.find_obj(objroot, dir, path, w[2]) 5467750ad47SMarcel Moolenaar if ddep: 5477750ad47SMarcel Moolenaar self.add(self.obj_deps, ddep, 'obj') 5487750ad47SMarcel Moolenaar else: 5497750ad47SMarcel Moolenaar # don't waste time looking again 5507750ad47SMarcel Moolenaar self.seenit(w[2]) 5517750ad47SMarcel Moolenaar self.seenit(dir) 5527750ad47SMarcel Moolenaar 5537750ad47SMarcel Moolenaar 5547750ad47SMarcel Moolenaardef main(argv, klass=MetaFile, xopts='', xoptf=None): 5557750ad47SMarcel Moolenaar """Simple driver for class MetaFile. 5567750ad47SMarcel Moolenaar 5577750ad47SMarcel Moolenaar Usage: 5587750ad47SMarcel Moolenaar script [options] [key=value ...] "meta" ... 5597750ad47SMarcel Moolenaar 5607750ad47SMarcel Moolenaar Options and key=value pairs contribute to the 5617750ad47SMarcel Moolenaar dictionary passed to MetaFile. 5627750ad47SMarcel Moolenaar 5637750ad47SMarcel Moolenaar -S "SRCTOP" 5647750ad47SMarcel Moolenaar add "SRCTOP" to the "SRCTOPS" list. 5657750ad47SMarcel Moolenaar 5667750ad47SMarcel Moolenaar -C "CURDIR" 5677750ad47SMarcel Moolenaar 5687750ad47SMarcel Moolenaar -O "OBJROOT" 5697750ad47SMarcel Moolenaar add "OBJROOT" to the "OBJROOTS" list. 5707750ad47SMarcel Moolenaar 5717750ad47SMarcel Moolenaar -m "MACHINE" 5727750ad47SMarcel Moolenaar 573bf062775SSimon J. Gerraty -a "MACHINE_ARCH" 574bf062775SSimon J. Gerraty 5757750ad47SMarcel Moolenaar -H "HOST_TARGET" 5767750ad47SMarcel Moolenaar 5777750ad47SMarcel Moolenaar -D "DPDEPS" 5787750ad47SMarcel Moolenaar 5797750ad47SMarcel Moolenaar -d bumps debug level 5807750ad47SMarcel Moolenaar 5817750ad47SMarcel Moolenaar """ 5827750ad47SMarcel Moolenaar import getopt 5837750ad47SMarcel Moolenaar 5847750ad47SMarcel Moolenaar # import Psyco if we can 5857750ad47SMarcel Moolenaar # it can speed things up quite a bit 5867750ad47SMarcel Moolenaar have_psyco = 0 5877750ad47SMarcel Moolenaar try: 5887750ad47SMarcel Moolenaar import psyco 5897750ad47SMarcel Moolenaar psyco.full() 5907750ad47SMarcel Moolenaar have_psyco = 1 5917750ad47SMarcel Moolenaar except: 5927750ad47SMarcel Moolenaar pass 5937750ad47SMarcel Moolenaar 5947750ad47SMarcel Moolenaar conf = { 5957750ad47SMarcel Moolenaar 'SRCTOPS': [], 5967750ad47SMarcel Moolenaar 'OBJROOTS': [], 597ccfb9654SSimon J. Gerraty 'EXCLUDES': [], 5987750ad47SMarcel Moolenaar } 5997750ad47SMarcel Moolenaar 6007750ad47SMarcel Moolenaar try: 6017750ad47SMarcel Moolenaar machine = os.environ['MACHINE'] 6027750ad47SMarcel Moolenaar if machine: 6037750ad47SMarcel Moolenaar conf['MACHINE'] = machine 604bf062775SSimon J. Gerraty machine_arch = os.environ['MACHINE_ARCH'] 605bf062775SSimon J. Gerraty if machine_arch: 606bf062775SSimon J. Gerraty conf['MACHINE_ARCH'] = machine_arch 6077750ad47SMarcel Moolenaar srctop = os.environ['SB_SRC'] 6087750ad47SMarcel Moolenaar if srctop: 6097750ad47SMarcel Moolenaar conf['SRCTOPS'].append(srctop) 6107750ad47SMarcel Moolenaar objroot = os.environ['SB_OBJROOT'] 6117750ad47SMarcel Moolenaar if objroot: 6127750ad47SMarcel Moolenaar conf['OBJROOTS'].append(objroot) 6137750ad47SMarcel Moolenaar except: 6147750ad47SMarcel Moolenaar pass 6157750ad47SMarcel Moolenaar 6167750ad47SMarcel Moolenaar debug = 0 6177750ad47SMarcel Moolenaar output = True 6187750ad47SMarcel Moolenaar 619ccfb9654SSimon J. Gerraty opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:X:' + xopts) 6207750ad47SMarcel Moolenaar for o, a in opts: 621bf062775SSimon J. Gerraty if o == '-a': 622bf062775SSimon J. Gerraty conf['MACHINE_ARCH'] = a 623bf062775SSimon J. Gerraty elif o == '-d': 6247750ad47SMarcel Moolenaar debug += 1 6257750ad47SMarcel Moolenaar elif o == '-q': 6267750ad47SMarcel Moolenaar output = False 6277750ad47SMarcel Moolenaar elif o == '-H': 6287750ad47SMarcel Moolenaar conf['HOST_TARGET'] = a 6297750ad47SMarcel Moolenaar elif o == '-S': 6307750ad47SMarcel Moolenaar if a not in conf['SRCTOPS']: 6317750ad47SMarcel Moolenaar conf['SRCTOPS'].append(a) 6327750ad47SMarcel Moolenaar elif o == '-C': 6337750ad47SMarcel Moolenaar conf['CURDIR'] = a 6347750ad47SMarcel Moolenaar elif o == '-O': 6357750ad47SMarcel Moolenaar if a not in conf['OBJROOTS']: 6367750ad47SMarcel Moolenaar conf['OBJROOTS'].append(a) 6377750ad47SMarcel Moolenaar elif o == '-R': 6387750ad47SMarcel Moolenaar conf['RELDIR'] = a 6397750ad47SMarcel Moolenaar elif o == '-D': 6407750ad47SMarcel Moolenaar conf['DPDEPS'] = a 6417750ad47SMarcel Moolenaar elif o == '-m': 6427750ad47SMarcel Moolenaar conf['MACHINE'] = a 643bf062775SSimon J. Gerraty elif o == '-T': 644bf062775SSimon J. Gerraty conf['TARGET_SPEC'] = a 645ccfb9654SSimon J. Gerraty elif o == '-X': 646ccfb9654SSimon J. Gerraty if a not in conf['EXCLUDES']: 647ccfb9654SSimon J. Gerraty conf['EXCLUDES'].append(a) 6487750ad47SMarcel Moolenaar elif xoptf: 6497750ad47SMarcel Moolenaar xoptf(o, a, conf) 6507750ad47SMarcel Moolenaar 6517750ad47SMarcel Moolenaar conf['debug'] = debug 6527750ad47SMarcel Moolenaar 6537750ad47SMarcel Moolenaar # get any var=val assignments 6547750ad47SMarcel Moolenaar eaten = [] 6557750ad47SMarcel Moolenaar for a in args: 6567750ad47SMarcel Moolenaar if a.find('=') > 0: 6577750ad47SMarcel Moolenaar k,v = a.split('=') 6587750ad47SMarcel Moolenaar if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']: 6597750ad47SMarcel Moolenaar if k == 'SRCTOP': 6607750ad47SMarcel Moolenaar k = 'SRCTOPS' 6617750ad47SMarcel Moolenaar elif k == 'OBJROOT': 6627750ad47SMarcel Moolenaar k = 'OBJROOTS' 6637750ad47SMarcel Moolenaar if v not in conf[k]: 6647750ad47SMarcel Moolenaar conf[k].append(v) 6657750ad47SMarcel Moolenaar else: 6667750ad47SMarcel Moolenaar conf[k] = v 6677750ad47SMarcel Moolenaar eaten.append(a) 6687750ad47SMarcel Moolenaar continue 6697750ad47SMarcel Moolenaar break 6707750ad47SMarcel Moolenaar 6717750ad47SMarcel Moolenaar for a in eaten: 6727750ad47SMarcel Moolenaar args.remove(a) 6737750ad47SMarcel Moolenaar 6747750ad47SMarcel Moolenaar debug_out = getv(conf, 'debug_out', sys.stderr) 6757750ad47SMarcel Moolenaar 6767750ad47SMarcel Moolenaar if debug: 67710ea6facSSimon J. Gerraty print("config:", file=debug_out) 67810ea6facSSimon J. Gerraty print("psyco=", have_psyco, file=debug_out) 67910ea6facSSimon J. Gerraty for k,v in list(conf.items()): 68010ea6facSSimon J. Gerraty print("%s=%s" % (k,v), file=debug_out) 6817750ad47SMarcel Moolenaar 682ccfb9654SSimon J. Gerraty m = None 6837750ad47SMarcel Moolenaar for a in args: 684d5ddb276SSimon J. Gerraty if a.endswith('.meta'): 685ccfb9654SSimon J. Gerraty if not os.path.exists(a): 686ccfb9654SSimon J. Gerraty continue 6877750ad47SMarcel Moolenaar m = klass(a, conf) 688d5ddb276SSimon J. Gerraty elif a.startswith('@'): 689d5ddb276SSimon J. Gerraty # there can actually multiple files per line 690d5ddb276SSimon J. Gerraty for line in open(a[1:]): 691d5ddb276SSimon J. Gerraty for f in line.strip().split(): 692ccfb9654SSimon J. Gerraty if not os.path.exists(f): 693ccfb9654SSimon J. Gerraty continue 694d5ddb276SSimon J. Gerraty m = klass(f, conf) 6957750ad47SMarcel Moolenaar 696ccfb9654SSimon J. Gerraty if output and m: 69710ea6facSSimon J. Gerraty print(m.dirdeps()) 6987750ad47SMarcel Moolenaar 69910ea6facSSimon J. Gerraty print(m.src_dirdeps('\nsrc:')) 7007750ad47SMarcel Moolenaar 7017750ad47SMarcel Moolenaar dpdeps = getv(conf, 'DPDEPS') 7027750ad47SMarcel Moolenaar if dpdeps: 7037750ad47SMarcel Moolenaar m.file_depends(open(dpdeps, 'wb')) 7047750ad47SMarcel Moolenaar 7057750ad47SMarcel Moolenaar return m 7067750ad47SMarcel Moolenaar 7077750ad47SMarcel Moolenaarif __name__ == '__main__': 7087750ad47SMarcel Moolenaar try: 7097750ad47SMarcel Moolenaar main(sys.argv) 7107750ad47SMarcel Moolenaar except: 7117750ad47SMarcel Moolenaar # yes, this goes to stdout 71210ea6facSSimon J. Gerraty print("ERROR: ", sys.exc_info()[1]) 7137750ad47SMarcel Moolenaar raise 7147750ad47SMarcel Moolenaar 715