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:
|