xref: /freebsd/share/mk/meta2deps.py (revision c8245ceb47565e864a350e6aa33ba9a6461ebe02)
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"""
39f974ced3SSimon J. GerratySPDX-License-Identifier: BSD-2-Clause
40f974ced3SSimon J. Gerraty
417750ad47SMarcel MoolenaarRCSid:
42*c8245cebSSimon J. Gerraty	$Id: meta2deps.py,v 1.50 2024/09/27 00:08:36 sjg Exp $
437750ad47SMarcel Moolenaar
44960b77beSSimon J. Gerraty	Copyright (c) 2011-2020, Simon J. Gerraty
45960b77beSSimon J. Gerraty	Copyright (c) 2011-2017, Juniper Networks, Inc.
464ed4429cSSimon J. Gerraty	All rights reserved.
477750ad47SMarcel Moolenaar
487750ad47SMarcel Moolenaar	Redistribution and use in source and binary forms, with or without
497750ad47SMarcel Moolenaar	modification, are permitted provided that the following conditions
507750ad47SMarcel Moolenaar	are met:
517750ad47SMarcel Moolenaar	1. Redistributions of source code must retain the above copyright
527750ad47SMarcel Moolenaar	   notice, this list of conditions and the following disclaimer.
537750ad47SMarcel Moolenaar	2. Redistributions in binary form must reproduce the above copyright
547750ad47SMarcel Moolenaar	   notice, this list of conditions and the following disclaimer in the
557750ad47SMarcel Moolenaar	   documentation and/or other materials provided with the distribution.
567750ad47SMarcel Moolenaar
577750ad47SMarcel Moolenaar	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
587750ad47SMarcel Moolenaar	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
597750ad47SMarcel Moolenaar	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
607750ad47SMarcel Moolenaar	A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
617750ad47SMarcel Moolenaar	OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
627750ad47SMarcel Moolenaar	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
637750ad47SMarcel Moolenaar	LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
647750ad47SMarcel Moolenaar	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
657750ad47SMarcel Moolenaar	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
667750ad47SMarcel Moolenaar	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
677750ad47SMarcel Moolenaar	OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
687750ad47SMarcel Moolenaar
697750ad47SMarcel Moolenaar"""
707750ad47SMarcel Moolenaar
71bf7aa99aSSimon J. Gerratyimport os
72bf7aa99aSSimon J. Gerratyimport re
73bf7aa99aSSimon J. Gerratyimport sys
74bf7aa99aSSimon J. Gerratyimport stat
757750ad47SMarcel Moolenaar
767750ad47SMarcel Moolenaardef resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
777750ad47SMarcel Moolenaar    """
787750ad47SMarcel Moolenaar    Return an absolute path, resolving via cwd or last_dir if needed.
79f974ced3SSimon J. Gerraty
80f974ced3SSimon J. Gerraty    Cleanup any leading ``./`` and trailing ``/.``
817750ad47SMarcel Moolenaar    """
82f974ced3SSimon J. Gerraty    while path.endswith('/.'):
837750ad47SMarcel Moolenaar        path = path[0:-2]
84d5ddb276SSimon J. Gerraty    if len(path) > 0 and path[0] == '/':
85960b77beSSimon J. Gerraty        if os.path.exists(path):
867750ad47SMarcel Moolenaar            return path
87960b77beSSimon J. Gerraty        if debug > 2:
88960b77beSSimon J. Gerraty            print("skipping non-existent:", path, file=debug_out)
89960b77beSSimon J. Gerraty        return None
907750ad47SMarcel Moolenaar    if path == '.':
917750ad47SMarcel Moolenaar        return cwd
927750ad47SMarcel Moolenaar    if path.startswith('./'):
93f974ced3SSimon J. Gerraty        while path.startswith('./'):
94f974ced3SSimon J. Gerraty            path = path[1:]
95f974ced3SSimon J. Gerraty        return cwd + path
967750ad47SMarcel Moolenaar    if last_dir == cwd:
977750ad47SMarcel Moolenaar        last_dir = None
987750ad47SMarcel Moolenaar    for d in [last_dir, cwd]:
997750ad47SMarcel Moolenaar        if not d:
1007750ad47SMarcel Moolenaar            continue
101a6589ab7SSimon J. Gerraty        if path == '..':
102a6589ab7SSimon J. Gerraty            dw = d.split('/')
103a6589ab7SSimon J. Gerraty            p = '/'.join(dw[:-1])
104a6589ab7SSimon J. Gerraty            if not p:
105a6589ab7SSimon J. Gerraty                p = '/'
106a6589ab7SSimon J. Gerraty            return p
1077750ad47SMarcel Moolenaar        p = '/'.join([d,path])
1087750ad47SMarcel Moolenaar        if debug > 2:
10910ea6facSSimon J. Gerraty            print("looking for:", p, end=' ', file=debug_out)
1107750ad47SMarcel Moolenaar        if not os.path.exists(p):
1117750ad47SMarcel Moolenaar            if debug > 2:
11210ea6facSSimon J. Gerraty                print("nope", file=debug_out)
1137750ad47SMarcel Moolenaar            p = None
1147750ad47SMarcel Moolenaar            continue
1157750ad47SMarcel Moolenaar        if debug > 2:
11610ea6facSSimon J. Gerraty            print("found:", p, file=debug_out)
1177750ad47SMarcel Moolenaar        return p
1187750ad47SMarcel Moolenaar    return None
1197750ad47SMarcel Moolenaar
1206d4f05fdSSimon J. Gerratydef cleanpath(path):
1216d4f05fdSSimon J. Gerraty    """cleanup path without using realpath(3)"""
1226d4f05fdSSimon J. Gerraty    if path.startswith('/'):
1236d4f05fdSSimon J. Gerraty        r = '/'
1246d4f05fdSSimon J. Gerraty    else:
1256d4f05fdSSimon J. Gerraty        r = ''
1266d4f05fdSSimon J. Gerraty    p = []
1276d4f05fdSSimon J. Gerraty    w = path.split('/')
1286d4f05fdSSimon J. Gerraty    for d in w:
1296d4f05fdSSimon J. Gerraty        if not d or d == '.':
1306d4f05fdSSimon J. Gerraty            continue
1316d4f05fdSSimon J. Gerraty        if d == '..':
132a6589ab7SSimon J. Gerraty            try:
1336d4f05fdSSimon J. Gerraty                p.pop()
1346d4f05fdSSimon J. Gerraty                continue
135a6589ab7SSimon J. Gerraty            except:
136a6589ab7SSimon J. Gerraty                break
1376d4f05fdSSimon J. Gerraty        p.append(d)
1386d4f05fdSSimon J. Gerraty
1396d4f05fdSSimon J. Gerraty    return r + '/'.join(p)
1406d4f05fdSSimon J. Gerraty
1417750ad47SMarcel Moolenaardef abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
1427750ad47SMarcel Moolenaar    """
1437750ad47SMarcel Moolenaar    Return an absolute path, resolving via cwd or last_dir if needed.
1446d4f05fdSSimon J. Gerraty    this gets called a lot, so we try to avoid calling realpath.
1457750ad47SMarcel Moolenaar    """
146d5ddb276SSimon J. Gerraty    rpath = resolve(path, cwd, last_dir, debug, debug_out)
147d5ddb276SSimon J. Gerraty    if rpath:
148d5ddb276SSimon J. Gerraty        path = rpath
149960b77beSSimon J. Gerraty    elif len(path) > 0 and path[0] == '/':
150960b77beSSimon J. Gerraty        return None
151ccfb9654SSimon J. Gerraty    if (path.find('/') < 0 or
152ccfb9654SSimon J. Gerraty        path.find('./') > 0 or
153f974ced3SSimon J. Gerraty        path.find('/../') > 0 or
1546d4f05fdSSimon J. Gerraty        path.endswith('/..')):
1556d4f05fdSSimon J. Gerraty        path = cleanpath(path)
1567750ad47SMarcel Moolenaar    return path
1577750ad47SMarcel Moolenaar
1587750ad47SMarcel Moolenaardef sort_unique(list, cmp=None, key=None, reverse=False):
1593b26e5a4SSimon J. Gerraty    if sys.version_info[0] == 2:
1607750ad47SMarcel Moolenaar        list.sort(cmp, key, reverse)
1613b26e5a4SSimon J. Gerraty    else:
1623b26e5a4SSimon J. Gerraty        list.sort(reverse=reverse)
1637750ad47SMarcel Moolenaar    nl = []
1647750ad47SMarcel Moolenaar    le = None
1657750ad47SMarcel Moolenaar    for e in list:
1667750ad47SMarcel Moolenaar        if e == le:
1677750ad47SMarcel Moolenaar            continue
1686d4f05fdSSimon J. Gerraty        le = e
1697750ad47SMarcel Moolenaar        nl.append(e)
1707750ad47SMarcel Moolenaar    return nl
1717750ad47SMarcel Moolenaar
172bf062775SSimon J. Gerratydef add_trims(x):
173bf062775SSimon J. Gerraty    return ['/' + x + '/',
174bf062775SSimon J. Gerraty            '/' + x,
175bf062775SSimon J. Gerraty            x + '/',
176bf062775SSimon J. Gerraty            x]
177bf062775SSimon J. Gerraty
1783b26e5a4SSimon J. Gerratydef target_spec_exts(target_spec):
1793b26e5a4SSimon J. Gerraty    """return a list of dirdep extensions that could match target_spec"""
1803b26e5a4SSimon J. Gerraty
1813b26e5a4SSimon J. Gerraty    if target_spec.find(',') < 0:
1823b26e5a4SSimon J. Gerraty        return ['.'+target_spec]
1833b26e5a4SSimon J. Gerraty    w = target_spec.split(',')
1843b26e5a4SSimon J. Gerraty    n = len(w)
1853b26e5a4SSimon J. Gerraty    e = []
1863b26e5a4SSimon J. Gerraty    while n > 0:
1873b26e5a4SSimon J. Gerraty        e.append('.'+','.join(w[0:n]))
1883b26e5a4SSimon J. Gerraty        n -= 1
1893b26e5a4SSimon J. Gerraty    return e
1903b26e5a4SSimon J. Gerraty
1917750ad47SMarcel Moolenaarclass MetaFile:
1927750ad47SMarcel Moolenaar    """class to parse meta files generated by bmake."""
1937750ad47SMarcel Moolenaar
1947750ad47SMarcel Moolenaar    conf = None
1957750ad47SMarcel Moolenaar    dirdep_re = None
1967750ad47SMarcel Moolenaar    host_target = None
1977750ad47SMarcel Moolenaar    srctops = []
1987750ad47SMarcel Moolenaar    objroots = []
199ccfb9654SSimon J. Gerraty    excludes = []
2007750ad47SMarcel Moolenaar    seen = {}
2017750ad47SMarcel Moolenaar    obj_deps = []
2027750ad47SMarcel Moolenaar    src_deps = []
2037750ad47SMarcel Moolenaar    file_deps = []
2047750ad47SMarcel Moolenaar
2057750ad47SMarcel Moolenaar    def __init__(self, name, conf={}):
2067750ad47SMarcel Moolenaar        """if name is set we will parse it now.
207f974ced3SSimon J. Gerraty        conf can have the follwing keys:
2087750ad47SMarcel Moolenaar
2097750ad47SMarcel Moolenaar        SRCTOPS list of tops of the src tree(s).
2107750ad47SMarcel Moolenaar
2117750ad47SMarcel Moolenaar        CURDIR  the src directory 'bmake' was run from.
2127750ad47SMarcel Moolenaar
2137750ad47SMarcel Moolenaar        RELDIR  the relative path from SRCTOP to CURDIR
2147750ad47SMarcel Moolenaar
2157750ad47SMarcel Moolenaar        MACHINE the machine we built for.
2167750ad47SMarcel Moolenaar                set to 'none' if we are not cross-building.
21751048477SSimon J. Gerraty                More specifically if machine cannot be deduced from objdirs.
2187750ad47SMarcel Moolenaar
219bf062775SSimon J. Gerraty        TARGET_SPEC
220bf062775SSimon J. Gerraty                Sometimes MACHINE isn't enough.
221bf062775SSimon J. Gerraty
2227750ad47SMarcel Moolenaar        HOST_TARGET
223ccfb9654SSimon J. Gerraty                when we build for the pseudo machine 'host'
2247750ad47SMarcel Moolenaar                the object tree uses HOST_TARGET rather than MACHINE.
2257750ad47SMarcel Moolenaar
2267750ad47SMarcel Moolenaar        OBJROOTS a list of the common prefix for all obj dirs it might
2277750ad47SMarcel Moolenaar                end in '/' or '-'.
2287750ad47SMarcel Moolenaar
2297750ad47SMarcel Moolenaar        DPDEPS  names an optional file to which per file dependencies
2307750ad47SMarcel Moolenaar                will be appended.
2317750ad47SMarcel Moolenaar                For example if 'some/path/foo.h' is read from SRCTOP
2327750ad47SMarcel Moolenaar                then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output.
2337750ad47SMarcel Moolenaar                This can allow 'bmake' to learn all the dirs within
2347750ad47SMarcel Moolenaar                the tree that depend on 'foo.h'
2357750ad47SMarcel Moolenaar
236ccfb9654SSimon J. Gerraty        EXCLUDES
237ccfb9654SSimon J. Gerraty                A list of paths to ignore.
238ccfb9654SSimon J. Gerraty                ccache(1) can otherwise be trouble.
239ccfb9654SSimon J. Gerraty
2407750ad47SMarcel Moolenaar        debug   desired debug level
2417750ad47SMarcel Moolenaar
2427750ad47SMarcel Moolenaar        debug_out open file to send debug output to (sys.stderr)
2437750ad47SMarcel Moolenaar
2447750ad47SMarcel Moolenaar        """
2457750ad47SMarcel Moolenaar
2467750ad47SMarcel Moolenaar        self.name = name
2473b26e5a4SSimon J. Gerraty        self.debug = conf.get('debug', 0)
2483b26e5a4SSimon J. Gerraty        self.debug_out = conf.get('debug_out', sys.stderr)
2497750ad47SMarcel Moolenaar
2503b26e5a4SSimon J. Gerraty        self.machine = conf.get('MACHINE', '')
2513b26e5a4SSimon J. Gerraty        self.machine_arch = conf.get('MACHINE_ARCH', '')
2523b26e5a4SSimon J. Gerraty        self.target_spec = conf.get('TARGET_SPEC', self.machine)
2533b26e5a4SSimon J. Gerraty        self.exts = target_spec_exts(self.target_spec)
2543b26e5a4SSimon J. Gerraty        self.curdir = conf.get('CURDIR')
2553b26e5a4SSimon J. Gerraty        self.reldir = conf.get('RELDIR')
2563b26e5a4SSimon J. Gerraty        self.dpdeps = conf.get('DPDEPS')
257bf7aa99aSSimon J. Gerraty        self.pids = {}
258d5ddb276SSimon J. Gerraty        self.line = 0
2594ed4429cSSimon J. Gerraty
2607750ad47SMarcel Moolenaar        if not self.conf:
2617750ad47SMarcel Moolenaar            # some of the steps below we want to do only once
2627750ad47SMarcel Moolenaar            self.conf = conf
2633b26e5a4SSimon J. Gerraty            self.host_target = conf.get('HOST_TARGET')
2643b26e5a4SSimon J. Gerraty            for srctop in conf.get('SRCTOPS', []):
2657750ad47SMarcel Moolenaar                if srctop[-1] != '/':
2667750ad47SMarcel Moolenaar                    srctop += '/'
2677750ad47SMarcel Moolenaar                if not srctop in self.srctops:
2687750ad47SMarcel Moolenaar                    self.srctops.append(srctop)
269fbc1b149SSimon J. Gerraty                _srctop = os.path.realpath(srctop)
270fbc1b149SSimon J. Gerraty                if _srctop[-1] != '/':
271fbc1b149SSimon J. Gerraty                    _srctop += '/'
272fbc1b149SSimon J. Gerraty                if not _srctop in self.srctops:
273fbc1b149SSimon J. Gerraty                    self.srctops.append(_srctop)
2747750ad47SMarcel Moolenaar
275bf062775SSimon J. Gerraty            trim_list = add_trims(self.machine)
2768c95c434SSimon J. Gerraty            if self.machine == 'host':
277bf062775SSimon J. Gerraty                trim_list += add_trims(self.host_target)
2783b26e5a4SSimon J. Gerraty            if self.target_spec != self.machine:
279bf062775SSimon J. Gerraty                trim_list += add_trims(self.target_spec)
280876336c8SSimon J. Gerraty
2813b26e5a4SSimon J. Gerraty            for objroot in conf.get('OBJROOTS', []):
2828c95c434SSimon J. Gerraty                for e in trim_list:
2834ed4429cSSimon J. Gerraty                    if objroot.endswith(e):
2844ed4429cSSimon J. Gerraty                        # this is not what we want - fix it
2854ed4429cSSimon J. Gerraty                        objroot = objroot[0:-len(e)]
286b47b9f6bSSimon J. Gerraty
287b47b9f6bSSimon J. Gerraty                if objroot[-1] != '/':
2884ed4429cSSimon J. Gerraty                    objroot += '/'
2897750ad47SMarcel Moolenaar                if not objroot in self.objroots:
2907750ad47SMarcel Moolenaar                    self.objroots.append(objroot)
2917750ad47SMarcel Moolenaar                    _objroot = os.path.realpath(objroot)
2927750ad47SMarcel Moolenaar                    if objroot[-1] == '/':
2937750ad47SMarcel Moolenaar                        _objroot += '/'
2947750ad47SMarcel Moolenaar                    if not _objroot in self.objroots:
2957750ad47SMarcel Moolenaar                        self.objroots.append(_objroot)
2967750ad47SMarcel Moolenaar
297*c8245cebSSimon J. Gerraty            self.sb = conf.get('SB', '')
2984ed4429cSSimon J. Gerraty            # we want the longest match
2994ed4429cSSimon J. Gerraty            self.srctops.sort(reverse=True)
3004ed4429cSSimon J. Gerraty            self.objroots.sort(reverse=True)
3014ed4429cSSimon J. Gerraty
3023b26e5a4SSimon J. Gerraty            self.excludes = conf.get('EXCLUDES', [])
303ccfb9654SSimon J. Gerraty
3047750ad47SMarcel Moolenaar            if self.debug:
30510ea6facSSimon J. Gerraty                print("host_target=", self.host_target, file=self.debug_out)
30610ea6facSSimon J. Gerraty                print("srctops=", self.srctops, file=self.debug_out)
30710ea6facSSimon J. Gerraty                print("objroots=", self.objroots, file=self.debug_out)
308ccfb9654SSimon J. Gerraty                print("excludes=", self.excludes, file=self.debug_out)
3093b26e5a4SSimon J. Gerraty                print("ext_list=", self.exts, file=self.debug_out)
3107750ad47SMarcel Moolenaar
3117750ad47SMarcel Moolenaar            self.dirdep_re = re.compile(r'([^/]+)/(.+)')
3127750ad47SMarcel Moolenaar
3137750ad47SMarcel Moolenaar        if self.dpdeps and not self.reldir:
3147750ad47SMarcel Moolenaar            if self.debug:
31510ea6facSSimon J. Gerraty                print("need reldir:", end=' ', file=self.debug_out)
3167750ad47SMarcel Moolenaar            if self.curdir:
3177750ad47SMarcel Moolenaar                srctop = self.find_top(self.curdir, self.srctops)
3187750ad47SMarcel Moolenaar                if srctop:
3197750ad47SMarcel Moolenaar                    self.reldir = self.curdir.replace(srctop,'')
3207750ad47SMarcel Moolenaar                    if self.debug:
32110ea6facSSimon J. Gerraty                        print(self.reldir, file=self.debug_out)
3227750ad47SMarcel Moolenaar            if not self.reldir:
3237750ad47SMarcel Moolenaar                self.dpdeps = None      # we cannot do it?
3247750ad47SMarcel Moolenaar
325876336c8SSimon J. Gerraty        self.cwd = os.getcwd()          # make sure this is initialized
326ccfb9654SSimon J. Gerraty        self.last_dir = self.cwd
327876336c8SSimon J. Gerraty
3287750ad47SMarcel Moolenaar        if name:
329d5ddb276SSimon J. Gerraty            self.try_parse()
3307750ad47SMarcel Moolenaar
3317750ad47SMarcel Moolenaar    def reset(self):
3327750ad47SMarcel Moolenaar        """reset state if we are being passed meta files from multiple directories."""
3337750ad47SMarcel Moolenaar        self.seen = {}
3347750ad47SMarcel Moolenaar        self.obj_deps = []
3357750ad47SMarcel Moolenaar        self.src_deps = []
3367750ad47SMarcel Moolenaar        self.file_deps = []
3377750ad47SMarcel Moolenaar
3387750ad47SMarcel Moolenaar    def dirdeps(self, sep='\n'):
3397750ad47SMarcel Moolenaar        """return DIRDEPS"""
3407750ad47SMarcel Moolenaar        return sep.strip() + sep.join(self.obj_deps)
3417750ad47SMarcel Moolenaar
3427750ad47SMarcel Moolenaar    def src_dirdeps(self, sep='\n'):
3437750ad47SMarcel Moolenaar        """return SRC_DIRDEPS"""
3447750ad47SMarcel Moolenaar        return sep.strip() + sep.join(self.src_deps)
3457750ad47SMarcel Moolenaar
3467750ad47SMarcel Moolenaar    def file_depends(self, out=None):
3477750ad47SMarcel Moolenaar        """Append DPDEPS_${file} += ${RELDIR}
3487750ad47SMarcel Moolenaar        for each file we saw, to the output file."""
3497750ad47SMarcel Moolenaar        if not self.reldir:
3507750ad47SMarcel Moolenaar            return None
3517750ad47SMarcel Moolenaar        for f in sort_unique(self.file_deps):
35210ea6facSSimon J. Gerraty            print('DPDEPS_%s += %s' % (f, self.reldir), file=out)
353b47b9f6bSSimon J. Gerraty        # these entries provide for reverse DIRDEPS lookup
354b47b9f6bSSimon J. Gerraty        for f in self.obj_deps:
355b47b9f6bSSimon J. Gerraty            print('DEPDIRS_%s += %s' % (f, self.reldir), file=out)
3567750ad47SMarcel Moolenaar
3577750ad47SMarcel Moolenaar    def seenit(self, dir):
3587750ad47SMarcel Moolenaar        """rememer that we have seen dir."""
3597750ad47SMarcel Moolenaar        self.seen[dir] = 1
3607750ad47SMarcel Moolenaar
3617750ad47SMarcel Moolenaar    def add(self, list, data, clue=''):
3627750ad47SMarcel Moolenaar        """add data to list if it isn't already there."""
3637750ad47SMarcel Moolenaar        if data not in list:
3647750ad47SMarcel Moolenaar            list.append(data)
3657750ad47SMarcel Moolenaar            if self.debug:
36610ea6facSSimon J. Gerraty                print("%s: %sAdd: %s" % (self.name, clue, data), file=self.debug_out)
3677750ad47SMarcel Moolenaar
3687750ad47SMarcel Moolenaar    def find_top(self, path, list):
369ccfb9654SSimon J. Gerraty        """the logical tree may be split across multiple trees"""
3707750ad47SMarcel Moolenaar        for top in list:
3717750ad47SMarcel Moolenaar            if path.startswith(top):
3727750ad47SMarcel Moolenaar                if self.debug > 2:
37310ea6facSSimon J. Gerraty                    print("found in", top, file=self.debug_out)
3747750ad47SMarcel Moolenaar                return top
3757750ad47SMarcel Moolenaar        return None
3767750ad47SMarcel Moolenaar
3777750ad47SMarcel Moolenaar    def find_obj(self, objroot, dir, path, input):
3787750ad47SMarcel Moolenaar        """return path within objroot, taking care of .dirdep files"""
3797750ad47SMarcel Moolenaar        ddep = None
3807750ad47SMarcel Moolenaar        for ddepf in [path + '.dirdep', dir + '/.dirdep']:
3817750ad47SMarcel Moolenaar            if not ddep and os.path.exists(ddepf):
38210ea6facSSimon J. Gerraty                ddep = open(ddepf, 'r').readline().strip('# \n')
3837750ad47SMarcel Moolenaar                if self.debug > 1:
38410ea6facSSimon J. Gerraty                    print("found %s: %s\n" % (ddepf, ddep), file=self.debug_out)
3853b26e5a4SSimon J. Gerraty                for e in self.exts:
3863b26e5a4SSimon J. Gerraty                    if ddep.endswith(e):
3873b26e5a4SSimon J. Gerraty                        ddep = ddep[0:-len(e)]
3883b26e5a4SSimon J. Gerraty                        break
3897750ad47SMarcel Moolenaar
3907750ad47SMarcel Moolenaar        if not ddep:
3917750ad47SMarcel Moolenaar            # no .dirdeps, so remember that we've seen the raw input
3927750ad47SMarcel Moolenaar            self.seenit(input)
3937750ad47SMarcel Moolenaar            self.seenit(dir)
3947750ad47SMarcel Moolenaar            if self.machine == 'none':
3957750ad47SMarcel Moolenaar                if dir.startswith(objroot):
3967750ad47SMarcel Moolenaar                    return dir.replace(objroot,'')
3977750ad47SMarcel Moolenaar                return None
3987750ad47SMarcel Moolenaar            m = self.dirdep_re.match(dir.replace(objroot,''))
3997750ad47SMarcel Moolenaar            if m:
4007750ad47SMarcel Moolenaar                ddep = m.group(2)
4017750ad47SMarcel Moolenaar                dmachine = m.group(1)
4027750ad47SMarcel Moolenaar                if dmachine != self.machine:
4037750ad47SMarcel Moolenaar                    if not (self.machine == 'host' and
4047750ad47SMarcel Moolenaar                            dmachine == self.host_target):
4057750ad47SMarcel Moolenaar                        if self.debug > 2:
40610ea6facSSimon J. Gerraty                            print("adding .%s to %s" % (dmachine, ddep), file=self.debug_out)
4077750ad47SMarcel Moolenaar                        ddep += '.' + dmachine
4087750ad47SMarcel Moolenaar
4097750ad47SMarcel Moolenaar        return ddep
4107750ad47SMarcel Moolenaar
411d5ddb276SSimon J. Gerraty    def try_parse(self, name=None, file=None):
412d5ddb276SSimon J. Gerraty        """give file and line number causing exception"""
413d5ddb276SSimon J. Gerraty        try:
414d5ddb276SSimon J. Gerraty            self.parse(name, file)
415d5ddb276SSimon J. Gerraty        except:
416d5ddb276SSimon J. Gerraty            # give a useful clue
41710ea6facSSimon J. Gerraty            print('{}:{}: '.format(self.name, self.line), end=' ', file=sys.stderr)
418d5ddb276SSimon J. Gerraty            raise
419d5ddb276SSimon J. Gerraty
4207750ad47SMarcel Moolenaar    def parse(self, name=None, file=None):
4217750ad47SMarcel Moolenaar        """A meta file looks like:
4227750ad47SMarcel Moolenaar
4237750ad47SMarcel Moolenaar        # Meta data file "path"
4247750ad47SMarcel Moolenaar        CMD "command-line"
4257750ad47SMarcel Moolenaar        CWD "cwd"
4267750ad47SMarcel Moolenaar        TARGET "target"
4277750ad47SMarcel Moolenaar        -- command output --
4287750ad47SMarcel Moolenaar        -- filemon acquired metadata --
4297750ad47SMarcel Moolenaar        # buildmon version 3
4307750ad47SMarcel Moolenaar        V 3
4317750ad47SMarcel Moolenaar        C "pid" "cwd"
4327750ad47SMarcel Moolenaar        E "pid" "path"
4337750ad47SMarcel Moolenaar        F "pid" "child"
4347750ad47SMarcel Moolenaar        R "pid" "path"
4357750ad47SMarcel Moolenaar        W "pid" "path"
4367750ad47SMarcel Moolenaar        X "pid" "status"
4377750ad47SMarcel Moolenaar        D "pid" "path"
4387750ad47SMarcel Moolenaar        L "pid" "src" "target"
4397750ad47SMarcel Moolenaar        M "pid" "old" "new"
4407750ad47SMarcel Moolenaar        S "pid" "path"
4417750ad47SMarcel Moolenaar        # Bye bye
4427750ad47SMarcel Moolenaar
4437750ad47SMarcel Moolenaar        We go to some effort to avoid processing a dependency more than once.
4447750ad47SMarcel Moolenaar        Of the above record types only C,E,F,L,R,V and W are of interest.
4457750ad47SMarcel Moolenaar        """
4467750ad47SMarcel Moolenaar
4477750ad47SMarcel Moolenaar        version = 0                     # unknown
4487750ad47SMarcel Moolenaar        if name:
4497750ad47SMarcel Moolenaar            self.name = name;
4507750ad47SMarcel Moolenaar        if file:
4517750ad47SMarcel Moolenaar            f = file
452ccfb9654SSimon J. Gerraty            cwd = self.last_dir = self.cwd
4537750ad47SMarcel Moolenaar        else:
45410ea6facSSimon J. Gerraty            f = open(self.name, 'r')
4557750ad47SMarcel Moolenaar        skip = True
4567750ad47SMarcel Moolenaar        pid_cwd = {}
4577750ad47SMarcel Moolenaar        pid_last_dir = {}
4587750ad47SMarcel Moolenaar        last_pid = 0
459bf7aa99aSSimon J. Gerraty        eof_token = False
4607750ad47SMarcel Moolenaar
461d5ddb276SSimon J. Gerraty        self.line = 0
4627750ad47SMarcel Moolenaar        if self.curdir:
4637750ad47SMarcel Moolenaar            self.seenit(self.curdir)    # we ignore this
4647750ad47SMarcel Moolenaar
465*c8245cebSSimon J. Gerraty        if self.sb and self.name.startswith(self.sb):
466*c8245cebSSimon J. Gerraty            error_name = self.name.replace(self.sb+'/','')
467*c8245cebSSimon J. Gerraty        else:
468*c8245cebSSimon J. Gerraty            error_name = self.name
469bf7aa99aSSimon J. Gerraty        interesting = '#CEFLRVX'
4707750ad47SMarcel Moolenaar        for line in f:
471d5ddb276SSimon J. Gerraty            self.line += 1
4727750ad47SMarcel Moolenaar            # ignore anything we don't care about
4737750ad47SMarcel Moolenaar            if not line[0] in interesting:
4747750ad47SMarcel Moolenaar                continue
4757750ad47SMarcel Moolenaar            if self.debug > 2:
47610ea6facSSimon J. Gerraty                print("input:", line, end=' ', file=self.debug_out)
4777750ad47SMarcel Moolenaar            w = line.split()
4787750ad47SMarcel Moolenaar
4797750ad47SMarcel Moolenaar            if skip:
4807750ad47SMarcel Moolenaar                if w[0] == 'V':
4817750ad47SMarcel Moolenaar                    skip = False
4827750ad47SMarcel Moolenaar                    version = int(w[1])
4837750ad47SMarcel Moolenaar                    """
4847750ad47SMarcel Moolenaar                    if version < 4:
4857750ad47SMarcel Moolenaar                        # we cannot ignore 'W' records
4867750ad47SMarcel Moolenaar                        # as they may be 'rw'
4877750ad47SMarcel Moolenaar                        interesting += 'W'
4887750ad47SMarcel Moolenaar                    """
4897750ad47SMarcel Moolenaar                elif w[0] == 'CWD':
490ccfb9654SSimon J. Gerraty                    self.cwd = cwd = self.last_dir = w[1]
4917750ad47SMarcel Moolenaar                    self.seenit(cwd)    # ignore this
4927750ad47SMarcel Moolenaar                    if self.debug:
49310ea6facSSimon J. Gerraty                        print("%s: CWD=%s" % (self.name, cwd), file=self.debug_out)
4947750ad47SMarcel Moolenaar                continue
4957750ad47SMarcel Moolenaar
496bf7aa99aSSimon J. Gerraty            if w[0] == '#':
497bf7aa99aSSimon J. Gerraty                # check the file has not been truncated
498bf7aa99aSSimon J. Gerraty                if line.find('Bye') > 0:
499bf7aa99aSSimon J. Gerraty                    eof_token = True
500bf7aa99aSSimon J. Gerraty                continue
501bf7aa99aSSimon J. Gerraty
5027750ad47SMarcel Moolenaar            pid = int(w[1])
5037750ad47SMarcel Moolenaar            if pid != last_pid:
5047750ad47SMarcel Moolenaar                if last_pid:
505ccfb9654SSimon J. Gerraty                    pid_last_dir[last_pid] = self.last_dir
5063b26e5a4SSimon J. Gerraty                cwd = pid_cwd.get(pid, self.cwd)
5073b26e5a4SSimon J. Gerraty                self.last_dir = pid_last_dir.get(pid, self.cwd)
5087750ad47SMarcel Moolenaar                last_pid = pid
5097750ad47SMarcel Moolenaar
5107750ad47SMarcel Moolenaar            # process operations
5117750ad47SMarcel Moolenaar            if w[0] == 'F':
5127750ad47SMarcel Moolenaar                npid = int(w[2])
5137750ad47SMarcel Moolenaar                pid_cwd[npid] = cwd
5147750ad47SMarcel Moolenaar                pid_last_dir[npid] = cwd
5157750ad47SMarcel Moolenaar                last_pid = npid
5167750ad47SMarcel Moolenaar                continue
5177750ad47SMarcel Moolenaar            elif w[0] == 'C':
5187750ad47SMarcel Moolenaar                cwd = abspath(w[2], cwd, None, self.debug, self.debug_out)
519960b77beSSimon J. Gerraty                if not cwd:
520960b77beSSimon J. Gerraty                    cwd = w[2]
521960b77beSSimon J. Gerraty                    if self.debug > 1:
522960b77beSSimon J. Gerraty                        print("missing cwd=", cwd, file=self.debug_out)
5237750ad47SMarcel Moolenaar                if cwd.endswith('/.'):
5247750ad47SMarcel Moolenaar                    cwd = cwd[0:-2]
525b47b9f6bSSimon J. Gerraty                self.last_dir = pid_last_dir[pid] = cwd
526b47b9f6bSSimon J. Gerraty                pid_cwd[pid] = cwd
5277750ad47SMarcel Moolenaar                if self.debug > 1:
52810ea6facSSimon J. Gerraty                    print("cwd=", cwd, file=self.debug_out)
5297750ad47SMarcel Moolenaar                continue
5307750ad47SMarcel Moolenaar
531bf7aa99aSSimon J. Gerraty            if w[0] == 'X':
532bf7aa99aSSimon J. Gerraty                try:
533bf7aa99aSSimon J. Gerraty                    del self.pids[pid]
534bf7aa99aSSimon J. Gerraty                except KeyError:
535bf7aa99aSSimon J. Gerraty                    pass
536bf7aa99aSSimon J. Gerraty                continue
537bf7aa99aSSimon J. Gerraty
5387750ad47SMarcel Moolenaar            if w[2] in self.seen:
5397750ad47SMarcel Moolenaar                if self.debug > 2:
54010ea6facSSimon J. Gerraty                    print("seen:", w[2], file=self.debug_out)
5417750ad47SMarcel Moolenaar                continue
5427750ad47SMarcel Moolenaar            # file operations
5437750ad47SMarcel Moolenaar            if w[0] in 'ML':
544ccfb9654SSimon J. Gerraty                # these are special, tread src as read and
545ccfb9654SSimon J. Gerraty                # target as write
546960b77beSSimon J. Gerraty                self.parse_path(w[2].strip("'"), cwd, 'R', w)
547960b77beSSimon J. Gerraty                self.parse_path(w[3].strip("'"), cwd, 'W', w)
548ccfb9654SSimon J. Gerraty                continue
549ccfb9654SSimon J. Gerraty            elif w[0] in 'ERWS':
5507750ad47SMarcel Moolenaar                path = w[2]
551bf7aa99aSSimon J. Gerraty                if w[0] == 'E':
552bf7aa99aSSimon J. Gerraty                    self.pids[pid] = path
553bf7aa99aSSimon J. Gerraty                elif path == '.':
554960b77beSSimon J. Gerraty                    continue
555ccfb9654SSimon J. Gerraty                self.parse_path(path, cwd, w[0], w)
556ccfb9654SSimon J. Gerraty
557bf7aa99aSSimon J. Gerraty        if version == 0:
558*c8245cebSSimon J. Gerraty            raise AssertionError('missing filemon data: {}'.format(error_name))
559bf7aa99aSSimon J. Gerraty        if not eof_token:
560*c8245cebSSimon J. Gerraty            raise AssertionError('truncated filemon data: {}'.format(error_name))
561bf7aa99aSSimon J. Gerraty
562bf7aa99aSSimon J. Gerraty        setid_pids = []
563bf7aa99aSSimon J. Gerraty        # self.pids should be empty!
564bf7aa99aSSimon J. Gerraty        for pid,path in self.pids.items():
565bf7aa99aSSimon J. Gerraty            try:
566bf7aa99aSSimon J. Gerraty                # no guarantee that path is still valid
567bf7aa99aSSimon J. Gerraty                if os.stat(path).st_mode & (stat.S_ISUID|stat.S_ISGID):
568bf7aa99aSSimon J. Gerraty                    # we do not expect anything after Exec
569bf7aa99aSSimon J. Gerraty                    setid_pids.append(pid)
570bf7aa99aSSimon J. Gerraty                    continue
571bf7aa99aSSimon J. Gerraty            except:
572bf7aa99aSSimon J. Gerraty                # we do not care why the above fails,
573bf7aa99aSSimon J. Gerraty                # we do not want to miss the ERROR below.
574bf7aa99aSSimon J. Gerraty                pass
575bf7aa99aSSimon J. Gerraty            print("ERROR: missing eXit for {} pid {}".format(path, pid))
576bf7aa99aSSimon J. Gerraty        for pid in setid_pids:
577bf7aa99aSSimon J. Gerraty            del self.pids[pid]
578*c8245cebSSimon J. Gerraty        if len(self.pids) > 0:
579*c8245cebSSimon J. Gerraty            raise AssertionError('bad filemon data - missing eXits: {}'.format(error_name))
580ccfb9654SSimon J. Gerraty        if not file:
581ccfb9654SSimon J. Gerraty            f.close()
582ccfb9654SSimon J. Gerraty
583c0339e7dSSimon J. Gerraty    def is_src(self, base, dir, rdir):
584c0339e7dSSimon J. Gerraty        """is base in srctop"""
585c0339e7dSSimon J. Gerraty        for dir in [dir,rdir]:
586c0339e7dSSimon J. Gerraty            if not dir:
587c0339e7dSSimon J. Gerraty                continue
588c0339e7dSSimon J. Gerraty            path = '/'.join([dir,base])
589c0339e7dSSimon J. Gerraty            srctop = self.find_top(path, self.srctops)
590c0339e7dSSimon J. Gerraty            if srctop:
591c0339e7dSSimon J. Gerraty                if self.dpdeps:
592c0339e7dSSimon J. Gerraty                    self.add(self.file_deps, path.replace(srctop,''), 'file')
593c0339e7dSSimon J. Gerraty                self.add(self.src_deps, dir.replace(srctop,''), 'src')
594c0339e7dSSimon J. Gerraty                self.seenit(dir)
595c0339e7dSSimon J. Gerraty                return True
596c0339e7dSSimon J. Gerraty        return False
597c0339e7dSSimon J. Gerraty
598ccfb9654SSimon J. Gerraty    def parse_path(self, path, cwd, op=None, w=[]):
599ccfb9654SSimon J. Gerraty        """look at a path for the op specified"""
600ccfb9654SSimon J. Gerraty
601ccfb9654SSimon J. Gerraty        if not op:
602ccfb9654SSimon J. Gerraty            op = w[0]
603ccfb9654SSimon J. Gerraty
604fbc1b149SSimon J. Gerraty        # we are never interested in .dirdep files as dependencies
605fbc1b149SSimon J. Gerraty        if path.endswith('.dirdep'):
606ccfb9654SSimon J. Gerraty            return
607ccfb9654SSimon J. Gerraty        for p in self.excludes:
608ccfb9654SSimon J. Gerraty            if p and path.startswith(p):
609ccfb9654SSimon J. Gerraty                if self.debug > 2:
610e1dfa657SBryan Drewery                    print("exclude:", p, path, file=self.debug_out)
611ccfb9654SSimon J. Gerraty                return
6127750ad47SMarcel Moolenaar        # we don't want to resolve the last component if it is
6137750ad47SMarcel Moolenaar        # a symlink
614ccfb9654SSimon J. Gerraty        path = resolve(path, cwd, self.last_dir, self.debug, self.debug_out)
6157750ad47SMarcel Moolenaar        if not path:
616ccfb9654SSimon J. Gerraty            return
6177750ad47SMarcel Moolenaar        dir,base = os.path.split(path)
6187750ad47SMarcel Moolenaar        if dir in self.seen:
6197750ad47SMarcel Moolenaar            if self.debug > 2:
62010ea6facSSimon J. Gerraty                print("seen:", dir, file=self.debug_out)
621ccfb9654SSimon J. Gerraty            return
6227750ad47SMarcel Moolenaar        # we can have a path in an objdir which is a link
6237750ad47SMarcel Moolenaar        # to the src dir, we may need to add dependencies for each
6247750ad47SMarcel Moolenaar        rdir = dir
625ccfb9654SSimon J. Gerraty        dir = abspath(dir, cwd, self.last_dir, self.debug, self.debug_out)
6263b26e5a4SSimon J. Gerraty        if dir:
6276d4f05fdSSimon J. Gerraty            rdir = os.path.realpath(dir)
6283b26e5a4SSimon J. Gerraty        else:
6293b26e5a4SSimon J. Gerraty            dir = rdir
630c0339e7dSSimon J. Gerraty        if rdir == dir:
631c0339e7dSSimon J. Gerraty            rdir = None
6327750ad47SMarcel Moolenaar        # now put path back together
6337750ad47SMarcel Moolenaar        path = '/'.join([dir,base])
6347750ad47SMarcel Moolenaar        if self.debug > 1:
63510ea6facSSimon J. Gerraty            print("raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path), file=self.debug_out)
636ccfb9654SSimon J. Gerraty        if op in 'RWS':
637ccfb9654SSimon J. Gerraty            if path in [self.last_dir, cwd, self.cwd, self.curdir]:
6387750ad47SMarcel Moolenaar                if self.debug > 1:
63910ea6facSSimon J. Gerraty                    print("skipping:", path, file=self.debug_out)
640ccfb9654SSimon J. Gerraty                return
6417750ad47SMarcel Moolenaar            if os.path.isdir(path):
642ccfb9654SSimon J. Gerraty                if op in 'RW':
643ccfb9654SSimon J. Gerraty                    self.last_dir = path;
6447750ad47SMarcel Moolenaar                if self.debug > 1:
645ccfb9654SSimon J. Gerraty                    print("ldir=", self.last_dir, file=self.debug_out)
646ccfb9654SSimon J. Gerraty                return
6477750ad47SMarcel Moolenaar
648960b77beSSimon J. Gerraty        if op in 'ER':
6497750ad47SMarcel Moolenaar            # finally, we get down to it
6507750ad47SMarcel Moolenaar            if dir == self.cwd or dir == self.curdir:
651ccfb9654SSimon J. Gerraty                return
652c0339e7dSSimon J. Gerraty            if self.is_src(base, dir, rdir):
6537750ad47SMarcel Moolenaar                self.seenit(w[2])
654c0339e7dSSimon J. Gerraty                if not rdir:
655ccfb9654SSimon J. Gerraty                    return
6567750ad47SMarcel Moolenaar
6577750ad47SMarcel Moolenaar            objroot = None
6587750ad47SMarcel Moolenaar            for dir in [dir,rdir]:
6597750ad47SMarcel Moolenaar                if not dir:
6607750ad47SMarcel Moolenaar                    continue
6617750ad47SMarcel Moolenaar                objroot = self.find_top(dir, self.objroots)
6627750ad47SMarcel Moolenaar                if objroot:
6637750ad47SMarcel Moolenaar                    break
6647750ad47SMarcel Moolenaar            if objroot:
6657750ad47SMarcel Moolenaar                ddep = self.find_obj(objroot, dir, path, w[2])
6667750ad47SMarcel Moolenaar                if ddep:
6677750ad47SMarcel Moolenaar                    self.add(self.obj_deps, ddep, 'obj')
668b47b9f6bSSimon J. Gerraty                    if self.dpdeps and objroot.endswith('/stage/'):
669b47b9f6bSSimon J. Gerraty                        sp = '/'.join(path.replace(objroot,'').split('/')[1:])
670b47b9f6bSSimon J. Gerraty                        self.add(self.file_deps, sp, 'file')
6717750ad47SMarcel Moolenaar            else:
6727750ad47SMarcel Moolenaar                # don't waste time looking again
6737750ad47SMarcel Moolenaar                self.seenit(w[2])
6747750ad47SMarcel Moolenaar                self.seenit(dir)
6757750ad47SMarcel Moolenaar
6767750ad47SMarcel Moolenaar
6777750ad47SMarcel Moolenaardef main(argv, klass=MetaFile, xopts='', xoptf=None):
6787750ad47SMarcel Moolenaar    """Simple driver for class MetaFile.
6797750ad47SMarcel Moolenaar
6807750ad47SMarcel Moolenaar    Usage:
6817750ad47SMarcel Moolenaar        script [options] [key=value ...] "meta" ...
6827750ad47SMarcel Moolenaar
6837750ad47SMarcel Moolenaar    Options and key=value pairs contribute to the
6847750ad47SMarcel Moolenaar    dictionary passed to MetaFile.
6857750ad47SMarcel Moolenaar
6867750ad47SMarcel Moolenaar    -S "SRCTOP"
6877750ad47SMarcel Moolenaar                add "SRCTOP" to the "SRCTOPS" list.
6887750ad47SMarcel Moolenaar
6897750ad47SMarcel Moolenaar    -C "CURDIR"
6907750ad47SMarcel Moolenaar
6917750ad47SMarcel Moolenaar    -O "OBJROOT"
6927750ad47SMarcel Moolenaar                add "OBJROOT" to the "OBJROOTS" list.
6937750ad47SMarcel Moolenaar
6947750ad47SMarcel Moolenaar    -m "MACHINE"
6957750ad47SMarcel Moolenaar
696bf062775SSimon J. Gerraty    -a "MACHINE_ARCH"
697bf062775SSimon J. Gerraty
6987750ad47SMarcel Moolenaar    -H "HOST_TARGET"
6997750ad47SMarcel Moolenaar
7007750ad47SMarcel Moolenaar    -D "DPDEPS"
7017750ad47SMarcel Moolenaar
7027750ad47SMarcel Moolenaar    -d  bumps debug level
7037750ad47SMarcel Moolenaar
7047750ad47SMarcel Moolenaar    """
7057750ad47SMarcel Moolenaar    import getopt
7067750ad47SMarcel Moolenaar
7077750ad47SMarcel Moolenaar    # import Psyco if we can
7087750ad47SMarcel Moolenaar    # it can speed things up quite a bit
7097750ad47SMarcel Moolenaar    have_psyco = 0
7107750ad47SMarcel Moolenaar    try:
7117750ad47SMarcel Moolenaar        import psyco
7127750ad47SMarcel Moolenaar        psyco.full()
7137750ad47SMarcel Moolenaar        have_psyco = 1
7147750ad47SMarcel Moolenaar    except:
7157750ad47SMarcel Moolenaar        pass
7167750ad47SMarcel Moolenaar
7177750ad47SMarcel Moolenaar    conf = {
7187750ad47SMarcel Moolenaar        'SRCTOPS': [],
7197750ad47SMarcel Moolenaar        'OBJROOTS': [],
720ccfb9654SSimon J. Gerraty        'EXCLUDES': [],
7217750ad47SMarcel Moolenaar        }
7227750ad47SMarcel Moolenaar
723*c8245cebSSimon J. Gerraty    conf['SB'] = os.getenv('SB', '')
724*c8245cebSSimon J. Gerraty
7257750ad47SMarcel Moolenaar    try:
7267750ad47SMarcel Moolenaar        machine = os.environ['MACHINE']
7277750ad47SMarcel Moolenaar        if machine:
7287750ad47SMarcel Moolenaar            conf['MACHINE'] = machine
729bf062775SSimon J. Gerraty        machine_arch = os.environ['MACHINE_ARCH']
730bf062775SSimon J. Gerraty        if machine_arch:
731bf062775SSimon J. Gerraty            conf['MACHINE_ARCH'] = machine_arch
7327750ad47SMarcel Moolenaar        srctop = os.environ['SB_SRC']
7337750ad47SMarcel Moolenaar        if srctop:
7347750ad47SMarcel Moolenaar            conf['SRCTOPS'].append(srctop)
7357750ad47SMarcel Moolenaar        objroot = os.environ['SB_OBJROOT']
7367750ad47SMarcel Moolenaar        if objroot:
7377750ad47SMarcel Moolenaar            conf['OBJROOTS'].append(objroot)
7387750ad47SMarcel Moolenaar    except:
7397750ad47SMarcel Moolenaar        pass
7407750ad47SMarcel Moolenaar
7417750ad47SMarcel Moolenaar    debug = 0
7427750ad47SMarcel Moolenaar    output = True
7437750ad47SMarcel Moolenaar
744ccfb9654SSimon J. Gerraty    opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:X:' + xopts)
7457750ad47SMarcel Moolenaar    for o, a in opts:
746bf062775SSimon J. Gerraty        if o == '-a':
747bf062775SSimon J. Gerraty            conf['MACHINE_ARCH'] = a
748bf062775SSimon J. Gerraty        elif o == '-d':
7497750ad47SMarcel Moolenaar            debug += 1
7507750ad47SMarcel Moolenaar        elif o == '-q':
7517750ad47SMarcel Moolenaar            output = False
7527750ad47SMarcel Moolenaar        elif o == '-H':
7537750ad47SMarcel Moolenaar            conf['HOST_TARGET'] = a
7547750ad47SMarcel Moolenaar        elif o == '-S':
7557750ad47SMarcel Moolenaar            if a not in conf['SRCTOPS']:
7567750ad47SMarcel Moolenaar                conf['SRCTOPS'].append(a)
7577750ad47SMarcel Moolenaar        elif o == '-C':
7587750ad47SMarcel Moolenaar            conf['CURDIR'] = a
7597750ad47SMarcel Moolenaar        elif o == '-O':
7607750ad47SMarcel Moolenaar            if a not in conf['OBJROOTS']:
7617750ad47SMarcel Moolenaar                conf['OBJROOTS'].append(a)
7627750ad47SMarcel Moolenaar        elif o == '-R':
7637750ad47SMarcel Moolenaar            conf['RELDIR'] = a
7647750ad47SMarcel Moolenaar        elif o == '-D':
7657750ad47SMarcel Moolenaar            conf['DPDEPS'] = a
7667750ad47SMarcel Moolenaar        elif o == '-m':
7677750ad47SMarcel Moolenaar            conf['MACHINE'] = a
768bf062775SSimon J. Gerraty        elif o == '-T':
769bf062775SSimon J. Gerraty            conf['TARGET_SPEC'] = a
770ccfb9654SSimon J. Gerraty        elif o == '-X':
771ccfb9654SSimon J. Gerraty            if a not in conf['EXCLUDES']:
772ccfb9654SSimon J. Gerraty                conf['EXCLUDES'].append(a)
7737750ad47SMarcel Moolenaar        elif xoptf:
7747750ad47SMarcel Moolenaar            xoptf(o, a, conf)
7757750ad47SMarcel Moolenaar
7767750ad47SMarcel Moolenaar    conf['debug'] = debug
7777750ad47SMarcel Moolenaar
7787750ad47SMarcel Moolenaar    # get any var=val assignments
7797750ad47SMarcel Moolenaar    eaten = []
7807750ad47SMarcel Moolenaar    for a in args:
7817750ad47SMarcel Moolenaar        if a.find('=') > 0:
7827750ad47SMarcel Moolenaar            k,v = a.split('=')
7837750ad47SMarcel Moolenaar            if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']:
7847750ad47SMarcel Moolenaar                if k == 'SRCTOP':
7857750ad47SMarcel Moolenaar                    k = 'SRCTOPS'
7867750ad47SMarcel Moolenaar                elif k == 'OBJROOT':
7877750ad47SMarcel Moolenaar                    k = 'OBJROOTS'
7887750ad47SMarcel Moolenaar                if v not in conf[k]:
7897750ad47SMarcel Moolenaar                    conf[k].append(v)
7907750ad47SMarcel Moolenaar            else:
7917750ad47SMarcel Moolenaar                conf[k] = v
7927750ad47SMarcel Moolenaar            eaten.append(a)
7937750ad47SMarcel Moolenaar            continue
7947750ad47SMarcel Moolenaar        break
7957750ad47SMarcel Moolenaar
7967750ad47SMarcel Moolenaar    for a in eaten:
7977750ad47SMarcel Moolenaar        args.remove(a)
7987750ad47SMarcel Moolenaar
7993b26e5a4SSimon J. Gerraty    debug_out = conf.get('debug_out', sys.stderr)
8007750ad47SMarcel Moolenaar
8017750ad47SMarcel Moolenaar    if debug:
80210ea6facSSimon J. Gerraty        print("config:", file=debug_out)
80310ea6facSSimon J. Gerraty        print("psyco=", have_psyco, file=debug_out)
80410ea6facSSimon J. Gerraty        for k,v in list(conf.items()):
80510ea6facSSimon J. Gerraty            print("%s=%s" % (k,v), file=debug_out)
8067750ad47SMarcel Moolenaar
807ccfb9654SSimon J. Gerraty    m = None
8087750ad47SMarcel Moolenaar    for a in args:
809d5ddb276SSimon J. Gerraty        if a.endswith('.meta'):
810ccfb9654SSimon J. Gerraty            if not os.path.exists(a):
811ccfb9654SSimon J. Gerraty                continue
8127750ad47SMarcel Moolenaar            m = klass(a, conf)
813d5ddb276SSimon J. Gerraty        elif a.startswith('@'):
814d5ddb276SSimon J. Gerraty            # there can actually multiple files per line
815d5ddb276SSimon J. Gerraty            for line in open(a[1:]):
816d5ddb276SSimon J. Gerraty                for f in line.strip().split():
817ccfb9654SSimon J. Gerraty                    if not os.path.exists(f):
818ccfb9654SSimon J. Gerraty                        continue
819d5ddb276SSimon J. Gerraty                    m = klass(f, conf)
8207750ad47SMarcel Moolenaar
821ccfb9654SSimon J. Gerraty    if output and m:
82210ea6facSSimon J. Gerraty        print(m.dirdeps())
8237750ad47SMarcel Moolenaar
82410ea6facSSimon J. Gerraty        print(m.src_dirdeps('\nsrc:'))
8257750ad47SMarcel Moolenaar
8263b26e5a4SSimon J. Gerraty        dpdeps = conf.get('DPDEPS')
8277750ad47SMarcel Moolenaar        if dpdeps:
8283b26e5a4SSimon J. Gerraty            m.file_depends(open(dpdeps, 'w'))
8297750ad47SMarcel Moolenaar
8307750ad47SMarcel Moolenaar    return m
8317750ad47SMarcel Moolenaar
8327750ad47SMarcel Moolenaarif __name__ == '__main__':
8337750ad47SMarcel Moolenaar    try:
8347750ad47SMarcel Moolenaar        main(sys.argv)
8357750ad47SMarcel Moolenaar    except:
8367750ad47SMarcel Moolenaar        # yes, this goes to stdout
83710ea6facSSimon J. Gerraty        print("ERROR: ", sys.exc_info()[1])
8387750ad47SMarcel Moolenaar        raise
8397750ad47SMarcel Moolenaar
840