xref: /freebsd/share/mk/meta2deps.py (revision 4ed4429c63952b5a92d5f707fa48a42cc2a95e08)
17750ad47SMarcel Moolenaar#!/usr/bin/env python
27750ad47SMarcel Moolenaar
37750ad47SMarcel Moolenaar"""
47750ad47SMarcel MoolenaarThis script parses each "meta" file and extracts the
57750ad47SMarcel Moolenaarinformation needed to deduce build and src dependencies.
67750ad47SMarcel Moolenaar
77750ad47SMarcel MoolenaarIt works much the same as the original shell script, but is
87750ad47SMarcel Moolenaar*much* more efficient.
97750ad47SMarcel Moolenaar
107750ad47SMarcel MoolenaarThe parsing work is handled by the class MetaFile.
117750ad47SMarcel MoolenaarWe only pay attention to a subset of the information in the
127750ad47SMarcel Moolenaar"meta" files.  Specifically:
137750ad47SMarcel Moolenaar
147750ad47SMarcel Moolenaar'CWD'	to initialize our notion.
157750ad47SMarcel Moolenaar
167750ad47SMarcel Moolenaar'C'	to track chdir(2) on a per process basis
177750ad47SMarcel Moolenaar
187750ad47SMarcel Moolenaar'R'	files read are what we really care about.
197750ad47SMarcel Moolenaar	directories read, provide a clue to resolving
207750ad47SMarcel Moolenaar	subsequent relative paths.  That is if we cannot find
217750ad47SMarcel Moolenaar	them relative to 'cwd', we check relative to the last
227750ad47SMarcel Moolenaar	dir read.
237750ad47SMarcel Moolenaar
247750ad47SMarcel Moolenaar'W'	files opened for write or read-write,
257750ad47SMarcel Moolenaar	for filemon V3 and earlier.
267750ad47SMarcel Moolenaar
277750ad47SMarcel Moolenaar'E'	files executed.
287750ad47SMarcel Moolenaar
297750ad47SMarcel Moolenaar'L'	files linked
307750ad47SMarcel Moolenaar
317750ad47SMarcel Moolenaar'V'	the filemon version, this record is used as a clue
327750ad47SMarcel Moolenaar	that we have reached the interesting bit.
337750ad47SMarcel Moolenaar
347750ad47SMarcel Moolenaar"""
357750ad47SMarcel Moolenaar
367750ad47SMarcel Moolenaar"""
377750ad47SMarcel MoolenaarRCSid:
38*4ed4429cSSimon J. Gerraty	$Id: meta2deps.py,v 1.8 2013/02/10 19:21:46 sjg Exp $
397750ad47SMarcel Moolenaar
40*4ed4429cSSimon J. Gerraty	Copyright (c) 2011-2013, Juniper Networks, Inc.
41*4ed4429cSSimon J. Gerraty	All rights reserved.
427750ad47SMarcel Moolenaar
437750ad47SMarcel Moolenaar	Redistribution and use in source and binary forms, with or without
447750ad47SMarcel Moolenaar	modification, are permitted provided that the following conditions
457750ad47SMarcel Moolenaar	are met:
467750ad47SMarcel Moolenaar	1. Redistributions of source code must retain the above copyright
477750ad47SMarcel Moolenaar	   notice, this list of conditions and the following disclaimer.
487750ad47SMarcel Moolenaar	2. Redistributions in binary form must reproduce the above copyright
497750ad47SMarcel Moolenaar	   notice, this list of conditions and the following disclaimer in the
507750ad47SMarcel Moolenaar	   documentation and/or other materials provided with the distribution.
517750ad47SMarcel Moolenaar
527750ad47SMarcel Moolenaar	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
537750ad47SMarcel Moolenaar	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
547750ad47SMarcel Moolenaar	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
557750ad47SMarcel Moolenaar	A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
567750ad47SMarcel Moolenaar	OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
577750ad47SMarcel Moolenaar	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
587750ad47SMarcel Moolenaar	LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
597750ad47SMarcel Moolenaar	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
607750ad47SMarcel Moolenaar	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
617750ad47SMarcel Moolenaar	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
627750ad47SMarcel Moolenaar	OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
637750ad47SMarcel Moolenaar
647750ad47SMarcel Moolenaar"""
657750ad47SMarcel Moolenaar
667750ad47SMarcel Moolenaarimport os, re, sys
677750ad47SMarcel Moolenaar
687750ad47SMarcel Moolenaardef getv(dict, key, d=None):
697750ad47SMarcel Moolenaar    """Lookup key in dict and return value or the supplied default."""
707750ad47SMarcel Moolenaar    if key in dict:
717750ad47SMarcel Moolenaar        return dict[key]
727750ad47SMarcel Moolenaar    return d
737750ad47SMarcel Moolenaar
747750ad47SMarcel Moolenaardef resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
757750ad47SMarcel Moolenaar    """
767750ad47SMarcel Moolenaar    Return an absolute path, resolving via cwd or last_dir if needed.
777750ad47SMarcel Moolenaar    """
787750ad47SMarcel Moolenaar    if path.endswith('/.'):
797750ad47SMarcel Moolenaar        path = path[0:-2]
807750ad47SMarcel Moolenaar    if path[0] == '/':
817750ad47SMarcel Moolenaar        return path
827750ad47SMarcel Moolenaar    if path == '.':
837750ad47SMarcel Moolenaar        return cwd
847750ad47SMarcel Moolenaar    if path.startswith('./'):
857750ad47SMarcel Moolenaar        return cwd + path[1:]
867750ad47SMarcel Moolenaar    if last_dir == cwd:
877750ad47SMarcel Moolenaar        last_dir = None
887750ad47SMarcel Moolenaar    for d in [last_dir, cwd]:
897750ad47SMarcel Moolenaar        if not d:
907750ad47SMarcel Moolenaar            continue
917750ad47SMarcel Moolenaar        p = '/'.join([d,path])
927750ad47SMarcel Moolenaar        if debug > 2:
937750ad47SMarcel Moolenaar            print >> debug_out, "looking for:", p,
947750ad47SMarcel Moolenaar        if not os.path.exists(p):
957750ad47SMarcel Moolenaar            if debug > 2:
967750ad47SMarcel Moolenaar                print >> debug_out, "nope"
977750ad47SMarcel Moolenaar            p = None
987750ad47SMarcel Moolenaar            continue
997750ad47SMarcel Moolenaar        if debug > 2:
1007750ad47SMarcel Moolenaar            print >> debug_out, "found:", p
1017750ad47SMarcel Moolenaar        return p
1027750ad47SMarcel Moolenaar    return None
1037750ad47SMarcel Moolenaar
1047750ad47SMarcel Moolenaardef abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
1057750ad47SMarcel Moolenaar    """
1067750ad47SMarcel Moolenaar    Return an absolute path, resolving via cwd or last_dir if needed.
1077750ad47SMarcel Moolenaar    this gets called a lot, so we try to avoid calling realpath
1087750ad47SMarcel Moolenaar    until we know we have something.
1097750ad47SMarcel Moolenaar    """
1107750ad47SMarcel Moolenaar    path = resolve(path, cwd, last_dir, debug, debug_out)
1117750ad47SMarcel Moolenaar    if path and (path.find('./') > 0 or
1127750ad47SMarcel Moolenaar                 path.endswith('/..') or
1137750ad47SMarcel Moolenaar                 os.path.islink(path)):
1147750ad47SMarcel Moolenaar        return os.path.realpath(path)
1157750ad47SMarcel Moolenaar    return path
1167750ad47SMarcel Moolenaar
1177750ad47SMarcel Moolenaardef sort_unique(list, cmp=None, key=None, reverse=False):
1187750ad47SMarcel Moolenaar    list.sort(cmp, key, reverse)
1197750ad47SMarcel Moolenaar    nl = []
1207750ad47SMarcel Moolenaar    le = None
1217750ad47SMarcel Moolenaar    for e in list:
1227750ad47SMarcel Moolenaar        if e == le:
1237750ad47SMarcel Moolenaar            continue
1247750ad47SMarcel Moolenaar        nl.append(e)
1257750ad47SMarcel Moolenaar    return nl
1267750ad47SMarcel Moolenaar
1277750ad47SMarcel Moolenaarclass MetaFile:
1287750ad47SMarcel Moolenaar    """class to parse meta files generated by bmake."""
1297750ad47SMarcel Moolenaar
1307750ad47SMarcel Moolenaar    conf = None
1317750ad47SMarcel Moolenaar    dirdep_re = None
1327750ad47SMarcel Moolenaar    host_target = None
1337750ad47SMarcel Moolenaar    srctops = []
1347750ad47SMarcel Moolenaar    objroots = []
1357750ad47SMarcel Moolenaar
1367750ad47SMarcel Moolenaar    seen = {}
1377750ad47SMarcel Moolenaar    obj_deps = []
1387750ad47SMarcel Moolenaar    src_deps = []
1397750ad47SMarcel Moolenaar    file_deps = []
1407750ad47SMarcel Moolenaar
1417750ad47SMarcel Moolenaar    def __init__(self, name, conf={}):
1427750ad47SMarcel Moolenaar        """if name is set we will parse it now.
1437750ad47SMarcel Moolenaar        conf can have the follwing keys:
1447750ad47SMarcel Moolenaar
1457750ad47SMarcel Moolenaar        SRCTOPS	list of tops of the src tree(s).
1467750ad47SMarcel Moolenaar
1477750ad47SMarcel Moolenaar        CURDIR	the src directory 'bmake' was run from.
1487750ad47SMarcel Moolenaar
1497750ad47SMarcel Moolenaar        RELDIR	the relative path from SRCTOP to CURDIR
1507750ad47SMarcel Moolenaar
1517750ad47SMarcel Moolenaar        MACHINE	the machine we built for.
1527750ad47SMarcel Moolenaar        	set to 'none' if we are not cross-building.
1537750ad47SMarcel Moolenaar
1547750ad47SMarcel Moolenaar        HOST_TARGET
1557750ad47SMarcel Moolenaar		when we build for the psuedo machine 'host'
1567750ad47SMarcel Moolenaar		the object tree uses HOST_TARGET rather than MACHINE.
1577750ad47SMarcel Moolenaar
1587750ad47SMarcel Moolenaar        OBJROOTS a list of the common prefix for all obj dirs it might
1597750ad47SMarcel Moolenaar		end in '/' or '-'.
1607750ad47SMarcel Moolenaar
1617750ad47SMarcel Moolenaar        DPDEPS	names an optional file to which per file dependencies
1627750ad47SMarcel Moolenaar		will be appended.
1637750ad47SMarcel Moolenaar		For example if 'some/path/foo.h' is read from SRCTOP
1647750ad47SMarcel Moolenaar		then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output.
1657750ad47SMarcel Moolenaar		This can allow 'bmake' to learn all the dirs within
1667750ad47SMarcel Moolenaar 		the tree that depend on 'foo.h'
1677750ad47SMarcel Moolenaar
1687750ad47SMarcel Moolenaar        debug	desired debug level
1697750ad47SMarcel Moolenaar
1707750ad47SMarcel Moolenaar        debug_out open file to send debug output to (sys.stderr)
1717750ad47SMarcel Moolenaar
1727750ad47SMarcel Moolenaar        """
1737750ad47SMarcel Moolenaar
1747750ad47SMarcel Moolenaar        self.name = name
1757750ad47SMarcel Moolenaar        self.debug = getv(conf, 'debug', 0)
1767750ad47SMarcel Moolenaar        self.debug_out = getv(conf, 'debug_out', sys.stderr)
1777750ad47SMarcel Moolenaar
178*4ed4429cSSimon J. Gerraty        self.machine = getv(conf, 'MACHINE', '')
179*4ed4429cSSimon J. Gerraty
1807750ad47SMarcel Moolenaar        if not self.conf:
1817750ad47SMarcel Moolenaar            # some of the steps below we want to do only once
1827750ad47SMarcel Moolenaar            self.conf = conf
1837750ad47SMarcel Moolenaar            self.host_target = getv(conf, 'HOST_TARGET')
1847750ad47SMarcel Moolenaar            for srctop in getv(conf, 'SRCTOPS', []):
1857750ad47SMarcel Moolenaar                if srctop[-1] != '/':
1867750ad47SMarcel Moolenaar                    srctop += '/'
1877750ad47SMarcel Moolenaar                if not srctop in self.srctops:
1887750ad47SMarcel Moolenaar                    self.srctops.append(srctop)
189fbc1b149SSimon J. Gerraty                _srctop = os.path.realpath(srctop)
190fbc1b149SSimon J. Gerraty                if _srctop[-1] != '/':
191fbc1b149SSimon J. Gerraty                    _srctop += '/'
192fbc1b149SSimon J. Gerraty                if not _srctop in self.srctops:
193fbc1b149SSimon J. Gerraty                    self.srctops.append(_srctop)
1947750ad47SMarcel Moolenaar
1957750ad47SMarcel Moolenaar            for objroot in getv(conf, 'OBJROOTS', []):
196*4ed4429cSSimon J. Gerraty                for e in ['/' + self.machine, '/' + self.machine + '/']:
197*4ed4429cSSimon J. Gerraty                    if objroot.endswith(e):
198*4ed4429cSSimon J. Gerraty                        # this is not what we want - fix it
199*4ed4429cSSimon J. Gerraty                        objroot = objroot[0:-len(e)]
200*4ed4429cSSimon J. Gerraty                        if e.endswith('/'):
201*4ed4429cSSimon J. Gerraty                            objroot += '/'
2027750ad47SMarcel Moolenaar                if not objroot in self.objroots:
2037750ad47SMarcel Moolenaar                    self.objroots.append(objroot)
2047750ad47SMarcel Moolenaar                    _objroot = os.path.realpath(objroot)
2057750ad47SMarcel Moolenaar                    if objroot[-1] == '/':
2067750ad47SMarcel Moolenaar                        _objroot += '/'
2077750ad47SMarcel Moolenaar                    if not _objroot in self.objroots:
2087750ad47SMarcel Moolenaar                        self.objroots.append(_objroot)
2097750ad47SMarcel Moolenaar
210*4ed4429cSSimon J. Gerraty            # we want the longest match
211*4ed4429cSSimon J. Gerraty            self.srctops.sort(reverse=True)
212*4ed4429cSSimon J. Gerraty            self.objroots.sort(reverse=True)
213*4ed4429cSSimon J. Gerraty
2147750ad47SMarcel Moolenaar            if self.debug:
2157750ad47SMarcel Moolenaar                print >> self.debug_out, "host_target=", self.host_target
2167750ad47SMarcel Moolenaar                print >> self.debug_out, "srctops=", self.srctops
2177750ad47SMarcel Moolenaar                print >> self.debug_out, "objroots=", self.objroots
2187750ad47SMarcel Moolenaar
2197750ad47SMarcel Moolenaar            self.dirdep_re = re.compile(r'([^/]+)/(.+)')
2207750ad47SMarcel Moolenaar
2217750ad47SMarcel Moolenaar        self.curdir = getv(conf, 'CURDIR')
2227750ad47SMarcel Moolenaar        self.reldir = getv(conf, 'RELDIR')
2237750ad47SMarcel Moolenaar        self.dpdeps = getv(conf, 'DPDEPS')
2247750ad47SMarcel Moolenaar        if self.dpdeps and not self.reldir:
2257750ad47SMarcel Moolenaar            if self.debug:
2267750ad47SMarcel Moolenaar                print >> self.debug_out, "need reldir:",
2277750ad47SMarcel Moolenaar            if self.curdir:
2287750ad47SMarcel Moolenaar                srctop = self.find_top(self.curdir, self.srctops)
2297750ad47SMarcel Moolenaar                if srctop:
2307750ad47SMarcel Moolenaar                    self.reldir = self.curdir.replace(srctop,'')
2317750ad47SMarcel Moolenaar                    if self.debug:
2327750ad47SMarcel Moolenaar                        print >> self.debug_out, self.reldir
2337750ad47SMarcel Moolenaar            if not self.reldir:
2347750ad47SMarcel Moolenaar                self.dpdeps = None      # we cannot do it?
2357750ad47SMarcel Moolenaar
2367750ad47SMarcel Moolenaar        if name:
2377750ad47SMarcel Moolenaar            self.parse()
2387750ad47SMarcel Moolenaar
2397750ad47SMarcel Moolenaar    def reset(self):
2407750ad47SMarcel Moolenaar        """reset state if we are being passed meta files from multiple directories."""
2417750ad47SMarcel Moolenaar        self.seen = {}
2427750ad47SMarcel Moolenaar        self.obj_deps = []
2437750ad47SMarcel Moolenaar        self.src_deps = []
2447750ad47SMarcel Moolenaar        self.file_deps = []
2457750ad47SMarcel Moolenaar
2467750ad47SMarcel Moolenaar    def dirdeps(self, sep='\n'):
2477750ad47SMarcel Moolenaar        """return DIRDEPS"""
2487750ad47SMarcel Moolenaar        return sep.strip() + sep.join(self.obj_deps)
2497750ad47SMarcel Moolenaar
2507750ad47SMarcel Moolenaar    def src_dirdeps(self, sep='\n'):
2517750ad47SMarcel Moolenaar        """return SRC_DIRDEPS"""
2527750ad47SMarcel Moolenaar        return sep.strip() + sep.join(self.src_deps)
2537750ad47SMarcel Moolenaar
2547750ad47SMarcel Moolenaar    def file_depends(self, out=None):
2557750ad47SMarcel Moolenaar        """Append DPDEPS_${file} += ${RELDIR}
2567750ad47SMarcel Moolenaar        for each file we saw, to the output file."""
2577750ad47SMarcel Moolenaar        if not self.reldir:
2587750ad47SMarcel Moolenaar            return None
2597750ad47SMarcel Moolenaar        for f in sort_unique(self.file_deps):
2607750ad47SMarcel Moolenaar            print >> out, 'DPDEPS_%s += %s' % (f, self.reldir)
2617750ad47SMarcel Moolenaar
2627750ad47SMarcel Moolenaar    def seenit(self, dir):
2637750ad47SMarcel Moolenaar        """rememer that we have seen dir."""
2647750ad47SMarcel Moolenaar        self.seen[dir] = 1
2657750ad47SMarcel Moolenaar
2667750ad47SMarcel Moolenaar    def add(self, list, data, clue=''):
2677750ad47SMarcel Moolenaar        """add data to list if it isn't already there."""
2687750ad47SMarcel Moolenaar        if data not in list:
2697750ad47SMarcel Moolenaar            list.append(data)
2707750ad47SMarcel Moolenaar            if self.debug:
2717750ad47SMarcel Moolenaar                print >> self.debug_out, "%s: %sAdd: %s" % (self.name, clue, data)
2727750ad47SMarcel Moolenaar
2737750ad47SMarcel Moolenaar    def find_top(self, path, list):
2747750ad47SMarcel Moolenaar        """the logical tree may be split accross multiple trees"""
2757750ad47SMarcel Moolenaar        for top in list:
2767750ad47SMarcel Moolenaar            if path.startswith(top):
2777750ad47SMarcel Moolenaar                if self.debug > 2:
2787750ad47SMarcel Moolenaar                    print >> self.debug_out, "found in", top
2797750ad47SMarcel Moolenaar                return top
2807750ad47SMarcel Moolenaar        return None
2817750ad47SMarcel Moolenaar
2827750ad47SMarcel Moolenaar    def find_obj(self, objroot, dir, path, input):
2837750ad47SMarcel Moolenaar        """return path within objroot, taking care of .dirdep files"""
2847750ad47SMarcel Moolenaar        ddep = None
2857750ad47SMarcel Moolenaar        for ddepf in [path + '.dirdep', dir + '/.dirdep']:
2867750ad47SMarcel Moolenaar            if not ddep and os.path.exists(ddepf):
2877750ad47SMarcel Moolenaar                ddep = open(ddepf, 'rb').readline().strip('# \n')
2887750ad47SMarcel Moolenaar                if self.debug > 1:
2897750ad47SMarcel Moolenaar                    print >> self.debug_out, "found %s: %s\n" % (ddepf, ddep)
2907750ad47SMarcel Moolenaar                if ddep.endswith(self.machine):
2917750ad47SMarcel Moolenaar                    ddep = ddep[0:-(1+len(self.machine))]
2927750ad47SMarcel Moolenaar
2937750ad47SMarcel Moolenaar        if not ddep:
2947750ad47SMarcel Moolenaar            # no .dirdeps, so remember that we've seen the raw input
2957750ad47SMarcel Moolenaar            self.seenit(input)
2967750ad47SMarcel Moolenaar            self.seenit(dir)
2977750ad47SMarcel Moolenaar            if self.machine == 'none':
2987750ad47SMarcel Moolenaar                if dir.startswith(objroot):
2997750ad47SMarcel Moolenaar                    return dir.replace(objroot,'')
3007750ad47SMarcel Moolenaar                return None
3017750ad47SMarcel Moolenaar            m = self.dirdep_re.match(dir.replace(objroot,''))
3027750ad47SMarcel Moolenaar            if m:
3037750ad47SMarcel Moolenaar                ddep = m.group(2)
3047750ad47SMarcel Moolenaar                dmachine = m.group(1)
3057750ad47SMarcel Moolenaar                if dmachine != self.machine:
3067750ad47SMarcel Moolenaar                    if not (self.machine == 'host' and
3077750ad47SMarcel Moolenaar                            dmachine == self.host_target):
3087750ad47SMarcel Moolenaar                        if self.debug > 2:
3097750ad47SMarcel Moolenaar                            print >> self.debug_out, "adding .%s to %s" % (dmachine, ddep)
3107750ad47SMarcel Moolenaar                        ddep += '.' + dmachine
3117750ad47SMarcel Moolenaar
3127750ad47SMarcel Moolenaar        return ddep
3137750ad47SMarcel Moolenaar
3147750ad47SMarcel Moolenaar    def parse(self, name=None, file=None):
3157750ad47SMarcel Moolenaar        """A meta file looks like:
3167750ad47SMarcel Moolenaar
3177750ad47SMarcel Moolenaar	# Meta data file "path"
3187750ad47SMarcel Moolenaar	CMD "command-line"
3197750ad47SMarcel Moolenaar	CWD "cwd"
3207750ad47SMarcel Moolenaar	TARGET "target"
3217750ad47SMarcel Moolenaar	-- command output --
3227750ad47SMarcel Moolenaar	-- filemon acquired metadata --
3237750ad47SMarcel Moolenaar	# buildmon version 3
3247750ad47SMarcel Moolenaar	V 3
3257750ad47SMarcel Moolenaar	C "pid" "cwd"
3267750ad47SMarcel Moolenaar	E "pid" "path"
3277750ad47SMarcel Moolenaar        F "pid" "child"
3287750ad47SMarcel Moolenaar	R "pid" "path"
3297750ad47SMarcel Moolenaar	W "pid" "path"
3307750ad47SMarcel Moolenaar	X "pid" "status"
3317750ad47SMarcel Moolenaar        D "pid" "path"
3327750ad47SMarcel Moolenaar        L "pid" "src" "target"
3337750ad47SMarcel Moolenaar        M "pid" "old" "new"
3347750ad47SMarcel Moolenaar        S "pid" "path"
3357750ad47SMarcel Moolenaar        # Bye bye
3367750ad47SMarcel Moolenaar
3377750ad47SMarcel Moolenaar        We go to some effort to avoid processing a dependency more than once.
3387750ad47SMarcel Moolenaar        Of the above record types only C,E,F,L,R,V and W are of interest.
3397750ad47SMarcel Moolenaar        """
3407750ad47SMarcel Moolenaar
3417750ad47SMarcel Moolenaar        version = 0                     # unknown
3427750ad47SMarcel Moolenaar        if name:
3437750ad47SMarcel Moolenaar            self.name = name;
3447750ad47SMarcel Moolenaar        if file:
3457750ad47SMarcel Moolenaar            f = file
3467750ad47SMarcel Moolenaar            cwd = last_dir = self.cwd
3477750ad47SMarcel Moolenaar        else:
3487750ad47SMarcel Moolenaar            f = open(self.name, 'rb')
3497750ad47SMarcel Moolenaar        skip = True
3507750ad47SMarcel Moolenaar        pid_cwd = {}
3517750ad47SMarcel Moolenaar        pid_last_dir = {}
3527750ad47SMarcel Moolenaar        last_pid = 0
3537750ad47SMarcel Moolenaar
3547750ad47SMarcel Moolenaar        if self.curdir:
3557750ad47SMarcel Moolenaar            self.seenit(self.curdir)    # we ignore this
3567750ad47SMarcel Moolenaar
3577750ad47SMarcel Moolenaar        interesting = 'CEFLRV'
3587750ad47SMarcel Moolenaar        for line in f:
3597750ad47SMarcel Moolenaar            # ignore anything we don't care about
3607750ad47SMarcel Moolenaar            if not line[0] in interesting:
3617750ad47SMarcel Moolenaar                continue
3627750ad47SMarcel Moolenaar            if self.debug > 2:
3637750ad47SMarcel Moolenaar                print >> self.debug_out, "input:", line,
3647750ad47SMarcel Moolenaar            w = line.split()
3657750ad47SMarcel Moolenaar
3667750ad47SMarcel Moolenaar            if skip:
3677750ad47SMarcel Moolenaar                if w[0] == 'V':
3687750ad47SMarcel Moolenaar                    skip = False
3697750ad47SMarcel Moolenaar                    version = int(w[1])
3707750ad47SMarcel Moolenaar                    """
3717750ad47SMarcel Moolenaar                    if version < 4:
3727750ad47SMarcel Moolenaar                        # we cannot ignore 'W' records
3737750ad47SMarcel Moolenaar                        # as they may be 'rw'
3747750ad47SMarcel Moolenaar                        interesting += 'W'
3757750ad47SMarcel Moolenaar                    """
3767750ad47SMarcel Moolenaar                elif w[0] == 'CWD':
3777750ad47SMarcel Moolenaar                    self.cwd = cwd = last_dir = w[1]
3787750ad47SMarcel Moolenaar                    self.seenit(cwd)    # ignore this
3797750ad47SMarcel Moolenaar                    if self.debug:
3807750ad47SMarcel Moolenaar                        print >> self.debug_out, "%s: CWD=%s" % (self.name, cwd)
3817750ad47SMarcel Moolenaar                continue
3827750ad47SMarcel Moolenaar
3837750ad47SMarcel Moolenaar            pid = int(w[1])
3847750ad47SMarcel Moolenaar            if pid != last_pid:
3857750ad47SMarcel Moolenaar                if last_pid:
3867750ad47SMarcel Moolenaar                    pid_cwd[last_pid] = cwd
3877750ad47SMarcel Moolenaar                    pid_last_dir[last_pid] = last_dir
3887750ad47SMarcel Moolenaar                cwd = getv(pid_cwd, pid, self.cwd)
3897750ad47SMarcel Moolenaar                last_dir = getv(pid_last_dir, pid, self.cwd)
3907750ad47SMarcel Moolenaar                last_pid = pid
3917750ad47SMarcel Moolenaar
3927750ad47SMarcel Moolenaar            # process operations
3937750ad47SMarcel Moolenaar            if w[0] == 'F':
3947750ad47SMarcel Moolenaar                npid = int(w[2])
3957750ad47SMarcel Moolenaar                pid_cwd[npid] = cwd
3967750ad47SMarcel Moolenaar                pid_last_dir[npid] = cwd
3977750ad47SMarcel Moolenaar                last_pid = npid
3987750ad47SMarcel Moolenaar                continue
3997750ad47SMarcel Moolenaar            elif w[0] == 'C':
4007750ad47SMarcel Moolenaar                cwd = abspath(w[2], cwd, None, self.debug, self.debug_out)
4017750ad47SMarcel Moolenaar                if cwd.endswith('/.'):
4027750ad47SMarcel Moolenaar                    cwd = cwd[0:-2]
4037750ad47SMarcel Moolenaar                last_dir = cwd
4047750ad47SMarcel Moolenaar                if self.debug > 1:
4057750ad47SMarcel Moolenaar                    print >> self.debug_out, "cwd=", cwd
4067750ad47SMarcel Moolenaar                continue
4077750ad47SMarcel Moolenaar
4087750ad47SMarcel Moolenaar            if w[2] in self.seen:
4097750ad47SMarcel Moolenaar                if self.debug > 2:
4107750ad47SMarcel Moolenaar                    print >> self.debug_out, "seen:", w[2]
4117750ad47SMarcel Moolenaar                continue
4127750ad47SMarcel Moolenaar            # file operations
4137750ad47SMarcel Moolenaar            if w[0] in 'ML':
4147750ad47SMarcel Moolenaar                path = w[2].strip("'")
4157750ad47SMarcel Moolenaar            else:
4167750ad47SMarcel Moolenaar                path = w[2]
417fbc1b149SSimon J. Gerraty            # we are never interested in .dirdep files as dependencies
418fbc1b149SSimon J. Gerraty            if path.endswith('.dirdep'):
419fbc1b149SSimon J. Gerraty                continue
4207750ad47SMarcel Moolenaar            # we don't want to resolve the last component if it is
4217750ad47SMarcel Moolenaar            # a symlink
4227750ad47SMarcel Moolenaar            path = resolve(path, cwd, last_dir, self.debug, self.debug_out)
4237750ad47SMarcel Moolenaar            if not path:
4247750ad47SMarcel Moolenaar                continue
4257750ad47SMarcel Moolenaar            dir,base = os.path.split(path)
4267750ad47SMarcel Moolenaar            if dir in self.seen:
4277750ad47SMarcel Moolenaar                if self.debug > 2:
4287750ad47SMarcel Moolenaar                    print >> self.debug_out, "seen:", dir
4297750ad47SMarcel Moolenaar                continue
4307750ad47SMarcel Moolenaar            # we can have a path in an objdir which is a link
4317750ad47SMarcel Moolenaar            # to the src dir, we may need to add dependencies for each
4327750ad47SMarcel Moolenaar            rdir = dir
4337750ad47SMarcel Moolenaar            dir = abspath(dir, cwd, last_dir, self.debug, self.debug_out)
4347750ad47SMarcel Moolenaar            if rdir == dir or rdir.find('./') > 0:
4357750ad47SMarcel Moolenaar                rdir = None
4367750ad47SMarcel Moolenaar            # now put path back together
4377750ad47SMarcel Moolenaar            path = '/'.join([dir,base])
4387750ad47SMarcel Moolenaar            if self.debug > 1:
4397750ad47SMarcel Moolenaar                print >> self.debug_out, "raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path)
4407750ad47SMarcel Moolenaar            if w[0] in 'SRWL':
4417750ad47SMarcel Moolenaar                if w[0] == 'W' and path.endswith('.dirdep'):
4427750ad47SMarcel Moolenaar                    continue
4437750ad47SMarcel Moolenaar                if path in [last_dir, cwd, self.cwd, self.curdir]:
4447750ad47SMarcel Moolenaar                    if self.debug > 1:
4457750ad47SMarcel Moolenaar                        print >> self.debug_out, "skipping:", path
4467750ad47SMarcel Moolenaar                    continue
4477750ad47SMarcel Moolenaar                if os.path.isdir(path):
4487750ad47SMarcel Moolenaar                    if w[0] in 'RW':
4497750ad47SMarcel Moolenaar                        last_dir = path;
4507750ad47SMarcel Moolenaar                    if self.debug > 1:
4517750ad47SMarcel Moolenaar                        print >> self.debug_out, "ldir=", last_dir
4527750ad47SMarcel Moolenaar                    continue
4537750ad47SMarcel Moolenaar
4547750ad47SMarcel Moolenaar            if w[0] in 'REWML':
4557750ad47SMarcel Moolenaar                # finally, we get down to it
4567750ad47SMarcel Moolenaar                if dir == self.cwd or dir == self.curdir:
4577750ad47SMarcel Moolenaar                    continue
4587750ad47SMarcel Moolenaar                srctop = self.find_top(path, self.srctops)
4597750ad47SMarcel Moolenaar                if srctop:
4607750ad47SMarcel Moolenaar                    if self.dpdeps:
4617750ad47SMarcel Moolenaar                        self.add(self.file_deps, path.replace(srctop,''), 'file')
4627750ad47SMarcel Moolenaar                    self.add(self.src_deps, dir.replace(srctop,''), 'src')
4637750ad47SMarcel Moolenaar                    self.seenit(w[2])
4647750ad47SMarcel Moolenaar                    self.seenit(dir)
4657750ad47SMarcel Moolenaar                    if rdir and not rdir.startswith(srctop):
4667750ad47SMarcel Moolenaar                        dir = rdir      # for below
4677750ad47SMarcel Moolenaar                        rdir = None
4687750ad47SMarcel Moolenaar                    else:
4697750ad47SMarcel Moolenaar                        continue
4707750ad47SMarcel Moolenaar
4717750ad47SMarcel Moolenaar                objroot = None
4727750ad47SMarcel Moolenaar                for dir in [dir,rdir]:
4737750ad47SMarcel Moolenaar                    if not dir:
4747750ad47SMarcel Moolenaar                        continue
4757750ad47SMarcel Moolenaar                    objroot = self.find_top(dir, self.objroots)
4767750ad47SMarcel Moolenaar                    if objroot:
4777750ad47SMarcel Moolenaar                        break
4787750ad47SMarcel Moolenaar                if objroot:
4797750ad47SMarcel Moolenaar                    ddep = self.find_obj(objroot, dir, path, w[2])
4807750ad47SMarcel Moolenaar                    if ddep:
4817750ad47SMarcel Moolenaar                        self.add(self.obj_deps, ddep, 'obj')
4827750ad47SMarcel Moolenaar                else:
4837750ad47SMarcel Moolenaar                    # don't waste time looking again
4847750ad47SMarcel Moolenaar                    self.seenit(w[2])
4857750ad47SMarcel Moolenaar                    self.seenit(dir)
4867750ad47SMarcel Moolenaar        if not file:
4877750ad47SMarcel Moolenaar            f.close()
4887750ad47SMarcel Moolenaar
4897750ad47SMarcel Moolenaar
4907750ad47SMarcel Moolenaardef main(argv, klass=MetaFile, xopts='', xoptf=None):
4917750ad47SMarcel Moolenaar    """Simple driver for class MetaFile.
4927750ad47SMarcel Moolenaar
4937750ad47SMarcel Moolenaar    Usage:
4947750ad47SMarcel Moolenaar    	script [options] [key=value ...] "meta" ...
4957750ad47SMarcel Moolenaar
4967750ad47SMarcel Moolenaar    Options and key=value pairs contribute to the
4977750ad47SMarcel Moolenaar    dictionary passed to MetaFile.
4987750ad47SMarcel Moolenaar
4997750ad47SMarcel Moolenaar    -S "SRCTOP"
5007750ad47SMarcel Moolenaar		add "SRCTOP" to the "SRCTOPS" list.
5017750ad47SMarcel Moolenaar
5027750ad47SMarcel Moolenaar    -C "CURDIR"
5037750ad47SMarcel Moolenaar
5047750ad47SMarcel Moolenaar    -O "OBJROOT"
5057750ad47SMarcel Moolenaar    		add "OBJROOT" to the "OBJROOTS" list.
5067750ad47SMarcel Moolenaar
5077750ad47SMarcel Moolenaar    -m "MACHINE"
5087750ad47SMarcel Moolenaar
5097750ad47SMarcel Moolenaar    -H "HOST_TARGET"
5107750ad47SMarcel Moolenaar
5117750ad47SMarcel Moolenaar    -D "DPDEPS"
5127750ad47SMarcel Moolenaar
5137750ad47SMarcel Moolenaar    -d	bumps debug level
5147750ad47SMarcel Moolenaar
5157750ad47SMarcel Moolenaar    """
5167750ad47SMarcel Moolenaar    import getopt
5177750ad47SMarcel Moolenaar
5187750ad47SMarcel Moolenaar    # import Psyco if we can
5197750ad47SMarcel Moolenaar    # it can speed things up quite a bit
5207750ad47SMarcel Moolenaar    have_psyco = 0
5217750ad47SMarcel Moolenaar    try:
5227750ad47SMarcel Moolenaar        import psyco
5237750ad47SMarcel Moolenaar        psyco.full()
5247750ad47SMarcel Moolenaar        have_psyco = 1
5257750ad47SMarcel Moolenaar    except:
5267750ad47SMarcel Moolenaar        pass
5277750ad47SMarcel Moolenaar
5287750ad47SMarcel Moolenaar    conf = {
5297750ad47SMarcel Moolenaar        'SRCTOPS': [],
5307750ad47SMarcel Moolenaar        'OBJROOTS': [],
5317750ad47SMarcel Moolenaar        }
5327750ad47SMarcel Moolenaar
5337750ad47SMarcel Moolenaar    try:
5347750ad47SMarcel Moolenaar        machine = os.environ['MACHINE']
5357750ad47SMarcel Moolenaar        if machine:
5367750ad47SMarcel Moolenaar            conf['MACHINE'] = machine
5377750ad47SMarcel Moolenaar        srctop = os.environ['SB_SRC']
5387750ad47SMarcel Moolenaar        if srctop:
5397750ad47SMarcel Moolenaar            conf['SRCTOPS'].append(srctop)
5407750ad47SMarcel Moolenaar        objroot = os.environ['SB_OBJROOT']
5417750ad47SMarcel Moolenaar        if objroot:
5427750ad47SMarcel Moolenaar            conf['OBJROOTS'].append(objroot)
5437750ad47SMarcel Moolenaar    except:
5447750ad47SMarcel Moolenaar        pass
5457750ad47SMarcel Moolenaar
5467750ad47SMarcel Moolenaar    debug = 0
5477750ad47SMarcel Moolenaar    output = True
5487750ad47SMarcel Moolenaar
5497750ad47SMarcel Moolenaar    opts, args = getopt.getopt(argv[1:], 'dS:C:O:R:m:D:H:q' + xopts)
5507750ad47SMarcel Moolenaar    for o, a in opts:
5517750ad47SMarcel Moolenaar        if o == '-d':
5527750ad47SMarcel Moolenaar            debug += 1
5537750ad47SMarcel Moolenaar        elif o == '-q':
5547750ad47SMarcel Moolenaar            output = False
5557750ad47SMarcel Moolenaar        elif o == '-H':
5567750ad47SMarcel Moolenaar            conf['HOST_TARGET'] = a
5577750ad47SMarcel Moolenaar        elif o == '-S':
5587750ad47SMarcel Moolenaar            if a not in conf['SRCTOPS']:
5597750ad47SMarcel Moolenaar                conf['SRCTOPS'].append(a)
5607750ad47SMarcel Moolenaar        elif o == '-C':
5617750ad47SMarcel Moolenaar            conf['CURDIR'] = a
5627750ad47SMarcel Moolenaar        elif o == '-O':
5637750ad47SMarcel Moolenaar            if a not in conf['OBJROOTS']:
5647750ad47SMarcel Moolenaar                conf['OBJROOTS'].append(a)
5657750ad47SMarcel Moolenaar        elif o == '-R':
5667750ad47SMarcel Moolenaar            conf['RELDIR'] = a
5677750ad47SMarcel Moolenaar        elif o == '-D':
5687750ad47SMarcel Moolenaar            conf['DPDEPS'] = a
5697750ad47SMarcel Moolenaar        elif o == '-m':
5707750ad47SMarcel Moolenaar            conf['MACHINE'] = a
5717750ad47SMarcel Moolenaar        elif xoptf:
5727750ad47SMarcel Moolenaar            xoptf(o, a, conf)
5737750ad47SMarcel Moolenaar
5747750ad47SMarcel Moolenaar    conf['debug'] = debug
5757750ad47SMarcel Moolenaar
5767750ad47SMarcel Moolenaar    # get any var=val assignments
5777750ad47SMarcel Moolenaar    eaten = []
5787750ad47SMarcel Moolenaar    for a in args:
5797750ad47SMarcel Moolenaar        if a.find('=') > 0:
5807750ad47SMarcel Moolenaar            k,v = a.split('=')
5817750ad47SMarcel Moolenaar            if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']:
5827750ad47SMarcel Moolenaar                if k == 'SRCTOP':
5837750ad47SMarcel Moolenaar                    k = 'SRCTOPS'
5847750ad47SMarcel Moolenaar                elif k == 'OBJROOT':
5857750ad47SMarcel Moolenaar                    k = 'OBJROOTS'
5867750ad47SMarcel Moolenaar                if v not in conf[k]:
5877750ad47SMarcel Moolenaar                    conf[k].append(v)
5887750ad47SMarcel Moolenaar            else:
5897750ad47SMarcel Moolenaar                conf[k] = v
5907750ad47SMarcel Moolenaar            eaten.append(a)
5917750ad47SMarcel Moolenaar            continue
5927750ad47SMarcel Moolenaar        break
5937750ad47SMarcel Moolenaar
5947750ad47SMarcel Moolenaar    for a in eaten:
5957750ad47SMarcel Moolenaar        args.remove(a)
5967750ad47SMarcel Moolenaar
5977750ad47SMarcel Moolenaar    debug_out = getv(conf, 'debug_out', sys.stderr)
5987750ad47SMarcel Moolenaar
5997750ad47SMarcel Moolenaar    if debug:
6007750ad47SMarcel Moolenaar        print >> debug_out, "config:"
6017750ad47SMarcel Moolenaar        print >> debug_out, "psyco=", have_psyco
6027750ad47SMarcel Moolenaar        for k,v in conf.items():
6037750ad47SMarcel Moolenaar            print >> debug_out, "%s=%s" % (k,v)
6047750ad47SMarcel Moolenaar
6057750ad47SMarcel Moolenaar    for a in args:
6067750ad47SMarcel Moolenaar        m = klass(a, conf)
6077750ad47SMarcel Moolenaar
6087750ad47SMarcel Moolenaar    if output:
6097750ad47SMarcel Moolenaar        print m.dirdeps()
6107750ad47SMarcel Moolenaar
6117750ad47SMarcel Moolenaar        print m.src_dirdeps('\nsrc:')
6127750ad47SMarcel Moolenaar
6137750ad47SMarcel Moolenaar        dpdeps = getv(conf, 'DPDEPS')
6147750ad47SMarcel Moolenaar        if dpdeps:
6157750ad47SMarcel Moolenaar            m.file_depends(open(dpdeps, 'wb'))
6167750ad47SMarcel Moolenaar
6177750ad47SMarcel Moolenaar    return m
6187750ad47SMarcel Moolenaar
6197750ad47SMarcel Moolenaarif __name__ == '__main__':
6207750ad47SMarcel Moolenaar    try:
6217750ad47SMarcel Moolenaar        main(sys.argv)
6227750ad47SMarcel Moolenaar    except:
6237750ad47SMarcel Moolenaar        # yes, this goes to stdout
6247750ad47SMarcel Moolenaar        print "ERROR: ", sys.exc_info()[1]
6257750ad47SMarcel Moolenaar        raise
6267750ad47SMarcel Moolenaar
627