xref: /freebsd/share/mk/meta2deps.py (revision c0339e7dfd865a9bae874fa128520cfd4bc134b1)
17750ad47SMarcel Moolenaar#!/usr/bin/env python
27750ad47SMarcel Moolenaar
310ea6facSSimon J. Gerratyfrom __future__ import print_function
410ea6facSSimon J. Gerraty
57750ad47SMarcel Moolenaar"""
67750ad47SMarcel MoolenaarThis script parses each "meta" file and extracts the
77750ad47SMarcel Moolenaarinformation needed to deduce build and src dependencies.
87750ad47SMarcel Moolenaar
97750ad47SMarcel MoolenaarIt works much the same as the original shell script, but is
107750ad47SMarcel Moolenaar*much* more efficient.
117750ad47SMarcel Moolenaar
127750ad47SMarcel MoolenaarThe parsing work is handled by the class MetaFile.
137750ad47SMarcel MoolenaarWe only pay attention to a subset of the information in the
147750ad47SMarcel Moolenaar"meta" files.  Specifically:
157750ad47SMarcel Moolenaar
167750ad47SMarcel Moolenaar'CWD'	to initialize our notion.
177750ad47SMarcel Moolenaar
187750ad47SMarcel Moolenaar'C'	to track chdir(2) on a per process basis
197750ad47SMarcel Moolenaar
207750ad47SMarcel Moolenaar'R'	files read are what we really care about.
217750ad47SMarcel Moolenaar	directories read, provide a clue to resolving
227750ad47SMarcel Moolenaar	subsequent relative paths.  That is if we cannot find
237750ad47SMarcel Moolenaar	them relative to 'cwd', we check relative to the last
247750ad47SMarcel Moolenaar	dir read.
257750ad47SMarcel Moolenaar
267750ad47SMarcel Moolenaar'W'	files opened for write or read-write,
277750ad47SMarcel Moolenaar	for filemon V3 and earlier.
287750ad47SMarcel Moolenaar
297750ad47SMarcel Moolenaar'E'	files executed.
307750ad47SMarcel Moolenaar
317750ad47SMarcel Moolenaar'L'	files linked
327750ad47SMarcel Moolenaar
337750ad47SMarcel Moolenaar'V'	the filemon version, this record is used as a clue
347750ad47SMarcel Moolenaar	that we have reached the interesting bit.
357750ad47SMarcel Moolenaar
367750ad47SMarcel Moolenaar"""
377750ad47SMarcel Moolenaar
387750ad47SMarcel Moolenaar"""
397750ad47SMarcel MoolenaarRCSid:
40b47b9f6bSSimon J. Gerraty	$FreeBSD$
416d4f05fdSSimon J. Gerraty	$Id: meta2deps.py,v 1.24 2017/02/08 22:17:10 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
1076d4f05fdSSimon J. Gerratydef cleanpath(path):
1086d4f05fdSSimon J. Gerraty    """cleanup path without using realpath(3)"""
1096d4f05fdSSimon J. Gerraty    if path.startswith('/'):
1106d4f05fdSSimon J. Gerraty        r = '/'
1116d4f05fdSSimon J. Gerraty    else:
1126d4f05fdSSimon J. Gerraty        r = ''
1136d4f05fdSSimon J. Gerraty    p = []
1146d4f05fdSSimon J. Gerraty    w = path.split('/')
1156d4f05fdSSimon J. Gerraty    for d in w:
1166d4f05fdSSimon J. Gerraty        if not d or d == '.':
1176d4f05fdSSimon J. Gerraty            continue
1186d4f05fdSSimon J. Gerraty        if d == '..':
1196d4f05fdSSimon J. Gerraty            p.pop()
1206d4f05fdSSimon J. Gerraty            continue
1216d4f05fdSSimon J. Gerraty        p.append(d)
1226d4f05fdSSimon J. Gerraty
1236d4f05fdSSimon J. Gerraty    return r + '/'.join(p)
1246d4f05fdSSimon J. Gerraty
1257750ad47SMarcel Moolenaardef abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
1267750ad47SMarcel Moolenaar    """
1277750ad47SMarcel Moolenaar    Return an absolute path, resolving via cwd or last_dir if needed.
1286d4f05fdSSimon J. Gerraty    this gets called a lot, so we try to avoid calling realpath.
1297750ad47SMarcel Moolenaar    """
130d5ddb276SSimon J. Gerraty    rpath = resolve(path, cwd, last_dir, debug, debug_out)
131d5ddb276SSimon J. Gerraty    if rpath:
132d5ddb276SSimon J. Gerraty        path = rpath
133ccfb9654SSimon J. Gerraty    if (path.find('/') < 0 or
134ccfb9654SSimon J. Gerraty        path.find('./') > 0 or
1356d4f05fdSSimon J. Gerraty        path.endswith('/..')):
1366d4f05fdSSimon J. Gerraty        path = cleanpath(path)
1377750ad47SMarcel Moolenaar    return path
1387750ad47SMarcel Moolenaar
1397750ad47SMarcel Moolenaardef sort_unique(list, cmp=None, key=None, reverse=False):
1407750ad47SMarcel Moolenaar    list.sort(cmp, key, reverse)
1417750ad47SMarcel Moolenaar    nl = []
1427750ad47SMarcel Moolenaar    le = None
1437750ad47SMarcel Moolenaar    for e in list:
1447750ad47SMarcel Moolenaar        if e == le:
1457750ad47SMarcel Moolenaar            continue
1466d4f05fdSSimon J. Gerraty	le = e
1477750ad47SMarcel Moolenaar        nl.append(e)
1487750ad47SMarcel Moolenaar    return nl
1497750ad47SMarcel Moolenaar
150bf062775SSimon J. Gerratydef add_trims(x):
151bf062775SSimon J. Gerraty    return ['/' + x + '/',
152bf062775SSimon J. Gerraty            '/' + x,
153bf062775SSimon J. Gerraty            x + '/',
154bf062775SSimon J. Gerraty            x]
155bf062775SSimon J. Gerraty
1567750ad47SMarcel Moolenaarclass MetaFile:
1577750ad47SMarcel Moolenaar    """class to parse meta files generated by bmake."""
1587750ad47SMarcel Moolenaar
1597750ad47SMarcel Moolenaar    conf = None
1607750ad47SMarcel Moolenaar    dirdep_re = None
1617750ad47SMarcel Moolenaar    host_target = None
1627750ad47SMarcel Moolenaar    srctops = []
1637750ad47SMarcel Moolenaar    objroots = []
164ccfb9654SSimon J. Gerraty    excludes = []
1657750ad47SMarcel Moolenaar    seen = {}
1667750ad47SMarcel Moolenaar    obj_deps = []
1677750ad47SMarcel Moolenaar    src_deps = []
1687750ad47SMarcel Moolenaar    file_deps = []
1697750ad47SMarcel Moolenaar
1707750ad47SMarcel Moolenaar    def __init__(self, name, conf={}):
1717750ad47SMarcel Moolenaar        """if name is set we will parse it now.
1727750ad47SMarcel Moolenaar        conf can have the follwing keys:
1737750ad47SMarcel Moolenaar
1747750ad47SMarcel Moolenaar        SRCTOPS list of tops of the src tree(s).
1757750ad47SMarcel Moolenaar
1767750ad47SMarcel Moolenaar        CURDIR  the src directory 'bmake' was run from.
1777750ad47SMarcel Moolenaar
1787750ad47SMarcel Moolenaar        RELDIR  the relative path from SRCTOP to CURDIR
1797750ad47SMarcel Moolenaar
1807750ad47SMarcel Moolenaar        MACHINE the machine we built for.
1817750ad47SMarcel Moolenaar                set to 'none' if we are not cross-building.
18251048477SSimon J. Gerraty                More specifically if machine cannot be deduced from objdirs.
1837750ad47SMarcel Moolenaar
184bf062775SSimon J. Gerraty        TARGET_SPEC
185bf062775SSimon J. Gerraty                Sometimes MACHINE isn't enough.
186bf062775SSimon J. Gerraty
1877750ad47SMarcel Moolenaar        HOST_TARGET
188ccfb9654SSimon J. Gerraty                when we build for the pseudo machine 'host'
1897750ad47SMarcel Moolenaar                the object tree uses HOST_TARGET rather than MACHINE.
1907750ad47SMarcel Moolenaar
1917750ad47SMarcel Moolenaar        OBJROOTS a list of the common prefix for all obj dirs it might
1927750ad47SMarcel Moolenaar                end in '/' or '-'.
1937750ad47SMarcel Moolenaar
1947750ad47SMarcel Moolenaar        DPDEPS  names an optional file to which per file dependencies
1957750ad47SMarcel Moolenaar                will be appended.
1967750ad47SMarcel Moolenaar                For example if 'some/path/foo.h' is read from SRCTOP
1977750ad47SMarcel Moolenaar                then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output.
1987750ad47SMarcel Moolenaar                This can allow 'bmake' to learn all the dirs within
1997750ad47SMarcel Moolenaar                the tree that depend on 'foo.h'
2007750ad47SMarcel Moolenaar
201ccfb9654SSimon J. Gerraty        EXCLUDES
202ccfb9654SSimon J. Gerraty                A list of paths to ignore.
203ccfb9654SSimon J. Gerraty                ccache(1) can otherwise be trouble.
204ccfb9654SSimon J. Gerraty
2057750ad47SMarcel Moolenaar        debug   desired debug level
2067750ad47SMarcel Moolenaar
2077750ad47SMarcel Moolenaar        debug_out open file to send debug output to (sys.stderr)
2087750ad47SMarcel Moolenaar
2097750ad47SMarcel Moolenaar        """
2107750ad47SMarcel Moolenaar
2117750ad47SMarcel Moolenaar        self.name = name
2127750ad47SMarcel Moolenaar        self.debug = getv(conf, 'debug', 0)
2137750ad47SMarcel Moolenaar        self.debug_out = getv(conf, 'debug_out', sys.stderr)
2147750ad47SMarcel Moolenaar
2154ed4429cSSimon J. Gerraty        self.machine = getv(conf, 'MACHINE', '')
216bf062775SSimon J. Gerraty        self.machine_arch = getv(conf, 'MACHINE_ARCH', '')
217bf062775SSimon J. Gerraty        self.target_spec = getv(conf, 'TARGET_SPEC', '')
21851048477SSimon J. Gerraty        self.curdir = getv(conf, 'CURDIR')
21951048477SSimon J. Gerraty        self.reldir = getv(conf, 'RELDIR')
22051048477SSimon J. Gerraty        self.dpdeps = getv(conf, 'DPDEPS')
221d5ddb276SSimon J. Gerraty        self.line = 0
2224ed4429cSSimon J. Gerraty
2237750ad47SMarcel Moolenaar        if not self.conf:
2247750ad47SMarcel Moolenaar            # some of the steps below we want to do only once
2257750ad47SMarcel Moolenaar            self.conf = conf
2267750ad47SMarcel Moolenaar            self.host_target = getv(conf, 'HOST_TARGET')
2277750ad47SMarcel Moolenaar            for srctop in getv(conf, 'SRCTOPS', []):
2287750ad47SMarcel Moolenaar                if srctop[-1] != '/':
2297750ad47SMarcel Moolenaar                    srctop += '/'
2307750ad47SMarcel Moolenaar                if not srctop in self.srctops:
2317750ad47SMarcel Moolenaar                    self.srctops.append(srctop)
232fbc1b149SSimon J. Gerraty                _srctop = os.path.realpath(srctop)
233fbc1b149SSimon J. Gerraty                if _srctop[-1] != '/':
234fbc1b149SSimon J. Gerraty                    _srctop += '/'
235fbc1b149SSimon J. Gerraty                if not _srctop in self.srctops:
236fbc1b149SSimon J. Gerraty                    self.srctops.append(_srctop)
2377750ad47SMarcel Moolenaar
238bf062775SSimon J. Gerraty            trim_list = add_trims(self.machine)
2398c95c434SSimon J. Gerraty            if self.machine == 'host':
240bf062775SSimon J. Gerraty                trim_list += add_trims(self.host_target)
241bf062775SSimon J. Gerraty            if self.target_spec:
242bf062775SSimon J. Gerraty                trim_list += add_trims(self.target_spec)
243876336c8SSimon J. Gerraty
2447750ad47SMarcel Moolenaar            for objroot in getv(conf, 'OBJROOTS', []):
2458c95c434SSimon J. Gerraty                for e in trim_list:
2464ed4429cSSimon J. Gerraty                    if objroot.endswith(e):
2474ed4429cSSimon J. Gerraty                        # this is not what we want - fix it
2484ed4429cSSimon J. Gerraty                        objroot = objroot[0:-len(e)]
249b47b9f6bSSimon J. Gerraty
250b47b9f6bSSimon J. Gerraty                if objroot[-1] != '/':
2514ed4429cSSimon J. Gerraty                    objroot += '/'
2527750ad47SMarcel Moolenaar                if not objroot in self.objroots:
2537750ad47SMarcel Moolenaar                    self.objroots.append(objroot)
2547750ad47SMarcel Moolenaar                    _objroot = os.path.realpath(objroot)
2557750ad47SMarcel Moolenaar                    if objroot[-1] == '/':
2567750ad47SMarcel Moolenaar                        _objroot += '/'
2577750ad47SMarcel Moolenaar                    if not _objroot in self.objroots:
2587750ad47SMarcel Moolenaar                        self.objroots.append(_objroot)
2597750ad47SMarcel Moolenaar
2604ed4429cSSimon J. Gerraty            # we want the longest match
2614ed4429cSSimon J. Gerraty            self.srctops.sort(reverse=True)
2624ed4429cSSimon J. Gerraty            self.objroots.sort(reverse=True)
2634ed4429cSSimon J. Gerraty
264ccfb9654SSimon J. Gerraty            self.excludes = getv(conf, 'EXCLUDES', [])
265ccfb9654SSimon J. Gerraty
2667750ad47SMarcel Moolenaar            if self.debug:
26710ea6facSSimon J. Gerraty                print("host_target=", self.host_target, file=self.debug_out)
26810ea6facSSimon J. Gerraty                print("srctops=", self.srctops, file=self.debug_out)
26910ea6facSSimon J. Gerraty                print("objroots=", self.objroots, file=self.debug_out)
270ccfb9654SSimon J. Gerraty                print("excludes=", self.excludes, file=self.debug_out)
2717750ad47SMarcel Moolenaar
2727750ad47SMarcel Moolenaar            self.dirdep_re = re.compile(r'([^/]+)/(.+)')
2737750ad47SMarcel Moolenaar
2747750ad47SMarcel Moolenaar        if self.dpdeps and not self.reldir:
2757750ad47SMarcel Moolenaar            if self.debug:
27610ea6facSSimon J. Gerraty                print("need reldir:", end=' ', file=self.debug_out)
2777750ad47SMarcel Moolenaar            if self.curdir:
2787750ad47SMarcel Moolenaar                srctop = self.find_top(self.curdir, self.srctops)
2797750ad47SMarcel Moolenaar                if srctop:
2807750ad47SMarcel Moolenaar                    self.reldir = self.curdir.replace(srctop,'')
2817750ad47SMarcel Moolenaar                    if self.debug:
28210ea6facSSimon J. Gerraty                        print(self.reldir, file=self.debug_out)
2837750ad47SMarcel Moolenaar            if not self.reldir:
2847750ad47SMarcel Moolenaar                self.dpdeps = None      # we cannot do it?
2857750ad47SMarcel Moolenaar
286876336c8SSimon J. Gerraty        self.cwd = os.getcwd()          # make sure this is initialized
287ccfb9654SSimon J. Gerraty        self.last_dir = self.cwd
288876336c8SSimon J. Gerraty
2897750ad47SMarcel Moolenaar        if name:
290d5ddb276SSimon J. Gerraty            self.try_parse()
2917750ad47SMarcel Moolenaar
2927750ad47SMarcel Moolenaar    def reset(self):
2937750ad47SMarcel Moolenaar        """reset state if we are being passed meta files from multiple directories."""
2947750ad47SMarcel Moolenaar        self.seen = {}
2957750ad47SMarcel Moolenaar        self.obj_deps = []
2967750ad47SMarcel Moolenaar        self.src_deps = []
2977750ad47SMarcel Moolenaar        self.file_deps = []
2987750ad47SMarcel Moolenaar
2997750ad47SMarcel Moolenaar    def dirdeps(self, sep='\n'):
3007750ad47SMarcel Moolenaar        """return DIRDEPS"""
3017750ad47SMarcel Moolenaar        return sep.strip() + sep.join(self.obj_deps)
3027750ad47SMarcel Moolenaar
3037750ad47SMarcel Moolenaar    def src_dirdeps(self, sep='\n'):
3047750ad47SMarcel Moolenaar        """return SRC_DIRDEPS"""
3057750ad47SMarcel Moolenaar        return sep.strip() + sep.join(self.src_deps)
3067750ad47SMarcel Moolenaar
3077750ad47SMarcel Moolenaar    def file_depends(self, out=None):
3087750ad47SMarcel Moolenaar        """Append DPDEPS_${file} += ${RELDIR}
3097750ad47SMarcel Moolenaar        for each file we saw, to the output file."""
3107750ad47SMarcel Moolenaar        if not self.reldir:
3117750ad47SMarcel Moolenaar            return None
3127750ad47SMarcel Moolenaar        for f in sort_unique(self.file_deps):
31310ea6facSSimon J. Gerraty            print('DPDEPS_%s += %s' % (f, self.reldir), file=out)
314b47b9f6bSSimon J. Gerraty        # these entries provide for reverse DIRDEPS lookup
315b47b9f6bSSimon J. Gerraty        for f in self.obj_deps:
316b47b9f6bSSimon J. Gerraty            print('DEPDIRS_%s += %s' % (f, self.reldir), file=out)
3177750ad47SMarcel Moolenaar
3187750ad47SMarcel Moolenaar    def seenit(self, dir):
3197750ad47SMarcel Moolenaar        """rememer that we have seen dir."""
3207750ad47SMarcel Moolenaar        self.seen[dir] = 1
3217750ad47SMarcel Moolenaar
3227750ad47SMarcel Moolenaar    def add(self, list, data, clue=''):
3237750ad47SMarcel Moolenaar        """add data to list if it isn't already there."""
3247750ad47SMarcel Moolenaar        if data not in list:
3257750ad47SMarcel Moolenaar            list.append(data)
3267750ad47SMarcel Moolenaar            if self.debug:
32710ea6facSSimon J. Gerraty                print("%s: %sAdd: %s" % (self.name, clue, data), file=self.debug_out)
3287750ad47SMarcel Moolenaar
3297750ad47SMarcel Moolenaar    def find_top(self, path, list):
330ccfb9654SSimon J. Gerraty        """the logical tree may be split across multiple trees"""
3317750ad47SMarcel Moolenaar        for top in list:
3327750ad47SMarcel Moolenaar            if path.startswith(top):
3337750ad47SMarcel Moolenaar                if self.debug > 2:
33410ea6facSSimon J. Gerraty                    print("found in", top, file=self.debug_out)
3357750ad47SMarcel Moolenaar                return top
3367750ad47SMarcel Moolenaar        return None
3377750ad47SMarcel Moolenaar
3387750ad47SMarcel Moolenaar    def find_obj(self, objroot, dir, path, input):
3397750ad47SMarcel Moolenaar        """return path within objroot, taking care of .dirdep files"""
3407750ad47SMarcel Moolenaar        ddep = None
3417750ad47SMarcel Moolenaar        for ddepf in [path + '.dirdep', dir + '/.dirdep']:
3427750ad47SMarcel Moolenaar            if not ddep and os.path.exists(ddepf):
34310ea6facSSimon J. Gerraty                ddep = open(ddepf, 'r').readline().strip('# \n')
3447750ad47SMarcel Moolenaar                if self.debug > 1:
34510ea6facSSimon J. Gerraty                    print("found %s: %s\n" % (ddepf, ddep), file=self.debug_out)
3467750ad47SMarcel Moolenaar                if ddep.endswith(self.machine):
3477750ad47SMarcel Moolenaar                    ddep = ddep[0:-(1+len(self.machine))]
348bf062775SSimon J. Gerraty                elif self.target_spec and ddep.endswith(self.target_spec):
349bf062775SSimon J. Gerraty                    ddep = ddep[0:-(1+len(self.target_spec))]
3507750ad47SMarcel Moolenaar
3517750ad47SMarcel Moolenaar        if not ddep:
3527750ad47SMarcel Moolenaar            # no .dirdeps, so remember that we've seen the raw input
3537750ad47SMarcel Moolenaar            self.seenit(input)
3547750ad47SMarcel Moolenaar            self.seenit(dir)
3557750ad47SMarcel Moolenaar            if self.machine == 'none':
3567750ad47SMarcel Moolenaar                if dir.startswith(objroot):
3577750ad47SMarcel Moolenaar                    return dir.replace(objroot,'')
3587750ad47SMarcel Moolenaar                return None
3597750ad47SMarcel Moolenaar            m = self.dirdep_re.match(dir.replace(objroot,''))
3607750ad47SMarcel Moolenaar            if m:
3617750ad47SMarcel Moolenaar                ddep = m.group(2)
3627750ad47SMarcel Moolenaar                dmachine = m.group(1)
3637750ad47SMarcel Moolenaar                if dmachine != self.machine:
3647750ad47SMarcel Moolenaar                    if not (self.machine == 'host' and
3657750ad47SMarcel Moolenaar                            dmachine == self.host_target):
3667750ad47SMarcel Moolenaar                        if self.debug > 2:
36710ea6facSSimon J. Gerraty                            print("adding .%s to %s" % (dmachine, ddep), file=self.debug_out)
3687750ad47SMarcel Moolenaar                        ddep += '.' + dmachine
3697750ad47SMarcel Moolenaar
3707750ad47SMarcel Moolenaar        return ddep
3717750ad47SMarcel Moolenaar
372d5ddb276SSimon J. Gerraty    def try_parse(self, name=None, file=None):
373d5ddb276SSimon J. Gerraty        """give file and line number causing exception"""
374d5ddb276SSimon J. Gerraty        try:
375d5ddb276SSimon J. Gerraty            self.parse(name, file)
376d5ddb276SSimon J. Gerraty        except:
377d5ddb276SSimon J. Gerraty            # give a useful clue
37810ea6facSSimon J. Gerraty            print('{}:{}: '.format(self.name, self.line), end=' ', file=sys.stderr)
379d5ddb276SSimon J. Gerraty            raise
380d5ddb276SSimon J. Gerraty
3817750ad47SMarcel Moolenaar    def parse(self, name=None, file=None):
3827750ad47SMarcel Moolenaar        """A meta file looks like:
3837750ad47SMarcel Moolenaar
3847750ad47SMarcel Moolenaar        # Meta data file "path"
3857750ad47SMarcel Moolenaar        CMD "command-line"
3867750ad47SMarcel Moolenaar        CWD "cwd"
3877750ad47SMarcel Moolenaar        TARGET "target"
3887750ad47SMarcel Moolenaar        -- command output --
3897750ad47SMarcel Moolenaar        -- filemon acquired metadata --
3907750ad47SMarcel Moolenaar        # buildmon version 3
3917750ad47SMarcel Moolenaar        V 3
3927750ad47SMarcel Moolenaar        C "pid" "cwd"
3937750ad47SMarcel Moolenaar        E "pid" "path"
3947750ad47SMarcel Moolenaar        F "pid" "child"
3957750ad47SMarcel Moolenaar        R "pid" "path"
3967750ad47SMarcel Moolenaar        W "pid" "path"
3977750ad47SMarcel Moolenaar        X "pid" "status"
3987750ad47SMarcel Moolenaar        D "pid" "path"
3997750ad47SMarcel Moolenaar        L "pid" "src" "target"
4007750ad47SMarcel Moolenaar        M "pid" "old" "new"
4017750ad47SMarcel Moolenaar        S "pid" "path"
4027750ad47SMarcel Moolenaar        # Bye bye
4037750ad47SMarcel Moolenaar
4047750ad47SMarcel Moolenaar        We go to some effort to avoid processing a dependency more than once.
4057750ad47SMarcel Moolenaar        Of the above record types only C,E,F,L,R,V and W are of interest.
4067750ad47SMarcel Moolenaar        """
4077750ad47SMarcel Moolenaar
4087750ad47SMarcel Moolenaar        version = 0                     # unknown
4097750ad47SMarcel Moolenaar        if name:
4107750ad47SMarcel Moolenaar            self.name = name;
4117750ad47SMarcel Moolenaar        if file:
4127750ad47SMarcel Moolenaar            f = file
413ccfb9654SSimon J. Gerraty            cwd = self.last_dir = self.cwd
4147750ad47SMarcel Moolenaar        else:
41510ea6facSSimon J. Gerraty            f = open(self.name, 'r')
4167750ad47SMarcel Moolenaar        skip = True
4177750ad47SMarcel Moolenaar        pid_cwd = {}
4187750ad47SMarcel Moolenaar        pid_last_dir = {}
4197750ad47SMarcel Moolenaar        last_pid = 0
4207750ad47SMarcel Moolenaar
421d5ddb276SSimon J. Gerraty        self.line = 0
4227750ad47SMarcel Moolenaar        if self.curdir:
4237750ad47SMarcel Moolenaar            self.seenit(self.curdir)    # we ignore this
4247750ad47SMarcel Moolenaar
4257750ad47SMarcel Moolenaar        interesting = 'CEFLRV'
4267750ad47SMarcel Moolenaar        for line in f:
427d5ddb276SSimon J. Gerraty            self.line += 1
4287750ad47SMarcel Moolenaar            # ignore anything we don't care about
4297750ad47SMarcel Moolenaar            if not line[0] in interesting:
4307750ad47SMarcel Moolenaar                continue
4317750ad47SMarcel Moolenaar            if self.debug > 2:
43210ea6facSSimon J. Gerraty                print("input:", line, end=' ', file=self.debug_out)
4337750ad47SMarcel Moolenaar            w = line.split()
4347750ad47SMarcel Moolenaar
4357750ad47SMarcel Moolenaar            if skip:
4367750ad47SMarcel Moolenaar                if w[0] == 'V':
4377750ad47SMarcel Moolenaar                    skip = False
4387750ad47SMarcel Moolenaar                    version = int(w[1])
4397750ad47SMarcel Moolenaar                    """
4407750ad47SMarcel Moolenaar                    if version < 4:
4417750ad47SMarcel Moolenaar                        # we cannot ignore 'W' records
4427750ad47SMarcel Moolenaar                        # as they may be 'rw'
4437750ad47SMarcel Moolenaar                        interesting += 'W'
4447750ad47SMarcel Moolenaar                    """
4457750ad47SMarcel Moolenaar                elif w[0] == 'CWD':
446ccfb9654SSimon J. Gerraty                    self.cwd = cwd = self.last_dir = w[1]
4477750ad47SMarcel Moolenaar                    self.seenit(cwd)    # ignore this
4487750ad47SMarcel Moolenaar                    if self.debug:
44910ea6facSSimon J. Gerraty                        print("%s: CWD=%s" % (self.name, cwd), file=self.debug_out)
4507750ad47SMarcel Moolenaar                continue
4517750ad47SMarcel Moolenaar
4527750ad47SMarcel Moolenaar            pid = int(w[1])
4537750ad47SMarcel Moolenaar            if pid != last_pid:
4547750ad47SMarcel Moolenaar                if last_pid:
455ccfb9654SSimon J. Gerraty                    pid_last_dir[last_pid] = self.last_dir
4567750ad47SMarcel Moolenaar                cwd = getv(pid_cwd, pid, self.cwd)
457ccfb9654SSimon J. Gerraty                self.last_dir = getv(pid_last_dir, pid, self.cwd)
4587750ad47SMarcel Moolenaar                last_pid = pid
4597750ad47SMarcel Moolenaar
4607750ad47SMarcel Moolenaar            # process operations
4617750ad47SMarcel Moolenaar            if w[0] == 'F':
4627750ad47SMarcel Moolenaar                npid = int(w[2])
4637750ad47SMarcel Moolenaar                pid_cwd[npid] = cwd
4647750ad47SMarcel Moolenaar                pid_last_dir[npid] = cwd
4657750ad47SMarcel Moolenaar                last_pid = npid
4667750ad47SMarcel Moolenaar                continue
4677750ad47SMarcel Moolenaar            elif w[0] == 'C':
4687750ad47SMarcel Moolenaar                cwd = abspath(w[2], cwd, None, self.debug, self.debug_out)
4697750ad47SMarcel Moolenaar                if cwd.endswith('/.'):
4707750ad47SMarcel Moolenaar                    cwd = cwd[0:-2]
471b47b9f6bSSimon J. Gerraty                self.last_dir = pid_last_dir[pid] = cwd
472b47b9f6bSSimon J. Gerraty                pid_cwd[pid] = cwd
4737750ad47SMarcel Moolenaar                if self.debug > 1:
47410ea6facSSimon J. Gerraty                    print("cwd=", cwd, file=self.debug_out)
4757750ad47SMarcel Moolenaar                continue
4767750ad47SMarcel Moolenaar
4777750ad47SMarcel Moolenaar            if w[2] in self.seen:
4787750ad47SMarcel Moolenaar                if self.debug > 2:
47910ea6facSSimon J. Gerraty                    print("seen:", w[2], file=self.debug_out)
4807750ad47SMarcel Moolenaar                continue
4817750ad47SMarcel Moolenaar            # file operations
4827750ad47SMarcel Moolenaar            if w[0] in 'ML':
483ccfb9654SSimon J. Gerraty                # these are special, tread src as read and
484ccfb9654SSimon J. Gerraty                # target as write
485ccfb9654SSimon J. Gerraty                self.parse_path(w[1].strip("'"), cwd, 'R', w)
486ccfb9654SSimon J. Gerraty                self.parse_path(w[2].strip("'"), cwd, 'W', w)
487ccfb9654SSimon J. Gerraty                continue
488ccfb9654SSimon J. Gerraty            elif w[0] in 'ERWS':
4897750ad47SMarcel Moolenaar                path = w[2]
490ccfb9654SSimon J. Gerraty                self.parse_path(path, cwd, w[0], w)
491ccfb9654SSimon J. Gerraty
492ccfb9654SSimon J. Gerraty        if not file:
493ccfb9654SSimon J. Gerraty            f.close()
494ccfb9654SSimon J. Gerraty
495*c0339e7dSSimon J. Gerraty    def is_src(self, base, dir, rdir):
496*c0339e7dSSimon J. Gerraty        """is base in srctop"""
497*c0339e7dSSimon J. Gerraty        for dir in [dir,rdir]:
498*c0339e7dSSimon J. Gerraty            if not dir:
499*c0339e7dSSimon J. Gerraty                continue
500*c0339e7dSSimon J. Gerraty            path = '/'.join([dir,base])
501*c0339e7dSSimon J. Gerraty            srctop = self.find_top(path, self.srctops)
502*c0339e7dSSimon J. Gerraty            if srctop:
503*c0339e7dSSimon J. Gerraty                if self.dpdeps:
504*c0339e7dSSimon J. Gerraty                    self.add(self.file_deps, path.replace(srctop,''), 'file')
505*c0339e7dSSimon J. Gerraty                self.add(self.src_deps, dir.replace(srctop,''), 'src')
506*c0339e7dSSimon J. Gerraty                self.seenit(dir)
507*c0339e7dSSimon J. Gerraty                return True
508*c0339e7dSSimon J. Gerraty        return False
509*c0339e7dSSimon J. Gerraty
510ccfb9654SSimon J. Gerraty    def parse_path(self, path, cwd, op=None, w=[]):
511ccfb9654SSimon J. Gerraty        """look at a path for the op specified"""
512ccfb9654SSimon J. Gerraty
513ccfb9654SSimon J. Gerraty        if not op:
514ccfb9654SSimon J. Gerraty            op = w[0]
515ccfb9654SSimon J. Gerraty
516fbc1b149SSimon J. Gerraty        # we are never interested in .dirdep files as dependencies
517fbc1b149SSimon J. Gerraty        if path.endswith('.dirdep'):
518ccfb9654SSimon J. Gerraty            return
519ccfb9654SSimon J. Gerraty        for p in self.excludes:
520ccfb9654SSimon J. Gerraty            if p and path.startswith(p):
521ccfb9654SSimon J. Gerraty                if self.debug > 2:
522e1dfa657SBryan Drewery                    print("exclude:", p, path, file=self.debug_out)
523ccfb9654SSimon J. Gerraty                return
5247750ad47SMarcel Moolenaar        # we don't want to resolve the last component if it is
5257750ad47SMarcel Moolenaar        # a symlink
526ccfb9654SSimon J. Gerraty        path = resolve(path, cwd, self.last_dir, self.debug, self.debug_out)
5277750ad47SMarcel Moolenaar        if not path:
528ccfb9654SSimon J. Gerraty            return
5297750ad47SMarcel Moolenaar        dir,base = os.path.split(path)
5307750ad47SMarcel Moolenaar        if dir in self.seen:
5317750ad47SMarcel Moolenaar            if self.debug > 2:
53210ea6facSSimon J. Gerraty                print("seen:", dir, file=self.debug_out)
533ccfb9654SSimon J. Gerraty            return
5347750ad47SMarcel Moolenaar        # we can have a path in an objdir which is a link
5357750ad47SMarcel Moolenaar        # to the src dir, we may need to add dependencies for each
5367750ad47SMarcel Moolenaar        rdir = dir
537ccfb9654SSimon J. Gerraty        dir = abspath(dir, cwd, self.last_dir, self.debug, self.debug_out)
5386d4f05fdSSimon J. Gerraty            rdir = os.path.realpath(dir)
539*c0339e7dSSimon J. Gerraty        if rdir == dir:
540*c0339e7dSSimon J. Gerraty            rdir = None
5417750ad47SMarcel Moolenaar        # now put path back together
5427750ad47SMarcel Moolenaar        path = '/'.join([dir,base])
5437750ad47SMarcel Moolenaar        if self.debug > 1:
54410ea6facSSimon J. Gerraty            print("raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path), file=self.debug_out)
545ccfb9654SSimon J. Gerraty        if op in 'RWS':
546ccfb9654SSimon J. Gerraty            if path in [self.last_dir, cwd, self.cwd, self.curdir]:
5477750ad47SMarcel Moolenaar                if self.debug > 1:
54810ea6facSSimon J. Gerraty                    print("skipping:", path, file=self.debug_out)
549ccfb9654SSimon J. Gerraty                return
5507750ad47SMarcel Moolenaar            if os.path.isdir(path):
551ccfb9654SSimon J. Gerraty                if op in 'RW':
552ccfb9654SSimon J. Gerraty                    self.last_dir = path;
5537750ad47SMarcel Moolenaar                if self.debug > 1:
554ccfb9654SSimon J. Gerraty                    print("ldir=", self.last_dir, file=self.debug_out)
555ccfb9654SSimon J. Gerraty                return
5567750ad47SMarcel Moolenaar
557ccfb9654SSimon J. Gerraty        if op in 'ERW':
5587750ad47SMarcel Moolenaar            # finally, we get down to it
5597750ad47SMarcel Moolenaar            if dir == self.cwd or dir == self.curdir:
560ccfb9654SSimon J. Gerraty                return
561*c0339e7dSSimon J. Gerraty            if self.is_src(base, dir, rdir):
5627750ad47SMarcel Moolenaar                self.seenit(w[2])
563*c0339e7dSSimon J. Gerraty                if not rdir:
564ccfb9654SSimon J. Gerraty                    return
5657750ad47SMarcel Moolenaar
5667750ad47SMarcel Moolenaar            objroot = None
5677750ad47SMarcel Moolenaar            for dir in [dir,rdir]:
5687750ad47SMarcel Moolenaar                if not dir:
5697750ad47SMarcel Moolenaar                    continue
5707750ad47SMarcel Moolenaar                objroot = self.find_top(dir, self.objroots)
5717750ad47SMarcel Moolenaar                if objroot:
5727750ad47SMarcel Moolenaar                    break
5737750ad47SMarcel Moolenaar            if objroot:
5747750ad47SMarcel Moolenaar                ddep = self.find_obj(objroot, dir, path, w[2])
5757750ad47SMarcel Moolenaar                if ddep:
5767750ad47SMarcel Moolenaar                    self.add(self.obj_deps, ddep, 'obj')
577b47b9f6bSSimon J. Gerraty                    if self.dpdeps and objroot.endswith('/stage/'):
578b47b9f6bSSimon J. Gerraty                        sp = '/'.join(path.replace(objroot,'').split('/')[1:])
579b47b9f6bSSimon J. Gerraty                        self.add(self.file_deps, sp, 'file')
5807750ad47SMarcel Moolenaar            else:
5817750ad47SMarcel Moolenaar                # don't waste time looking again
5827750ad47SMarcel Moolenaar                self.seenit(w[2])
5837750ad47SMarcel Moolenaar                self.seenit(dir)
5847750ad47SMarcel Moolenaar
5857750ad47SMarcel Moolenaar
5867750ad47SMarcel Moolenaardef main(argv, klass=MetaFile, xopts='', xoptf=None):
5877750ad47SMarcel Moolenaar    """Simple driver for class MetaFile.
5887750ad47SMarcel Moolenaar
5897750ad47SMarcel Moolenaar    Usage:
5907750ad47SMarcel Moolenaar        script [options] [key=value ...] "meta" ...
5917750ad47SMarcel Moolenaar
5927750ad47SMarcel Moolenaar    Options and key=value pairs contribute to the
5937750ad47SMarcel Moolenaar    dictionary passed to MetaFile.
5947750ad47SMarcel Moolenaar
5957750ad47SMarcel Moolenaar    -S "SRCTOP"
5967750ad47SMarcel Moolenaar                add "SRCTOP" to the "SRCTOPS" list.
5977750ad47SMarcel Moolenaar
5987750ad47SMarcel Moolenaar    -C "CURDIR"
5997750ad47SMarcel Moolenaar
6007750ad47SMarcel Moolenaar    -O "OBJROOT"
6017750ad47SMarcel Moolenaar                add "OBJROOT" to the "OBJROOTS" list.
6027750ad47SMarcel Moolenaar
6037750ad47SMarcel Moolenaar    -m "MACHINE"
6047750ad47SMarcel Moolenaar
605bf062775SSimon J. Gerraty    -a "MACHINE_ARCH"
606bf062775SSimon J. Gerraty
6077750ad47SMarcel Moolenaar    -H "HOST_TARGET"
6087750ad47SMarcel Moolenaar
6097750ad47SMarcel Moolenaar    -D "DPDEPS"
6107750ad47SMarcel Moolenaar
6117750ad47SMarcel Moolenaar    -d  bumps debug level
6127750ad47SMarcel Moolenaar
6137750ad47SMarcel Moolenaar    """
6147750ad47SMarcel Moolenaar    import getopt
6157750ad47SMarcel Moolenaar
6167750ad47SMarcel Moolenaar    # import Psyco if we can
6177750ad47SMarcel Moolenaar    # it can speed things up quite a bit
6187750ad47SMarcel Moolenaar    have_psyco = 0
6197750ad47SMarcel Moolenaar    try:
6207750ad47SMarcel Moolenaar        import psyco
6217750ad47SMarcel Moolenaar        psyco.full()
6227750ad47SMarcel Moolenaar        have_psyco = 1
6237750ad47SMarcel Moolenaar    except:
6247750ad47SMarcel Moolenaar        pass
6257750ad47SMarcel Moolenaar
6267750ad47SMarcel Moolenaar    conf = {
6277750ad47SMarcel Moolenaar        'SRCTOPS': [],
6287750ad47SMarcel Moolenaar        'OBJROOTS': [],
629ccfb9654SSimon J. Gerraty        'EXCLUDES': [],
6307750ad47SMarcel Moolenaar        }
6317750ad47SMarcel Moolenaar
6327750ad47SMarcel Moolenaar    try:
6337750ad47SMarcel Moolenaar        machine = os.environ['MACHINE']
6347750ad47SMarcel Moolenaar        if machine:
6357750ad47SMarcel Moolenaar            conf['MACHINE'] = machine
636bf062775SSimon J. Gerraty        machine_arch = os.environ['MACHINE_ARCH']
637bf062775SSimon J. Gerraty        if machine_arch:
638bf062775SSimon J. Gerraty            conf['MACHINE_ARCH'] = machine_arch
6397750ad47SMarcel Moolenaar        srctop = os.environ['SB_SRC']
6407750ad47SMarcel Moolenaar        if srctop:
6417750ad47SMarcel Moolenaar            conf['SRCTOPS'].append(srctop)
6427750ad47SMarcel Moolenaar        objroot = os.environ['SB_OBJROOT']
6437750ad47SMarcel Moolenaar        if objroot:
6447750ad47SMarcel Moolenaar            conf['OBJROOTS'].append(objroot)
6457750ad47SMarcel Moolenaar    except:
6467750ad47SMarcel Moolenaar        pass
6477750ad47SMarcel Moolenaar
6487750ad47SMarcel Moolenaar    debug = 0
6497750ad47SMarcel Moolenaar    output = True
6507750ad47SMarcel Moolenaar
651ccfb9654SSimon J. Gerraty    opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:X:' + xopts)
6527750ad47SMarcel Moolenaar    for o, a in opts:
653bf062775SSimon J. Gerraty        if o == '-a':
654bf062775SSimon J. Gerraty            conf['MACHINE_ARCH'] = a
655bf062775SSimon J. Gerraty        elif o == '-d':
6567750ad47SMarcel Moolenaar            debug += 1
6577750ad47SMarcel Moolenaar        elif o == '-q':
6587750ad47SMarcel Moolenaar            output = False
6597750ad47SMarcel Moolenaar        elif o == '-H':
6607750ad47SMarcel Moolenaar            conf['HOST_TARGET'] = a
6617750ad47SMarcel Moolenaar        elif o == '-S':
6627750ad47SMarcel Moolenaar            if a not in conf['SRCTOPS']:
6637750ad47SMarcel Moolenaar                conf['SRCTOPS'].append(a)
6647750ad47SMarcel Moolenaar        elif o == '-C':
6657750ad47SMarcel Moolenaar            conf['CURDIR'] = a
6667750ad47SMarcel Moolenaar        elif o == '-O':
6677750ad47SMarcel Moolenaar            if a not in conf['OBJROOTS']:
6687750ad47SMarcel Moolenaar                conf['OBJROOTS'].append(a)
6697750ad47SMarcel Moolenaar        elif o == '-R':
6707750ad47SMarcel Moolenaar            conf['RELDIR'] = a
6717750ad47SMarcel Moolenaar        elif o == '-D':
6727750ad47SMarcel Moolenaar            conf['DPDEPS'] = a
6737750ad47SMarcel Moolenaar        elif o == '-m':
6747750ad47SMarcel Moolenaar            conf['MACHINE'] = a
675bf062775SSimon J. Gerraty        elif o == '-T':
676bf062775SSimon J. Gerraty            conf['TARGET_SPEC'] = a
677ccfb9654SSimon J. Gerraty        elif o == '-X':
678ccfb9654SSimon J. Gerraty            if a not in conf['EXCLUDES']:
679ccfb9654SSimon J. Gerraty                conf['EXCLUDES'].append(a)
6807750ad47SMarcel Moolenaar        elif xoptf:
6817750ad47SMarcel Moolenaar            xoptf(o, a, conf)
6827750ad47SMarcel Moolenaar
6837750ad47SMarcel Moolenaar    conf['debug'] = debug
6847750ad47SMarcel Moolenaar
6857750ad47SMarcel Moolenaar    # get any var=val assignments
6867750ad47SMarcel Moolenaar    eaten = []
6877750ad47SMarcel Moolenaar    for a in args:
6887750ad47SMarcel Moolenaar        if a.find('=') > 0:
6897750ad47SMarcel Moolenaar            k,v = a.split('=')
6907750ad47SMarcel Moolenaar            if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']:
6917750ad47SMarcel Moolenaar                if k == 'SRCTOP':
6927750ad47SMarcel Moolenaar                    k = 'SRCTOPS'
6937750ad47SMarcel Moolenaar                elif k == 'OBJROOT':
6947750ad47SMarcel Moolenaar                    k = 'OBJROOTS'
6957750ad47SMarcel Moolenaar                if v not in conf[k]:
6967750ad47SMarcel Moolenaar                    conf[k].append(v)
6977750ad47SMarcel Moolenaar            else:
6987750ad47SMarcel Moolenaar                conf[k] = v
6997750ad47SMarcel Moolenaar            eaten.append(a)
7007750ad47SMarcel Moolenaar            continue
7017750ad47SMarcel Moolenaar        break
7027750ad47SMarcel Moolenaar
7037750ad47SMarcel Moolenaar    for a in eaten:
7047750ad47SMarcel Moolenaar        args.remove(a)
7057750ad47SMarcel Moolenaar
7067750ad47SMarcel Moolenaar    debug_out = getv(conf, 'debug_out', sys.stderr)
7077750ad47SMarcel Moolenaar
7087750ad47SMarcel Moolenaar    if debug:
70910ea6facSSimon J. Gerraty        print("config:", file=debug_out)
71010ea6facSSimon J. Gerraty        print("psyco=", have_psyco, file=debug_out)
71110ea6facSSimon J. Gerraty        for k,v in list(conf.items()):
71210ea6facSSimon J. Gerraty            print("%s=%s" % (k,v), file=debug_out)
7137750ad47SMarcel Moolenaar
714ccfb9654SSimon J. Gerraty    m = None
7157750ad47SMarcel Moolenaar    for a in args:
716d5ddb276SSimon J. Gerraty        if a.endswith('.meta'):
717ccfb9654SSimon J. Gerraty            if not os.path.exists(a):
718ccfb9654SSimon J. Gerraty                continue
7197750ad47SMarcel Moolenaar            m = klass(a, conf)
720d5ddb276SSimon J. Gerraty        elif a.startswith('@'):
721d5ddb276SSimon J. Gerraty            # there can actually multiple files per line
722d5ddb276SSimon J. Gerraty            for line in open(a[1:]):
723d5ddb276SSimon J. Gerraty                for f in line.strip().split():
724ccfb9654SSimon J. Gerraty                    if not os.path.exists(f):
725ccfb9654SSimon J. Gerraty                        continue
726d5ddb276SSimon J. Gerraty                    m = klass(f, conf)
7277750ad47SMarcel Moolenaar
728ccfb9654SSimon J. Gerraty    if output and m:
72910ea6facSSimon J. Gerraty        print(m.dirdeps())
7307750ad47SMarcel Moolenaar
73110ea6facSSimon J. Gerraty        print(m.src_dirdeps('\nsrc:'))
7327750ad47SMarcel Moolenaar
7337750ad47SMarcel Moolenaar        dpdeps = getv(conf, 'DPDEPS')
7347750ad47SMarcel Moolenaar        if dpdeps:
7357750ad47SMarcel Moolenaar            m.file_depends(open(dpdeps, 'wb'))
7367750ad47SMarcel Moolenaar
7377750ad47SMarcel Moolenaar    return m
7387750ad47SMarcel Moolenaar
7397750ad47SMarcel Moolenaarif __name__ == '__main__':
7407750ad47SMarcel Moolenaar    try:
7417750ad47SMarcel Moolenaar        main(sys.argv)
7427750ad47SMarcel Moolenaar    except:
7437750ad47SMarcel Moolenaar        # yes, this goes to stdout
74410ea6facSSimon J. Gerraty        print("ERROR: ", sys.exc_info()[1])
7457750ad47SMarcel Moolenaar        raise
7467750ad47SMarcel Moolenaar
747