Back to index

enigmail  1.4.3
Public Member Functions | Public Attributes | Static Public Attributes | Private Attributes
pymake.data.Target Class Reference

List of all members.

Public Member Functions

def __init__
def addrule
def isdoublecolon
def isphony
def hasdependency
def resolveimplicitrule
def ruleswithcommands
def resolvedeps
def resolvevpath
def beingremade
def notifydone
def make

Public Attributes

 target
 vpathtarget
 rules
 variables
 explicit
 mtime
 realmtime
 error
 didanything

Static Public Attributes

 wasremade = False

Private Attributes

 _state
 _callbacks

Detailed Description

An actual (non-pattern) target.

It holds target-specific variables and a list of rules. It may also point to a parent
PatternTarget, if this target is being created by an implicit rule.

The rules associated with this target may be Rule instances or, in the case of static pattern
rules, PatternRule instances.

Definition at line 749 of file data.py.


Constructor & Destructor Documentation

def pymake.data.Target.__init__ (   self,
  target,
  makefile 
)

Definition at line 762 of file data.py.

00762 
00763     def __init__(self, target, makefile):
00764         assert isinstance(target, str)
00765         self.target = target
00766         self.vpathtarget = None
00767         self.rules = []
00768         self.variables = Variables(makefile.variables)
00769         self.explicit = False
00770         self._state = MAKESTATE_NONE


Member Function Documentation

def pymake.data.Target.addrule (   self,
  rule 
)

Definition at line 771 of file data.py.

00771 
00772     def addrule(self, rule):
00773         assert isinstance(rule, (Rule, PatternRuleInstance))
00774         if len(self.rules) and rule.doublecolon != self.rules[0].doublecolon:
00775             raise DataError("Cannot have single- and double-colon rules for the same target. Prior rule location: %s" % self.rules[0].loc, rule.loc)
00776 
00777         if isinstance(rule, PatternRuleInstance):
00778             if len(rule.prule.targetpatterns) != 1:
00779                 raise DataError("Static pattern rules must only have one target pattern", rule.prule.loc)
00780             if rule.prule.targetpatterns[0].match(self.target) is None:
00781                 raise DataError("Static pattern rule doesn't match target '%s'" % self.target, rule.loc)
00782 
00783         self.rules.append(rule)

When we remake ourself, we need to reset our mtime and vpathtarget.

We store our old mtime so that $? can calculate out-of-date prerequisites.

Definition at line 994 of file data.py.

00994 
00995     def beingremade(self):
00996         """
00997         When we remake ourself, we need to reset our mtime and vpathtarget.
00998 
00999         We store our old mtime so that $? can calculate out-of-date prerequisites.
01000         """
01001         self.realmtime = self.mtime
01002         self.mtime = None
01003         self.vpathtarget = self.target
01004         self.wasremade = True

def pymake.data.Target.hasdependency (   self,
  t 
)

Definition at line 791 of file data.py.

00791 
00792     def hasdependency(self, t):
00793         for rule in self.rules:
00794             if t in rule.prerequisites:
00795                 return True
00796 
00797         return False

Here is the caller graph for this function:

Definition at line 784 of file data.py.

00784 
00785     def isdoublecolon(self):
00786         return self.rules[0].doublecolon

Here is the caller graph for this function:

def pymake.data.Target.isphony (   self,
  makefile 
)
Is this a phony target? We don't check for existence of phony targets.

Definition at line 787 of file data.py.

00787 
00788     def isphony(self, makefile):
00789         """Is this a phony target? We don't check for existence of phony targets."""
00790         return makefile.gettarget('.PHONY').hasdependency(self.target)

Here is the call graph for this function:

Here is the caller graph for this function:

def pymake.data.Target.make (   self,
  makefile,
  targetstack,
  cb,
  avoidremakeloop = False,
  printerror = True 
)
If we are out of date, asynchronously make ourself. This is a multi-stage process, mostly handled
by the helper objects RemakeTargetSerially, RemakeTargetParallel,
RemakeRuleContext. These helper objects should keep us from developing
any cyclical dependencies.

* resolve dependencies (synchronous)
* gather a list of rules to execute and related dependencies (synchronous)
* for each rule (in parallel)
** remake dependencies (asynchronous)
** build list of commands to execute (synchronous)
** execute each command (asynchronous)
* asynchronously notify when all rules are complete

@param cb A callback function to notify when remaking is finished. It is called
       thusly: callback(error=True/False, didanything=True/False)
       If there is no asynchronous activity to perform, the callback may be called directly.

Definition at line 1013 of file data.py.

01013 
01014     def make(self, makefile, targetstack, cb, avoidremakeloop=False, printerror=True):
01015         """
01016         If we are out of date, asynchronously make ourself. This is a multi-stage process, mostly handled
01017         by the helper objects RemakeTargetSerially, RemakeTargetParallel,
01018         RemakeRuleContext. These helper objects should keep us from developing
01019         any cyclical dependencies.
01020 
01021         * resolve dependencies (synchronous)
01022         * gather a list of rules to execute and related dependencies (synchronous)
01023         * for each rule (in parallel)
01024         ** remake dependencies (asynchronous)
01025         ** build list of commands to execute (synchronous)
01026         ** execute each command (asynchronous)
01027         * asynchronously notify when all rules are complete
01028 
01029         @param cb A callback function to notify when remaking is finished. It is called
01030                thusly: callback(error=True/False, didanything=True/False)
01031                If there is no asynchronous activity to perform, the callback may be called directly.
01032         """
01033 
01034         serial = makefile.context.jcount == 1
01035         
01036         if self._state == MAKESTATE_FINISHED:
01037             cb(error=self.error, didanything=self.didanything)
01038             return
01039             
01040         if self._state == MAKESTATE_WORKING:
01041             assert not serial
01042             self._callbacks.append(cb)
01043             return
01044 
01045         assert self._state == MAKESTATE_NONE
01046 
01047         self._state = MAKESTATE_WORKING
01048         self._callbacks = [cb]
01049         self.error = False
01050         self.didanything = False
01051 
01052         indent = getindent(targetstack)
01053 
01054         try:
01055             self.resolvedeps(makefile, targetstack, [], False)
01056         except util.MakeError, e:
01057             if printerror:
01058                 print e
01059             self.error = True
01060             self.notifydone(makefile)
01061             return
01062 
01063         assert self.vpathtarget is not None, "Target was never resolved!"
01064         if not len(self.rules):
01065             self.notifydone(makefile)
01066             return
01067 
01068         if self.isdoublecolon():
01069             rulelist = [RemakeRuleContext(self, makefile, r, [(makefile.gettarget(p), False) for p in r.prerequisites], targetstack, avoidremakeloop) for r in self.rules]
01070         else:
01071             alldeps = []
01072 
01073             commandrule = None
01074             for r in self.rules:
01075                 rdeps = [(makefile.gettarget(p), r.weakdeps) for p in r.prerequisites]
01076                 if len(r.commands):
01077                     assert commandrule is None
01078                     commandrule = r
01079                     # The dependencies of the command rule are resolved before other dependencies,
01080                     # no matter the ordering of the other no-command rules
01081                     alldeps[0:0] = rdeps
01082                 else:
01083                     alldeps.extend(rdeps)
01084 
01085             rulelist = [RemakeRuleContext(self, makefile, commandrule, alldeps, targetstack, avoidremakeloop)]
01086 
01087         targetstack = targetstack + [self.target]
01088 
01089         if serial:
01090             RemakeTargetSerially(self, makefile, indent, rulelist)
01091         else:
01092             RemakeTargetParallel(self, makefile, indent, rulelist)

def pymake.data.Target.notifydone (   self,
  makefile 
)

Definition at line 1005 of file data.py.

01005 
01006     def notifydone(self, makefile):
01007         assert self._state == MAKESTATE_WORKING, "State was %s" % self._state
01008 
01009         self._state = MAKESTATE_FINISHED
01010         for cb in self._callbacks:
01011             makefile.context.defer(cb, error=self.error, didanything=self.didanything)
01012         del self._callbacks 

def pymake.data.Target.resolvedeps (   self,
  makefile,
  targetstack,
  rulestack,
  recursive 
)
Resolve the actual path of this target, using vpath if necessary.

Recursively resolve dependencies of this target. This means finding implicit
rules which match the target, if appropriate.

Figure out whether this target needs to be rebuild, and set self.outofdate
appropriately.

@param targetstack is the current stack of dependencies being resolved. If
       this target is already in targetstack, bail to prevent infinite
       recursion.
@param rulestack is the current stack of implicit rules being used to resolve
       dependencies. A rule chain cannot use the same implicit rule twice.

Definition at line 876 of file data.py.

00876 
00877     def resolvedeps(self, makefile, targetstack, rulestack, recursive):
00878         """
00879         Resolve the actual path of this target, using vpath if necessary.
00880 
00881         Recursively resolve dependencies of this target. This means finding implicit
00882         rules which match the target, if appropriate.
00883 
00884         Figure out whether this target needs to be rebuild, and set self.outofdate
00885         appropriately.
00886 
00887         @param targetstack is the current stack of dependencies being resolved. If
00888                this target is already in targetstack, bail to prevent infinite
00889                recursion.
00890         @param rulestack is the current stack of implicit rules being used to resolve
00891                dependencies. A rule chain cannot use the same implicit rule twice.
00892         """
00893         assert makefile.parsingfinished
00894 
00895         if self.target in targetstack:
00896             raise ResolutionError("Recursive dependency: %s -> %s" % (
00897                     " -> ".join(targetstack), self.target))
00898 
00899         targetstack = targetstack + [self.target]
00900         
00901         indent = getindent(targetstack)
00902 
00903         _log.info("%sConsidering target '%s'", indent, self.target)
00904 
00905         self.resolvevpath(makefile)
00906 
00907         # Sanity-check our rules. If we're single-colon, only one rule should have commands
00908         ruleswithcommands = self.ruleswithcommands()
00909         if len(self.rules) and not self.isdoublecolon():
00910             if ruleswithcommands > 1:
00911                 # In GNU make this is a warning, not an error. I'm going to be stricter.
00912                 # TODO: provide locations
00913                 raise DataError("Target '%s' has multiple rules with commands." % self.target)
00914 
00915         if ruleswithcommands == 0:
00916             self.resolveimplicitrule(makefile, targetstack, rulestack)
00917 
00918         # If a target is mentioned, but doesn't exist, has no commands and no
00919         # prerequisites, it is special and exists just to say that targets which
00920         # depend on it are always out of date. This is like .FORCE but more
00921         # compatible with other makes.
00922         # Otherwise, we don't know how to make it.
00923         if not len(self.rules) and self.mtime is None and not util.any((len(rule.prerequisites) > 0
00924                                                                         for rule in self.rules)):
00925             raise ResolutionError("No rule to make target '%s' needed by %r" % (self.target,
00926                                                                                 targetstack))
00927 
00928         if recursive:
00929             for r in self.rules:
00930                 newrulestack = rulestack + [r]
00931                 for d in r.prerequisites:
00932                     dt = makefile.gettarget(d)
00933                     if dt.explicit:
00934                         continue
00935 
00936                     dt.resolvedeps(makefile, targetstack, newrulestack, True)
00937 
00938         for v in makefile.getpatternvariablesfor(self.target):
00939             self.variables.merge(v)

Here is the call graph for this function:

def pymake.data.Target.resolveimplicitrule (   self,
  makefile,
  targetstack,
  rulestack 
)
Try to resolve an implicit rule to build this target.

Definition at line 798 of file data.py.

00798 
00799     def resolveimplicitrule(self, makefile, targetstack, rulestack):
00800         """
00801         Try to resolve an implicit rule to build this target.
00802         """
00803         # The steps in the GNU make manual Implicit-Rule-Search.html are very detailed. I hope they can be trusted.
00804 
00805         indent = getindent(targetstack)
00806 
00807         _log.info("%sSearching for implicit rule to make '%s'", indent, self.target)
00808 
00809         dir, s, file = util.strrpartition(self.target, '/')
00810         dir = dir + s
00811 
00812         candidates = [] # list of PatternRuleInstance
00813 
00814         hasmatch = util.any((r.hasspecificmatch(file) for r in makefile.implicitrules))
00815 
00816         for r in makefile.implicitrules:
00817             if r in rulestack:
00818                 _log.info("%s %s: Avoiding implicit rule recursion", indent, r.loc)
00819                 continue
00820 
00821             if not len(r.commands):
00822                 continue
00823 
00824             for ri in r.matchesfor(dir, file, hasmatch):
00825                 candidates.append(ri)
00826             
00827         newcandidates = []
00828 
00829         for r in candidates:
00830             depfailed = None
00831             for p in r.prerequisites:
00832                 t = makefile.gettarget(p)
00833                 t.resolvevpath(makefile)
00834                 if not t.explicit and t.mtime is None:
00835                     depfailed = p
00836                     break
00837 
00838             if depfailed is not None:
00839                 if r.doublecolon:
00840                     _log.info("%s Terminal rule at %s doesn't match: prerequisite '%s' not mentioned and doesn't exist.", indent, r.loc, depfailed)
00841                 else:
00842                     newcandidates.append(r)
00843                 continue
00844 
00845             _log.info("%sFound implicit rule at %s for target '%s'", indent, r.loc, self.target)
00846             self.rules.append(r)
00847             return
00848 
00849         # Try again, but this time with chaining and without terminal (double-colon) rules
00850 
00851         for r in newcandidates:
00852             newrulestack = rulestack + [r.prule]
00853 
00854             depfailed = None
00855             for p in r.prerequisites:
00856                 t = makefile.gettarget(p)
00857                 try:
00858                     t.resolvedeps(makefile, targetstack, newrulestack, True)
00859                 except ResolutionError:
00860                     depfailed = p
00861                     break
00862 
00863             if depfailed is not None:
00864                 _log.info("%s Rule at %s doesn't match: prerequisite '%s' could not be made.", indent, r.loc, depfailed)
00865                 continue
00866 
00867             _log.info("%sFound implicit rule at %s for target '%s'", indent, r.loc, self.target)
00868             self.rules.append(r)
00869             return
00870 
00871         _log.info("%sCouldn't find implicit rule to remake '%s'", indent, self.target)

Here is the call graph for this function:

Here is the caller graph for this function:

def pymake.data.Target.resolvevpath (   self,
  makefile 
)

Definition at line 940 of file data.py.

00940 
00941     def resolvevpath(self, makefile):
00942         if self.vpathtarget is not None:
00943             return
00944 
00945         if self.isphony(makefile):
00946             self.vpathtarget = self.target
00947             self.mtime = None
00948             return
00949 
00950         if self.target.startswith('-l'):
00951             stem = self.target[2:]
00952             f, s, e = makefile.variables.get('.LIBPATTERNS')
00953             if e is not None:
00954                 libpatterns = [Pattern(stripdotslash(s)) for s in e.resolvesplit(makefile, makefile.variables)]
00955                 if len(libpatterns):
00956                     searchdirs = ['']
00957                     searchdirs.extend(makefile.getvpath(self.target))
00958 
00959                     for lp in libpatterns:
00960                         if not lp.ispattern():
00961                             raise DataError('.LIBPATTERNS contains a non-pattern')
00962 
00963                         libname = lp.resolve('', stem)
00964 
00965                         for dir in searchdirs:
00966                             libpath = util.normaljoin(dir, libname).replace('\\', '/')
00967                             fspath = util.normaljoin(makefile.workdir, libpath)
00968                             mtime = getmtime(fspath)
00969                             if mtime is not None:
00970                                 self.vpathtarget = libpath
00971                                 self.mtime = mtime
00972                                 return
00973 
00974                     self.vpathtarget = self.target
00975                     self.mtime = None
00976                     return
00977 
00978         search = [self.target]
00979         if not os.path.isabs(self.target):
00980             search += [util.normaljoin(dir, self.target).replace('\\', '/')
00981                        for dir in makefile.getvpath(self.target)]
00982 
00983         for t in search:
00984             fspath = util.normaljoin(makefile.workdir, t).replace('\\', '/')
00985             mtime = getmtime(fspath)
00986 #            _log.info("Searching %s ... checking %s ... mtime %r" % (t, fspath, mtime))
00987             if mtime is not None:
00988                 self.vpathtarget = t
00989                 self.mtime = mtime
00990                 return
00991 
00992         self.vpathtarget = self.target
00993         self.mtime = None
        

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 872 of file data.py.

00872 
00873     def ruleswithcommands(self):
00874         "The number of rules with commands"
00875         return reduce(lambda i, rule: i + (len(rule.commands) > 0), self.rules, 0)

Here is the caller graph for this function:


Member Data Documentation

Definition at line 1047 of file data.py.

Definition at line 769 of file data.py.

Definition at line 1049 of file data.py.

Definition at line 1048 of file data.py.

Definition at line 768 of file data.py.

Definition at line 946 of file data.py.

Definition at line 1000 of file data.py.

Definition at line 766 of file data.py.

Definition at line 764 of file data.py.

Definition at line 767 of file data.py.

Definition at line 765 of file data.py.

Definition at line 760 of file data.py.


The documentation for this class was generated from the following file: