File: Depend.py

package info (click to toggle)
aap 1.072-1.1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k, lenny
  • size: 4,976 kB
  • ctags: 2,160
  • sloc: python: 15,113; makefile: 62; sh: 13
file content (239 lines) | stat: -rw-r--r-- 8,527 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# Part of the A-A-P recipe executive: Dependency rules

# Copyright (C) 2002-2003 Stichting NLnet Labs
# Permission to copy and use this file is specified in the file COPYING.
# If this file is missing you can find it here: http://www.a-a-p.org/COPYING


# A Depend object contains:
#  targetlist   - dictlist of targets
#  build_attr   - dictlist of build attributes (right after the ":")
#  sourcelist   - dictlist of sources
#  rpstack      - RecPos stack for where the commands were defined
#  commands     - string of command lines
#  builddir     - directory where "commands" are to be executed
#  buildrecdict - the recdict of the recipe where it was defined or None
#  use_recdict  - recdict to be used when executing build commands
#  matchstr     - for a rule: the string that matched %
#  startup      - non-zero for a dependency defined in a startup recipe
#
# Illustration:
#       targetlist : {build_attr} sourcelist
#               commands

import os
import os.path
import string

from Error import *
from Util import *
from Message import *

class Depend:
    def __init__(self, targetlist, build_attr, sourcelist,
                     work, rpstack, commands, builddir = None, recdict = None):
        self.targetlist = targetlist
        self.build_attr = build_attr
        self.sourcelist = sourcelist
        self.rpstack = rpstack

        self.commands = commands
        if builddir is None:
            self.builddir = os.getcwd()
        else:
            self.builddir = builddir
        self.buildrecdict = recdict
        self.keep_current_scope = 0     # Current scope overrules scope of
                                        # build commands; used for rules and
                                        # actions.
        self.use_recdict = None
        self.matchstr = ''
        self.startup = 0
        self.in_use = 0

        # Add nodes for all sources and targets, with a pointer back to the
        # node.  Also carries over the attributes to the node.
        work.dictlist_nodes(self.targetlist)
        work.dictlist_nodes(self.sourcelist)

    def __str__(self):
        from Dictlist import dictlist2str, dictlistattr2str

        return (dictlist2str(self.targetlist)
                    + " : "
                    + dictlistattr2str(self.build_attr)
                    + dictlist2str(self.sourcelist)
                    + "\n" + self.commands)

    def get_scope_names(self, work):
        """
        Get the list of scope names to be used for build commands.  First the
        one specified as build attribute.  A scope specified for a source
        is appended.
        """
        # Attribute on dependency itself.
        xscope = self.build_attr.get("scope")
        if xscope:
            ret = [ xscope ]
        else:
            ret = []

        for s in self.sourcelist:
            if s.get("scope"):
                # Attribute on source mentioned for dependency.
                ret.append(s["scope"])
            else:
                node = work.find_node(s["name"])
                if node and node.attributes.get("scope"):
                    # Attribute on source node.
                    ret.append(node.attributes["scope"])
        return ret


def depend_auto(work, recdict, node, node_dict, level):
    """
    Find the implied dependencies for "node".
    "node_dict" contains attributes specified for the node specifically for the
    current dependency.  They overrule attributes from the node itself.
    The dependencies are returned in node.autodep_dictlist.
    If "node" changed since last time, regenerate the dependencies.
    """
    # Previously we returned quickly when the automatic dependencies were
    # already generated, because we cannot be sure they are still up-to-date.
    # Changed attributes might matter.

    # Don't generate automatic dependencies when "AUTODEPEND" is "off".
    if (recdict["_no"].get("AUTODEPEND") == "off"
            or (node.attributes.get("autodepend") == "off"
                or node_dict.get("autodepend") == "off")):
        node.autodep_dictlist = []
        return

    # Get the file type.
    ftype = node_dict.get("filetype")
    if not ftype:
        ftype = node.get_ftype(recdict)
    if not ftype:
        msg_depend(recdict,
                        _('Unknown type of file, no dependency check for "%s"')
                                                    % node.short_name(), level)
        node.autodep_dictlist = []
        return

    # A compressed or ".in" file is not checked.
    if ftype == "ignore":
        node.autodep_dictlist = []
        return

    # Trigger the rule to produce a dependency recipe for this node.
    # This will also update node.autodep_dictlist when node.autodep_recursive
    # is set.
    from DoBuild import build_autodepend
    recipe = build_autodepend(work, recdict, ftype, node, node_dict, level)

    # return silently when no dependencies could be generated
    if not recipe:
        node.autodep_dictlist = []
        return

    if not os.path.exists(recipe.name):
        msg_warning(recdict,
                      _('Dependency file was not created: "%s"') % recipe.name)
        node.autodep_dictlist = []
        return

    # Read the generated recipe file when not done already.
    if not node.autodep_recursive:
        node.autodep_dictlist = read_auto_depend(recdict, recipe,
                                                               node.get_name())


def read_auto_depend(recdict, recipe, skipname):
    """
    Read a generated recipe file from node "recipe".
    We only want the part after the ":", the item before it may be wrong
    (gcc generates foo.o: foo.c foo.h).
    Ignore "skipname".
    Don't read the recipe as a normal recipe, that would cause trouble with
    things we don't want to find in there. 
    """
    try:
        file = open(recipe.name)
    except:
        msg_error(recdict, _('Cannot open "%s" for reading.') % recipe.name)
        return []

    from ParsePos import ParsePos
    from RecPos import RecPos
    rpstack = [ RecPos(recipe.name) ]

    # create an object to contain the file position
    fp = ParsePos(rpstack, file = file)
    fp.nextline()           # read the first (and only) line
    if fp.line is None:
        msg_depend(recdict, _('Nothing to read from "%s".') % recipe.name)
        return []
    i = string.find(fp.line, ":")
    if os.name != "posix" and i == 1:       # DOS filename: "C:\dir\foo.c"
        i = string.find(fp.line, ":", 2)
    if i < 0:
        msg_error(recdict, _('No colon found in "%s".') % recipe.name)
        return []

    autodep_dictlist = []
    if i + 1 < fp.line_len:
        # Need to convert names with backslash-space to quoted name.
        nl = ''
        i = i + 1
        item = ''
        had_bsl = 0
        had_q = 0
        line_len = len(fp.line)
        while 1:
            if i >= line_len or is_white(fp.line[i]):
                if item:
                    # End of an item, append it to "nl" with or without quotes.
                    if nl:
                        nl = nl + ' '
                    if had_bsl == 1:
                        nl = nl + enquote(item)
                    else:
                        nl = nl + item
                if i >= line_len:
                    break
                had_bsl = 0
                had_q = 0
                item = ''
            elif (fp.line[i] == '\\' and i + 1 < line_len
                                   and is_white(fp.line[i + 1]) and not had_q):
                i = i + 1
                had_bsl = 1     # found a backslashed space or tab
                item = item + fp.line[i]
            elif fp.line[i] == '"' or fp.line[i] == "'":
                had_q = 1       # don't recognize backslash after a quote
                item = item + fp.line[i]
            else:
                item = item + fp.line[i]
            i = i + 1

        from Dictlist import str2dictlist
        autodep_dictlist = str2dictlist(rpstack, nl)

        # Make the path absolute (that's faster, SRCPATH won't be used).
        # Remove the node itself.
        for k in autodep_dictlist[:]:
            k["name"] = os.path.abspath(k["name"])
            if k["name"] == skipname:
                autodep_dictlist.remove(k)

    # Check for trailing text.
    fp.nextline()
    if not fp.line is None:
        msg_note(recdict, _('Found trailing text in "%s"') % recipe.name)

    file.close()
    return autodep_dictlist



# vim: set sw=4 et sts=4 tw=79 fo+=l: