# Part of the A-A-P recipe executive: Dependency rules
# Copyright (C) 2002 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
# matchstr - for a rule: the string that matched %
#
# Illustration:
# targetlist : {build_attr} sourcelist
# commands
import os
import os.path
import string
from Error import *
import Filetype
from Util import *
from Message import *
class Depend:
def __init__(self, targetlist, build_attr, sourcelist,
work, rpstack, commands, builddir = 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.matchstr = ''
# 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 depend_auto(work, node):
"""Find the implied dependencies for "node". They are returned in
node.auto_depend.
If "node" changed since last time, regenerate the dependencies."""
# Return quickly when the automatic dependencies were already generated.
if not node.auto_depend is None:
return
# Don't generate automatic dependencies when "autodepend" is "off".
if ((work.globals.has_key("autodepend")
and work.globals["autodepend"] == "off")
or (node.attributes.has_key("autodepend")
and node.attributes["autodepend"] == "off")):
return
# Get the file type.
node_name = node.get_name()
if node.attributes.has_key("filetype"):
ftype = node.attributes["filetype"]
else:
ftype = Filetype.ft_detect(node_name)
if not ftype:
msg_depend(_('Unknown type of file, no dependency check for "%s"')
% node.short_name())
return
# Make the name for the recipe that contains the automatic dependencies for
# this node: "node_directory/aap/node_basename.aap"
recipe_name = os.path.join(os.path.dirname(node_name),
os.path.join("aap", os.path.basename(node_name))) + ".aap"
recipe = work.get_node(recipe_name, 1)
# Trigger the rule to produce a dependency recipe for this node.
from DoBuild import build_autodepend
if not build_autodepend(work, recipe, ftype, node):
return
if not os.path.exists(recipe.name):
msg_warning(_('Dependency file was not created: "%s"') % recipe.name)
return
# Read the generated recipe file.
node.auto_depend = read_auto_depend(recipe, node_name)
def read_auto_depend(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, "r")
except:
raise UserError, _('Cannot open "%s" for reading.') % recipe.name
from RecPos import RecPos
from ParsePos import ParsePos
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:
raise UserError, _('Nothing to read from "%s".') % recipe.name
i = string.find(fp.line, ":")
if i < 0:
raise UserError, _('No colon found in "%s".') % recipe.name
auto_depend = None
if i + 1 < fp.line_len:
from Dictlist import string2dictlist
auto_depend = string2dictlist(rpstack, fp.line[i + 1:])
# Remove the node itself.
for k in auto_depend:
if k["name"] == skipname:
auto_depend.remove(k)
# Check for trailing text.
fp.nextline()
if not fp.line is None:
msg_warning(_('Found trailing text in "%s"') % recipe.name)
file.close()
return auto_depend
# vim: set sw=4 sts=4 tw=79 fo+=l: