coriolis/cumulus/src/Alliance.py

1466 lines
47 KiB
Python
Raw Normal View History

# -*- Mode:Python; explicit-buffer-name: "Alliance.py<cumulus>" -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2014-2018, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
# | =============================================================== |
# | Python : "./plugins/Alliance.py" |
# +-----------------------------------------------------------------+
import os
import os.path
import sys
import time
import stat
import copy
import subprocess
import inspect
import helpers
Support for mixing real pads & symbolic core. Wrapper around s2r. * Change: In Hurricane::Error constructors disable the backtrace generation. (*very* slow). * Change: In Hurricane::Library::getHierarchicalname(), more compact naming. Remove the name of the root library. * New: In Hurricane::Net, new type "FUSED", for component with no net. More efficient than having one net for each. * Change: In CellViewer, BreakpointWidget, use Angry Birds icons. * Change: In CellWidget::State, use the hierarchical name (cached) as key to the state. This allow to load two cells with the same name but from different libraries in the widget history. * Change: In PyGraphics, export "isEnabled()" and "isHighDpi()" functions. * Change: In CRL/etc/symbolic/cmos/plugin.conf, and CRL/etc/common/plugin.conf use the physical dimensions converters. * Change: In CRL/etc/symbolic/cmos/technology.conf, make the GDS layer table coherent with the default Alliance cmos.rds. * New: CRL/python/helpers/io.py, put ErrorMessage new implementation here, along with a new ErrorWidget written in PyQt4. It seems finally that PyQt4 can be used alongside Coriolis Qt widgets. New ErrorMessage.catch() static function to manage all exceptions in except clauses. * Change: In CRL/python/helpers/, no longer use ErrorMessage.wrapPrint(), directly print it. Rewrite the utilities to display Python stack traces "textStacktrace()" and "showStacktrace()". * Change: In CRL::AllianceFramework, shorten the names of the libraries. * Change: In CRL::ApParser & CRL::ApDriver, more accurate translation between Alliance connectors (C record) and Hurricane::Pin objects. Pin are no longer made square but thin and oriented in the connecting direction. Use the new fused net for unnamed components. * New: In CRL::GdsParser, implementation of SREF parsing, i.e. instances. Due to the unordered nature of the GDS stream, instances creation are delayed until the whole stream has been parsed and only then are they created. For the sake of reading back Alliance s2r GDS, we assume that any TEXT following a boundary is the Net name the boundary (component) belongs to. Create abutment box for Cells, computed from the bounding box, so the Hurricane QuadTree could work properly. Make use of the fused net for unnamed components. * New: In Cumulus/plugins/chip, complete rewrite of the I/O pad management. Now we can mix real (foundry) pads and a symbolic core. To cleanly support the de-coupling between the real part and the symbolic one we introduce a new intermediary hierarchical level, the corona. We have now: Chip --> Pads + Corona --> Core. At chip level (and if we are using real pads) the layout is fully real (excepting the corona). The Corona contains everything that is symbolic. It has symbolic wires extending outward the abutment box to make contact with the real wires coming from the pads. In the pad ring we can use corners instances (or not), pad spacers or directly draw wires between connectors ring pads. Provide two flavors: placement only or full place & route. WARNING: If routing in a second step, *do not route* the *Chip* but the *Corona*. * Change: In Cumulus/plugins/clocktree, give the modified Cell an additional extension of "_cts" (Clock Tree Synthesis) instead of "_clocked", to follow the common convention. * New: In cumulus/plugins/S2R.py, encapsulate call to Alliance S2R and reload the translated Cell in the editor. * New: In cumulus/plugins/core2chip, provide an utility to automatically create a chip from a core. To work this plugins must have a basic understanding of the pad functionalities which may differs from foundry to foundry. So a base class CoreToChip is created, then for each supported pad foundry a derived class is added. Currently we support AMS c35b4 and Alliance symbolic cmos. * Bug: In Anabatic::Configuration, read the right configuration parameter "anabatic.topRoutinglayer" (Katana), and not the one for Katabatic... * Change: In Unicorn/cgt.py, process the plugins in alphabetical order to ensure a reproductible ordering of the menus...
2019-05-22 07:34:32 -05:00
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers import Dots
# Global display flags
ShowCommand = 0x00001000
ShowLog = 0x00002000
ShowDots = 0x00004000
ForceRun = 0x00008000
commandFlags = ShowCommand | ShowLog
class AddMode ( object ):
Append = 1
Prepend = 2
Replace = 3
class Gauge ( object ):
Horizontal = 1
Vertical = 2
PinOnly = 4
Default = 8
class SearchPath ( object ):
def __init__ ( self ):
self._pathes = []
return
def add ( self, path, mode ):
name = os.path.basename(path)
if mode == AddMode.Append:
self._pathes.append( (name,path) )
elif mode == AddMode.Prepend:
self._pathes.insert( 0, (name,path) )
elif mode == AddMode.Replace:
for ipath in range(len(self._pathes)):
if self._pathes[ipath][0] == name:
self._pathes[ipath] = (name, path)
return
self._pathes.append( (name,path) )
return
def toUnix ( self ):
if not len(self._pathes): return ''
s = ''
for ipath in range(len(self._pathes)):
if ipath > 0: s += ':'
s += self._pathes[ipath][1]
return s
def __str__ ( self ):
return self.toUnix()
class Environment ( object ):
DefaultEnv = 0x0001
CommandEnv = 0x0002
Append = 0x0004
BehavioralExt = 0x0001
StructuralExt = 0x0002
PhysicalExt = 0x0004
ScriptExt = 0x0008
CSourceExt = 0x0010
DirectiveExt = 0x0020
IocExt = 0x0040
PatExt = 0x0080
AllExt = 0x00ff
extTable = { BehavioralExt : [ 'vbe' ]
, StructuralExt : [ 'vst', 'al' ]
, PhysicalExt : [ 'ap' , 'cp' ]
, ScriptExt : [ 'sh' , 'py' ]
, CSourceExt : [ 'c' ]
, IocExt : [ 'ioc' ]
, DirectiveExt : [ 'lax', 'boom', 'dly' ]
, PatExt : [ 'pat' ]
}
@staticmethod
def symbolToFilename ( name, eflags ):
extensions = []
for iflag in range(0,len(Environment.extTable)):
if eflags & pow(2,iflag): extensions += Environment.extTable[ pow(2,iflag) ]
for extension in extensions:
if name.endswith('_'+extension):
l = len(extension)
return name[:-l-1], name[-l:]
return None, None
@staticmethod
def isExt ( ext, eflags ):
extensions = []
for iflag in range(0,len(Environment.extTable)):
if eflags & pow(2,iflag): extensions += Environment.extTable[ pow(2,iflag) ]
if ext in extensions: return True
return False
def __init__ ( self, flags ):
self.mbkEnv = {}
if flags & Environment.DefaultEnv:
self.mbkEnv[ 'ALLIANCE_TOP' ] = None
self.mbkEnv[ 'LD_LIBRARY_PATH' ] = None
self.mbkEnv[ 'MBK_TARGET_LIB' ] = None
self.mbkEnv[ 'MBK_WORK_LIB' ] = '.'
self.mbkEnv[ 'MBK_CATA_LIB' ] = SearchPath()
self.mbkEnv[ 'MBK_CATAL_NAME' ] = 'CATAL'
self.mbkEnv[ 'MBK_OUT_LO' ] = 'vst'
self.mbkEnv[ 'MBK_OUT_PH' ] = 'ap'
self.mbkEnv[ 'MBK_IN_LO' ] = 'vst'
self.mbkEnv[ 'MBK_IN_PH' ] = 'ap'
self.mbkEnv[ 'MBK_SEPAR' ] = '_'
self.mbkEnv[ 'MBK_VDD' ] = 'vdd'
self.mbkEnv[ 'MBK_VSS' ] = 'vss'
self.mbkEnv[ 'RDS_TECHNO_NAME' ] = None
self.mbkEnv[ 'GRAAL_TECHNO_NAME' ] = None
else:
self.mbkEnv[ 'ALLIANCE_TOP' ] = None
self.mbkEnv[ 'LD_LIBRARY_PATH' ] = None
self.mbkEnv[ 'MBK_TARGET_LIB' ] = None
self.mbkEnv[ 'MBK_WORK_LIB' ] = None
self.mbkEnv[ 'MBK_CATA_LIB' ] = SearchPath()
self.mbkEnv[ 'MBK_CATAL_NAME' ] = None
self.mbkEnv[ 'MBK_OUT_LO' ] = None
self.mbkEnv[ 'MBK_OUT_PH' ] = None
self.mbkEnv[ 'MBK_IN_LO' ] = None
self.mbkEnv[ 'MBK_IN_PH' ] = None
self.mbkEnv[ 'MBK_SEPAR' ] = None
self.mbkEnv[ 'MBK_VDD' ] = None
self.mbkEnv[ 'MBK_VSS' ] = None
self.mbkEnv[ 'RDS_TECHNO_NAME' ] = None
self.mbkEnv[ 'GRAAL_TECHNO_NAME' ] = None
return
def load ( self, allianceConfig, allianceFile ):
entryNo = 0
for entry in allianceConfig:
entryNo += 1
try:
if len(entry) != 2:
raise ErrorMessage(1,['Malformed entry in <allianceConfig>.'
,'Must have exactly two fields ("key", <value>).'
,str(entry)
])
key, value = entry
if key == 'ALLIANCE_TOP': self.mbkEnv[ key ] = value
if key == 'GRAAL_TECHNO_NAME': self.mbkEnv[ key ] = value
if key == 'RDS_TECHNO_NAME': self.mbkEnv[ key ] = value
if key == 'CATALOG': self.mbkEnv[ key ] = value
if key == 'SCALE_X': self.mbkEnv[ key ] = value
if key == 'IN_LO': self.mbkEnv[ key ] = value
if key == 'IN_PH': self.mbkEnv[ key ] = value
if key == 'OUT_PH': self.mbkEnv[ key ] = value
if key == 'OUT_LO': self.mbkEnv[ key ] = value
if key == 'POWER': self.mbkEnv[ key ] = value
if key == 'GROUND': self.mbkEnv[ key ] = value
if key == 'MBK_TARGET_LIB': self.mbkEnv[ key ] = value
if key == 'WORKING_LIBRARY': self.mbkEnv[ key ] = value
if key == 'SYSTEM_LIBRARY':
for libraryEntry in value:
if len(libraryEntry) != 2:
raise ErrorMessage(1,['Malformed system library entry in <allianceConfig>.'
,'Must have exactly two fields ("path", <mode>).'
,str(libraryEntry)
])
libPath, mode = libraryEntry
self.mbkEnv['MBK_CATA_LIB'].add( libPath, mode )
except Exception, e:
Support for mixing real pads & symbolic core. Wrapper around s2r. * Change: In Hurricane::Error constructors disable the backtrace generation. (*very* slow). * Change: In Hurricane::Library::getHierarchicalname(), more compact naming. Remove the name of the root library. * New: In Hurricane::Net, new type "FUSED", for component with no net. More efficient than having one net for each. * Change: In CellViewer, BreakpointWidget, use Angry Birds icons. * Change: In CellWidget::State, use the hierarchical name (cached) as key to the state. This allow to load two cells with the same name but from different libraries in the widget history. * Change: In PyGraphics, export "isEnabled()" and "isHighDpi()" functions. * Change: In CRL/etc/symbolic/cmos/plugin.conf, and CRL/etc/common/plugin.conf use the physical dimensions converters. * Change: In CRL/etc/symbolic/cmos/technology.conf, make the GDS layer table coherent with the default Alliance cmos.rds. * New: CRL/python/helpers/io.py, put ErrorMessage new implementation here, along with a new ErrorWidget written in PyQt4. It seems finally that PyQt4 can be used alongside Coriolis Qt widgets. New ErrorMessage.catch() static function to manage all exceptions in except clauses. * Change: In CRL/python/helpers/, no longer use ErrorMessage.wrapPrint(), directly print it. Rewrite the utilities to display Python stack traces "textStacktrace()" and "showStacktrace()". * Change: In CRL::AllianceFramework, shorten the names of the libraries. * Change: In CRL::ApParser & CRL::ApDriver, more accurate translation between Alliance connectors (C record) and Hurricane::Pin objects. Pin are no longer made square but thin and oriented in the connecting direction. Use the new fused net for unnamed components. * New: In CRL::GdsParser, implementation of SREF parsing, i.e. instances. Due to the unordered nature of the GDS stream, instances creation are delayed until the whole stream has been parsed and only then are they created. For the sake of reading back Alliance s2r GDS, we assume that any TEXT following a boundary is the Net name the boundary (component) belongs to. Create abutment box for Cells, computed from the bounding box, so the Hurricane QuadTree could work properly. Make use of the fused net for unnamed components. * New: In Cumulus/plugins/chip, complete rewrite of the I/O pad management. Now we can mix real (foundry) pads and a symbolic core. To cleanly support the de-coupling between the real part and the symbolic one we introduce a new intermediary hierarchical level, the corona. We have now: Chip --> Pads + Corona --> Core. At chip level (and if we are using real pads) the layout is fully real (excepting the corona). The Corona contains everything that is symbolic. It has symbolic wires extending outward the abutment box to make contact with the real wires coming from the pads. In the pad ring we can use corners instances (or not), pad spacers or directly draw wires between connectors ring pads. Provide two flavors: placement only or full place & route. WARNING: If routing in a second step, *do not route* the *Chip* but the *Corona*. * Change: In Cumulus/plugins/clocktree, give the modified Cell an additional extension of "_cts" (Clock Tree Synthesis) instead of "_clocked", to follow the common convention. * New: In cumulus/plugins/S2R.py, encapsulate call to Alliance S2R and reload the translated Cell in the editor. * New: In cumulus/plugins/core2chip, provide an utility to automatically create a chip from a core. To work this plugins must have a basic understanding of the pad functionalities which may differs from foundry to foundry. So a base class CoreToChip is created, then for each supported pad foundry a derived class is added. Currently we support AMS c35b4 and Alliance symbolic cmos. * Bug: In Anabatic::Configuration, read the right configuration parameter "anabatic.topRoutinglayer" (Katana), and not the one for Katabatic... * Change: In Unicorn/cgt.py, process the plugins in alphabetical order to ensure a reproductible ordering of the menus...
2019-05-22 07:34:32 -05:00
e = ErrorMessage( e )
e.addMessage( 'In %s:<Alliance> at index %d.' % (allianceFile,entryNo) )
print e
self.mbkEnv[ 'LD_LIBRARY_PATH' ] = self.mbkEnv[ 'ALLIANCE_TOP' ] + '/lib'
return
def clone ( self ):
return copy.deepcopy(self)
def toSystemEnv ( self ):
env = os.environ
for key in self.mbkEnv.keys():
if not self.mbkEnv[key]:
print WarningMessage( 'Environment variable <%s> is not set.' % key )
continue
env[ key ] = str(self.mbkEnv[ key ])
return env
class EnvironmentWrapper ( object ):
def __init__ ( self, env ):
self._env = env.clone()
return
def toSystemEnv ( self ): return self._env.toSystemEnv()
@property
def env ( self ): return self._env
@property
def TARGET_LIB ( self ): return self._env.mbkEnv[ 'MBK_TARGET_LIB' ]
@property
def WORK_LIB ( self ): return self._env.mbkEnv[ 'MBK_WORK_LIB']
@property
def CATA_LIB ( self ): return self._env.mbkEnv[ 'MBK_CATA_LIB']
@property
def CATAL_NAME ( self ): return self._env.mbkEnv[ 'MBK_CATAL_NAME' ]
@property
def OUT_LO ( self ): return self._env.mbkEnv[ 'MBK_OUT_LO' ]
@property
def OUT_PH ( self ): return self._env.mbkEnv[ 'MBK_OUT_PH' ]
@property
def IN_LO ( self ): return self._env.mbkEnv[ 'MBK_IN_LO' ]
@property
def IN_PH ( self ): return self._env.mbkEnv[ 'MBK_IN_PH' ]
@property
def SEPAR ( self ): return self._env.mbkEnv[ 'MBK_SEPAR' ]
@property
def VDD ( self ): return self._env.mbkEnv[ 'MBK_VDD' ]
@property
def VSS ( self ): return self._env.mbkEnv[ 'MBK_VSS' ]
@property
def RDS_TECHNO_NAME ( self ): return self._env.mbkEnv[ 'RDS_TECHNO_NAME' ]
@property
def GRAAL_TECHNO_NAME ( self ): return self._env.mbkEnv[ 'GRAAL_TECHNO_NAME' ]
@TARGET_LIB.setter
def TARGET_LIB ( self, value ): self._env.mbkEnv[ 'MBK_TARGET_LIB' ] = value
@WORK_LIB.setter
def WORK_LIB ( self, value ): self._env.mbkEnv[ 'MBK_WORK_LIB'] = value
@CATA_LIB.setter
def CATA_LIB ( self, value ): self._env.mbkEnv[ 'MBK_CATA_LIB'] = value
@CATAL_NAME.setter
def CATAL_NAME ( self, value ): self._env.mbkEnv[ 'MBK_CATAL_NAME' ] = value
@OUT_LO.setter
def OUT_LO ( self, value ): self._env.mbkEnv[ 'MBK_OUT_LO' ] = value
@OUT_PH.setter
def OUT_PH ( self, value ): self._env.mbkEnv[ 'MBK_OUT_PH' ] = value
@IN_LO.setter
def IN_LO ( self, value ): self._env.mbkEnv[ 'MBK_IN_LO' ] = value
@IN_PH.setter
def IN_PH ( self, value ): self._env.mbkEnv[ 'MBK_IN_PH' ] = value
@SEPAR.setter
def SEPAR ( self, value ): self._env.mbkEnv[ 'MBK_SEPAR' ] = value
@VDD.setter
def VDD ( self, value ): self._env.mbkEnv[ 'MBK_VDD' ] = value
@VSS.setter
def VSS ( self, value ): self._env.mbkEnv[ 'MBK_VSS' ] = value
@RDS_TECHNO_NAME.setter
def RDS_TECHNO_NAME ( self, value ): self._env.mbkEnv[ 'RDS_TECHNO_NAME' ] = value
@GRAAL_TECHNO_NAME.setter
def GRAAL_TECHNO_NAME ( self, value ): self._env.mbkEnv[ 'GRAAL_TECHNO_NAME' ] = value
class ReportLog ( object ):
def __init__ ( self, baseName ):
self._reportBase = baseName
self._reportFile = None
self._fd = None
self._lastLine = None
self._chooseName()
return
def _chooseName ( self ):
index = 0
timeTag = time.strftime("%Y.%m.%d")
while True:
self._reportFile = "./%s-%s-%02d.log" % (self._reportBase,timeTag,index)
if not os.path.isfile(self._reportFile):
print "Report log: <%s>" % self._reportFile
break
index += 1
return
@property
def baseName ( self ): return self._reportBase
@baseName.setter
def baseName ( self, baseName ): self._reportBase = baseName
def open ( self ):
if self._fd: return
self._fd = open( self._reportFile, "a+" )
return
def close ( self ):
if not self._fd: return
self._fd.close()
self._fd = None
return
def write ( self, line ):
if not self._fd: return
self._lastLine = line
self._fd.write( self._lastLine )
return
moduleGlobals = globals()
env = Environment( Environment.DefaultEnv )
def staticInitialization ():
global moduleGlobals
global env
confFile = helpers.sysConfDir+'/'+helpers.symbolicTechno+'/alliance.conf'
symbol = 'allianceConfig'
if not os.path.isfile(confFile):
print '[ERROR] Missing mandatory Coriolis2 system file:'
print ' <%s>' % confFile
sys.exit( 1 )
try:
print ' o Running configuration hook: Alliance.staticInitialization().'
print ' - Loading \"%s\".' % helpers.truncPath(confFile)
execfile( confFile, moduleGlobals )
except Exception, e:
print '[ERROR] An exception occured while loading the configuration file:'
print ' <%s>\n' % (confFile)
print ' You should check for simple python errors in this file.'
print ' Error was:'
print ' %s\n' % e
sys.exit( 1 )
if moduleGlobals.has_key(symbol):
env.load( moduleGlobals[symbol], confFile )
del moduleGlobals[symbol]
else:
print '[ERROR] Mandatory symbol <%s> is missing in system configuration file:' % symbol
print ' <%s>' % confFile
sys.exit( 1 )
print
return
helpers.staticInitialization()
staticInitialization()
report = ReportLog( 'alliance' )
class Node ( EnvironmentWrapper ):
Unreached = -1
__allNodes = []
@staticmethod
def getAllNodes (): return Node.__allNodes
@staticmethod
def lookup ( symbol ):
for node in Node.__allNodes:
if node.ruleName == symbol:
return node
return None
@staticmethod
def allClean ():
for node in Node.__allNodes: node.clean()
return
@staticmethod
def findSelfSymbols ():
for node in Node.__allNodes: node._findSelfSymbol()
return
def __init__ ( self ):
EnvironmentWrapper.__init__( self, env )
self._targetName = None
self._extension = None
self._dependencies = []
self._childs = []
self._depth = Node.Unreached
self._depsReacheds = 0
self._active = False
self._frame = inspect.stack()[self.frameDepth]
Node.__allNodes.append( self )
return
def _findSelfSymbol ( self ):
callerGlobals = self._frame[0].f_globals
for symbol in callerGlobals.keys():
if self == callerGlobals[symbol]:
self.setTarget( symbol )
return
self.setDefaultTargetName()
#raise ErrorMessage( 1, 'Node cannot find its symbol in parent frame.' )
return
def setTarget ( self, name ):
baseName, extension = Environment.symbolToFilename( name, Environment.AllExt )
if baseName:
self._targetName = baseName
self._extension = extension
else:
raise ErrorMessage( 1, 'Invalid file format of Node object <%s>' % name )
return
@property
def targetName ( self ): return self._targetName
def setDefaultTargetName ( self ):
if self._dependencies == []:
raise ErrorMessage( 1, 'Node.setDefaultTargetName(): node is neither used nor have dependencies.' )
self.setTarget( self.getDependency(0)._targetName+'_'+self.toolName.lower() )
print WarningMessage( 'Node.setDefaultTargetName(): Node is not affected, using: <%s>' % self.targetName )
return
def addDependency ( self, dependency ):
if not isinstance(dependency,Node):
raise ErrorMessage( 1, 'Node.addDependency(): Not a node %s.' % str(dependency) )
self._dependencies.append( dependency )
dependency.addChild( self )
return
def getDependency ( self, i ): return self._dependencies[i]
def getDependencies ( self ): return self._dependencies
def addChild ( self, child ):
if not child in self._childs: self._childs.append( child )
return
def getChilds ( self ): return self._childs
def getDepth ( self ): return self._depth
def resetOrder ( self ):
self._depth = Node.Unreached
self._depsReacheds = 0
return
def incDepsReached ( self, depth ):
if depth > self._depth: self._depth = depth
if self._depsReacheds < len(self._dependencies):
self._depsReacheds += 1
return self._depsReacheds >= len(self._dependencies)
def allDepsReached ( self ):
return self._depsReacheds >= len(self._dependencies)
def checkFile ( self, hardStop=False, errorMessage=[] ):
if not os.path.isfile(self.fileName):
error = ErrorMessage( 1, 'File <%s> of node <%s> has not been created.'
% (self.fileName,self._targetName) )
if errorMessage:
print
for line in errorMessage: print line
if hardStop:
raise error
else:
print error
return
def isUptodate ( self ):
depsMTime = 0
#print ' Target: %-30s %d' % (self.fileName, self.mtime)
for dependency in self.getDependencies():
dependency.checkFile()
depsMTime = max( depsMTime, dependency.mtime )
#print ' | Dep: %-31s %d' % (dependency.fileName, dependency.mtime)
return depsMTime <= self.mtime
def setActive ( self ):
self._active = True
for dependency in self.getDependencies():
dependency.setActive()
def isActive ( self ): return self._active
def setMbkEnv ( self ): return
def clean ( self ):
if not isinstance(self,Source) \
and not isinstance(self,Probe) \
and not isinstance(self,Rule):
print 'Clean | %-30s| rm %s' % ( "<%s>"%self.ruleName, self.fileName )
report.open()
report.write( 'Clean <%s>: (%s)\n' % (self.ruleName, self.fileName) )
if os.path.isfile(self.fileName):
report.write( ' rm %s\n' % self.fileName )
os.unlink( self.fileName )
return
report.close()
@property
def name ( self ): return self._targetName
@property
def extension ( self ): return self._extension
@property
def fileName ( self ): return self._targetName+'.'+self._extension
@property
def ruleName ( self ):
if self._extension:
return self._targetName+'_'+self._extension
return self._targetName
@property
def mtime ( self ):
if not os.path.isfile(self.fileName): return 0
return os.stat( self.fileName )[ stat.ST_MTIME ]
class Command ( Node ):
commandTypes = []
def __init__ ( self ):
Node.__init__( self )
self._flags = 0
Command.commandTypes.append( type(self) )
return
@staticmethod
def asString ( command ):
s = ''
for i in range( len(command) ):
if i: s += ' '
s += command[i]
return s
@staticmethod
def indent ( command, indent, width=109 ):
lines = []
lines.append( '|' )
for i in range(len(command)):
lines[-1] += ' ' + command[i]
if (len(lines) == 1 and len(lines[0]) >= width-indent) \
or len(lines[-1]) >= width:
if i < len(command)-1:
lines.append( ' '*indent + '|' + ' '*(len(command[0])+1) )
s = lines[0]
for line in lines[1:]:
s += '\n' + line
return s
#s = ''
#l = '|'
#for i in range(len(command)):
# l += ' ' + command[i]
# if len(l) >= width-indent:
# if len(s): s += '\n'
# s += l
# if i < len(command)-1:
# l = ' '*indent + '|' + ' '*(len(command[0])+1)
# else:
# return s
#if len(s): s += '\n'
#s += l
#return s
@property
def frameDepth ( self ): return 3
@property
def flags ( self ): return self._flags
@flags.setter
def flags ( self, flags ): self._flags = flags
def _run ( self, checkFile=True ):
global commandFlags
flags = commandFlags
if self._flags: flags = self._flags
command = self.asCommand()
ruleName = "<%s>" % self.ruleName
if self.isActive() and (not self.isUptodate() or flags & ForceRun):
if flags & ShowCommand:
print "Executing | %-30s%s" % (ruleName,Command.indent(command,42))
child = subprocess.Popen( command
, env=self.env.toSystemEnv()
, stdout=subprocess.PIPE
, stderr=subprocess.PIPE
)
dots = Dots( ' '*42+'| ', 109 )
report.open()
report.write( 'Executing command: %s \n' % ruleName )
report.write( ' %s\n' % Command.asString(command) )
while True:
line = child.stdout.readline()
if not line: break
if flags & ShowLog:
print "%s" % (line[:-1])
sys.stdout.flush()
elif flags & ShowDots:
dots.dot()
report.write( line )
errorLines = []
while True:
line = child.stderr.readline()
if not line: break
errorLines.append( line[:-1] )
sys.stderr.flush()
report.write( line )
report.close()
dots.reset()
(pid,status) = os.waitpid(child.pid, 0)
status >>= 8
if status != 0:
print
for line in errorLines: print line
raise ErrorMessage( 1, "%s returned status:%d." % (self.toolName,status) )
if checkFile:
self.checkFile( hardStop=True, errorMessage=errorLines )
else:
if self.isActive(): action = 'Up to date'
else: action = 'Inactive'
if flags & ShowCommand:
print "%-10s| %-30s%s" % (action,ruleName,Command.indent(command,42))
report.open()
report.write( '%s command:\n' % action )
report.write( ' %s\n' % Command.asString(command) )
report.close()
status = 0
return status
class StampCommand ( Command ):
def __init__ ( self ):
Command.__init__( self )
return
def setTarget ( self, name ):
if not name.startswith('stamp_'):
raise ErrorMessage( 1, 'Target of stamp commands must start with "stamp_" (<%s>)' % name )
self._targetName = 'stamp.' + name[6:]
return
@property
def frameDepth ( self ): return 4
@property
def fileName ( self ): return self._targetName
def _run ( self ):
Command._run( self, checkFile=False )
if self.isActive():
with file(self.fileName,'a'): os.utime(self.fileName,None)
return
class Probe ( Command ):
def __init__ ( self, script ):
Command.__init__( self )
self.addDependency( script )
return
@property
def toolName ( self ): return self.getDependency(0).name+'_'+self.getDependency(0).extension
def asCommand ( self ):
return [ os.path.join(os.getcwd(),self.getDependency(0).fileName) ]
def _run ( self ):
Command._run( self, checkFile=False )
return
class Source ( Node ):
def __init__ ( self ):
Node.__init__( self )
return
@property
def frameDepth ( self ): return 2
class Rule ( Node ):
def __init__ ( self, *dependencies ):
Node.__init__( self )
for dependency in dependencies:
self.addDependency( dependency )
return
@property
def frameDepth ( self ): return 2
@property
def mtime ( self ): return 0
def setTarget ( self, name ):
self._targetName = name
return
class Boom ( Command ):
Verbose = 0x00000001
Trace = 0x00000002
ReverseOrder = 0x00000004
LocalOptimization = 0x00000008
AlgorithmS = 's'
AlgorithmJ = 'j'
AlgorithmB = 'b'
AlgorithmG = 'g'
AlgorithmP = 'p'
AlgorithmW = 'w'
AlgorithmT = 't'
AlgorithmM = 'm'
AlgorithmO = 'o'
AlgorithmR = 'r'
AlgorithmN = 'n'
def __init__ ( self, behavioral ):
Command.__init__( self )
self._directives = None
self._level = 0
self._delayPercent = 0
self._iterations = None
self._bddReorder = None
self._algorithm = None
self.addDependency( behavioral )
return
@property
def toolName ( self ): return 'Boom'
@property
def fileName ( self ): return self.name+'.'+self.extension
@property
def directives ( self ): return self._directives
@directives.setter
def directives ( self, directives ):
self._directives = directives
self.addDependency( self._directives )
@property
def level ( self ): return self._level
@property
def delayPercent( self ): return self._delayPercent
@property
def iterations ( self ): return self._iterations
@property
def bddReorder ( self ): return self._bddReorder
@property
def algorithm ( self ): return self._algorithm
@level.setter
def level ( self, level ): self._level = level
@delayPercent.setter
def delayPercent( self, delayPercent ): self._delayPercent = delayPercent
@iterations.setter
def iterations ( self, iterations ): self._iterations = iterations
@bddReorder.setter
def bddReorder ( self, bddReorder ): self._bddReorder = bddReorder
@algorithm.setter
def algorithm ( self, algorithm ): self._algorithm = algorithm
def setMbkEnv ( self ):
if self.extension != 'vbe':
raise ErrorMessage( 1, 'Boom(): Optimized file format/ext must be <vbe>, not <%s>.'
% self.extension )
if self.getDependency(0).extension != 'vbe':
raise ErrorMessage( 1, 'Boom(): Behavioral source file format/ext must be <vbe>, not <%s>.'
% self.getDependency(0).extension )
if self._directives and self._directives.extension != 'boom':
raise ErrorMessage( 1, 'Boom(): Directive file format/ext must be <boom>, not <%s>.'
% self._directives.extension )
self.IN_LO = 'vst'
self.OUT_LO = 'vst'
return
def asCommand ( self ):
command = [ 'boom' ]
#command = [ './boom.sh' ]
if self._flags & Boom.Verbose: command += [ '-V' ]
if self._flags & Boom.Trace: command += [ '-T' ]
if self._flags & Boom.ReverseOrder: command += [ '-O' ]
if self._flags & Boom.LocalOptimization: command += [ '-A' ]
if self._directives: command += [ '-P', self.getDependency(1).name ]
if self._level: command += [ '-l', str(self._level) ]
if self._delayPercent: command += [ '-d', str(self._delayPercent) ]
if self._iterations: command += [ '-i', str(self._iterations) ]
if self._bddReorder: command += [ '-a', str(self._bddReorder) ]
if self._algorithm: command += [ '-'+self._algorithm ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Boog ( Command ):
def __init__ ( self, behavioral ):
Command.__init__( self )
self._optimMode = 5
self._xschMode = 2
self._delayPercent = 0
self._laxFile = None
self._debugFile = None
self.addDependency( behavioral )
return
@property
def toolName ( self ): return 'Boog'
@property
def fileName ( self ): return self.name+'.'+self.extension
@property
def laxFile ( self ): return self._laxNode
@laxFile.setter
def laxFile ( self, laxNode ):
self._laxNode = laxNode
self.addDependency( self._laxNode )
@property
def optimMode( self ): return self._optimMode
@property
def xschMode ( self ): return self._xschMode
@property
def debugFile( self ): return self._debugFile
@optimMode.setter
def optimMode( self, optimMode ): self._optimMode = optimMode
@xschMode.setter
def xschMode ( self, xschMode ): self._xschMode = xschMode
@debugFile.setter
def debugFile( self, debugFile ): self._debugFile = debugFile
def setMbkEnv ( self ):
if Environment.isExt(self.extension,Environment.StructuralExt):
self.OUT_LO = self.extension
else:
raise ErrorMessage( 1, 'Boog(): Invalid structural (netlist) file format/ext <%s>.'
% self.extension )
if self.getDependency(0).extension != 'vbe':
raise ErrorMessage( 1, 'Boog(): Behavioral source file format/ext must be <vbe>, not <%s>.'
% self.getDependency(0).extension )
if self._laxFile and self._laxFile.extension != 'lax':
raise ErrorMessage( 1, 'Boog(): Lax file format/ext must be <lax>, not <%s>.'
% self._directives.extension )
self.IN_LO = 'vst'
return
def asCommand ( self ):
command = [ 'boog' ]
if self._optimMode < 5: command += [ '-m', str(self._optimMode) ]
if self._xschMode < 2: command += [ '-x', str(self._xschMode) ]
if self._laxFile: command += [ '-l', self.getDependency(1).name ]
if self._debugFile: command += [ '-d', self._debugFile ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Loon ( Command ):
def __init__ ( self, structural ):
Command.__init__( self )
self._optimMode = 5
self._xschMode = 2
self._laxFile = None
self.addDependency( structural )
return
@property
def toolName ( self ): return 'Loon'
@property
def fileName ( self ): return self.name+'.'+self.OUT_LO
@property
def laxFile ( self ): return self._laxFile
@laxFile.setter
def laxFile ( self, laxFile ):
self._laxFile = laxFile
self.addDependency( self._laxFile )
@property
def optimMode( self ): return self._optimMode
@property
def xschMode ( self ): return self._xschMode
@optimMode.setter
def optimMode( self, optimMode ): self._optimMode = optimMode
@xschMode.setter
def xschMode ( self, xschMode ): self._xschMode = xschMode
def setMbkEnv ( self ):
if Environment.isExt(self.extension,Environment.StructuralExt):
self.OUT_LO = self.extension
else:
raise ErrorMessage( 1, 'Loon(): Invalid output structural (netlist) file format/ext <%s>.'
% self.extension )
if Environment.isExt(self.getDependency(0).extension,Environment.StructuralExt):
self.IN_LO = self.getDependency(0).extension
else:
raise ErrorMessage( 1, 'Loon(): Invalid input structural (netlist) file format/ext <%s>.'
% self.getDependency(0).extension )
if self._laxFile and self._laxFile.extension != 'lax':
raise ErrorMessage( 1, 'Loon(): Lax file format/ext must be <lax>, not <%s>.'
% self._directives.extension )
return
def asCommand ( self ):
command = [ 'loon' ]
if self._optimMode < 5: command += [ '-m', str(self._optimMode) ]
if self._xschMode < 2: command += [ '-x', str(self._xschMode) ]
if self._laxFile: command += [ '-l', self.getDependency(1).fileName ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Genlib ( Command ):
def __init__ ( self, csource ):
Command.__init__( self )
self.addDependency( csource )
return
@property
def toolName ( self ): return 'Genlib'
@property
def fileName ( self ): return self.name+'.'+self.OUT_LO
def setMbkEnv ( self ):
if not Environment.isExt(self.extension,Environment.StructuralExt|Environment.PhysicalExt):
raise ErrorMessage( 1, 'Genlib(): Invalid output netlist or layout file format/ext <%s>.'
% self.extension )
if not Environment.isExt(self.getDependency(0).extension,Environment.CSourceExt):
raise ErrorMessage( 1, 'Genlib(): Input file format/ext must be <c>, not <%s>.'
% self.getDependency(0).extension )
if Environment.isExt(self.extension,Environment.StructuralExt): self.OUT_LO = self.extension
if Environment.isExt(self.extension,Environment.PhysicalExt): self.OUT_PH = self.extension
return
def asCommand ( self ):
command = [ 'genlib', '-v', '-k' ]
command += [ self.getDependency(0).name ]
return command
class Genpat ( Command ):
def __init__ ( self, csource ):
Command.__init__( self )
self.addDependency( csource )
return
@property
def toolName ( self ): return 'Genpat'
@property
def fileName ( self ): return self.name+'.pat'
def setMbkEnv ( self ):
if self.extension != 'pat':
raise ErrorMessage( 1, 'Genpat(): Invalid output pattern file format/ext <%s>, must be <pat>.'
% self.extension )
if not Environment.isExt(self.getDependency(0).extension,Environment.CSourceExt):
raise ErrorMessage( 1, 'Genpat(): Input file format/ext must be <c>, not <%s>.'
% self.getDependency(0).extension )
return
def asCommand ( self ):
command = [ 'genpat', '-v' ]
command += [ self.getDependency(0).name ]
return command
class Asimut ( Command ):
RootIsBehavioral = 0x00000001
UseBdd = 0x00000002
CompileOnly = 0x00000004
ZeroDelay = 0x00000008
def __init__ ( self, model, patterns ):
Command.__init__( self )
self._backdelay = None
self.addDependency( patterns )
self.addDependency( model )
return
@property
def toolName ( self ): return 'Asimut'
@property
def fileName ( self ): return self.name+'.pat'
@property
def backdelay ( self ): return self._backdelay
@backdelay.setter
def backdelay ( self, backdelay ):
self._backdelay = backdelay
self.addDependency( self._backdelay )
def setMbkEnv ( self ):
if self.flags & Asimut.RootIsBehavioral:
if not Environment.isExt(self.getDependency(1).extension,Environment.BehavioralExt):
raise ErrorMessage( 1, 'Asimut(): Invalid input behavioral file format/ext <%s>, must be <vbe>.'
% self.getDependency(1).extension )
else:
if Environment.isExt(self.getDependency(1).extension,Environment.StructuralExt):
self.IN_LO = self.getDependency(1).extension
else:
raise ErrorMessage( 1, 'Asimut(): Invalid input structural (netlist) file format/ext <%s>.'
% self.getDependency(1).extension )
if self.extension != 'pat':
raise ErrorMessage( 1, 'Asimut(): Invalid output pattern file format/ext <%s>, must be <pat>.'
% self.extension )
if self.getDependency(0).extension != 'pat':
raise ErrorMessage( 1, 'Asimut(): Invalid input pattern file format/ext <%s>, must be <pat>.'
% self.getDependency(0).extension )
return
def asCommand ( self ):
command = [ 'asimut' ]
if self.flags & Asimut.RootIsBehavioral: command += [ '-b' ]
if self.flags & Asimut.UseBdd: command += [ '-bdd' ]
if self.flags & Asimut.CompileOnly: command += [ '-c' ]
if self.flags & Asimut.ZeroDelay: command += [ '-zd' ]
if self._backdelay: command += [ '-backdelay', self.getDependency(1).name ]
command += [ self.getDependency(1).name ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Ocp ( Command ):
Ring = 0x00000001
Gnuplot = 0x00000002
def __init__ ( self, netlist ):
Command.__init__( self )
self._partial = None
self._ioc = None
self._margin = -1
self.addDependency( netlist )
return
@property
def toolName ( self ): return 'Ocp'
@property
def fileName ( self ): return self.name+'.'+self._extension
@property
def partial ( self ): return self._partial
@partial.setter
def partial ( self, partial ):
self._partial = partial
self.addDependency( self._partial )
@property
def ioc ( self ): return self._ioc
@ioc.setter
def ioc ( self, ioc ):
self._ioc = ioc
self.addDependency( self._ioc )
@property
def margin ( self ): return self._margin
@margin.setter
def margin ( self, margin ):
if margin < 0 or margin > 100:
raise ErrorMessage( 1, 'Ocp: Margin must be between 0 and 100% (%d)' % margin )
self._margin = margin
def setMbkEnv ( self ):
if Environment.isExt(self.extension,Environment.PhysicalExt):
self.OUT_PH = self.extension
else:
raise ErrorMessage( 1, 'Ocp(): Invalid output layout file format/ext <%s>.'
% self.extension )
if Environment.isExt(self.getDependency(0).extension,Environment.StructuralExt):
self.IN_LO = self.getDependency(0).extension
else:
raise ErrorMessage( 1, 'Ocp(): Input file format/ext must be structural, not <%s>.'
% self.getDependency(0).extension )
if Environment.isExt(self._partial.extension,Environment.PhysicalExt):
self.IN_PH = self._partial.extension
else:
raise ErrorMessage( 1, 'Ocp(): Invalid input layout file format/ext <%s> for partial placement.'
% self._partial.extension )
if self._ioc.extension != 'ioc':
raise ErrorMessage( 1, 'Ocp(): Invalid IOC file format/ext <%s>, must be <ioc>.'
% self._ioc.extension )
return
def asCommand ( self ):
command = [ 'ocp', '-v' ]
if self.flags & Ocp.Ring: command += [ '-ring' ]
if self.flags & Ocp.Gnuplot: command += [ '-gnuplot' ]
if self._margin > 0: command += [ '-margin' , str(self._margin) ]
if self._partial: command += [ '-partial', self._partial.name ]
if self._ioc: command += [ '-ioc' , self._ioc.name ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Nero ( Command ):
ForceGlobalOff = 0x00000001
ForceGlobalOn = 0x00000002
Use2Layers = 0x00000004
Use3Layers = 0x00000008
Use4Layers = 0x00000010
Use5Layers = 0x00000020
Use6Layers = 0x00000040
def __init__ ( self, netlist ):
Command.__init__( self )
self._placement = None
self.addDependency( netlist )
return
@property
def toolName ( self ): return 'Nero'
@property
def fileName ( self ): return self.name+'.'+self._extension
@property
def placement ( self ): return self._placement
@placement.setter
def placement ( self, placement ):
self._placement = placement
self.addDependency( self._placement )
def setMbkEnv ( self ):
if Environment.isExt(self.extension,Environment.PhysicalExt):
self.OUT_PH = self.extension
else:
raise ErrorMessage( 1, 'Nero(): Invalid output layout file format/ext <%s>.'
% self.extension )
if Environment.isExt(self.getDependency(0).extension,Environment.StructuralExt):
self.IN_LO = self.getDependency(0).extension
else:
raise ErrorMessage( 1, 'Nero(): Input file format/ext must be structural, not <%s>.'
% self.getDependency(0).extension )
if Environment.isExt(self._placement.extension,Environment.PhysicalExt):
self.IN_PH = self._placement.extension
else:
raise ErrorMessage( 1, 'Nero(): Invalid input layout file format/ext <%s> for placement placement.'
% self._placement.extension )
return
def asCommand ( self ):
command = [ 'nero', '-V' ]
if self.flags & Nero.ForceGlobalOff: command += [ '-L' ]
if self.flags & Nero.ForceGlobalOn: command += [ '-G' ]
if self.flags & Nero.Use2Layers: command += [ '-2' ]
if self.flags & Nero.Use3Layers: command += [ '-3' ]
if self.flags & Nero.Use4Layers: command += [ '-4' ]
if self.flags & Nero.Use5Layers: command += [ '-5' ]
if self.flags & Nero.Use6Layers: command += [ '-6' ]
if self._placement: command += [ '-p', self._placement.name ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Cougar ( Command ):
TransistorFlatten = 0x00000001
CatalogFlatten = 0x00000002
CapaToGround = 0x00000004
RCToGround = 0x00000008
def __init__ ( self, layout ):
Command.__init__( self )
self.addDependency( layout )
return
@property
def toolName ( self ): return 'Cougar'
@property
def fileName ( self ): return self.name+'.'+self._extension
def setMbkEnv ( self ):
if Environment.isExt(self.extension,Environment.StructuralExt):
self.OUT_LO = self.extension
else:
raise ErrorMessage( 1, 'Cougar(): Invalid output netlist file format/ext <%s>.'
% self.extension )
if Environment.isExt(self.getDependency(0).extension,Environment.PhysicalExt):
self.IN_PH = self.getDependency(0).extension
else:
raise ErrorMessage( 1, 'Cougar(): Input file format/ext must be physical, not <%s>.'
% self.getDependency(0).extension )
return
def asCommand ( self ):
command = [ 'cougar', '-v' ]
if self.flags & Cougar.TransistorFlatten: command += [ '-t' ]
if self.flags & Cougar.CatalogFlatten: command += [ '-f' ]
if self.flags & Cougar.CapaToGround: command += [ '-ac' ]
if self.flags & Cougar.RCToGround: command += [ '-ar' ]
command += [ self.getDependency(0).name ]
command += [ self.name ]
return command
class Lvx ( StampCommand ):
MergeSupplies = 0x00000001
OrderConnectors = 0x00000002
CheckUnassigneds = 0x00000004
CatalogFlatten = 0x00000008
def __init__ ( self, netlist1, netlist2 ):
StampCommand.__init__( self )
self.addDependency( netlist1 )
self.addDependency( netlist2 )
return
@property
def toolName ( self ): return 'Lvx'
def setMbkEnv ( self ):
if not Environment.isExt(self.getDependency(0).extension,Environment.StructuralExt):
raise ErrorMessage( 1, 'Lvx(): Input file 1 format/ext must be structural (netlist), not <%s>.'
% self.getDependency(0).extension )
if not Environment.isExt(self.getDependency(1).extension,Environment.StructuralExt):
raise ErrorMessage( 1, 'Lvx(): Input file 2 format/ext must be structural (netlist), not <%s>.'
% self.getDependency(1).extension )
return
def asCommand ( self ):
command = [ 'lvx' ]
command += [ self.getDependency(0).extension ]
command += [ self.getDependency(1).extension ]
command += [ self.getDependency(0).name ]
command += [ self.getDependency(1).name ]
if self.flags & Lvx.MergeSupplies: command += [ '-a' ]
if self.flags & Lvx.CheckUnassigneds: command += [ '-u' ]
if self.flags & Lvx.CatalogFlatten: command += [ '-f' ]
return command
class Druc ( StampCommand ):
def __init__ ( self, layout ):
StampCommand.__init__( self )
self.addDependency( layout )
return
@property
def toolName ( self ): return 'Druc'
def setMbkEnv ( self ):
if not Environment.isExt(self.getDependency(0).extension,Environment.PhysicalExt):
raise ErrorMessage( 1, 'Druc(): Input file format/ext must be physical (layout), not <%s>.'
% self.getDependency(0).extension )
return
def asCommand ( self ):
command = [ 'druc', '-v' ]
command += [ self.getDependency(0).name ]
return command
class Tools ( object ):
def __init__ ( self ):
self._sourceNodes = []
self._toolNodes = []
self._ruleNodes = []
self._staticOrder = []
return
def _findNodes ( self ):
Node.findSelfSymbols()
for node in Node.getAllNodes():
isCommand = False
for commandType in Command.commandTypes:
if isinstance(node,commandType):
self._toolNodes.append( node )
isCommand = True
break
if not isCommand:
if isinstance(node,Source): self._sourceNodes.append( node )
if isinstance(node,Rule ): self._ruleNodes.append( node )
# Three level of stack from the user's script python module.
#callerGlobals = inspect.stack()[2][0].f_globals
#for symbol in callerGlobals.keys():
# isCommand = False
# node = callerGlobals[symbol]
# for commandType in Command.commandTypes:
# if isinstance(node,commandType):
# node.setTarget( symbol )
# self._toolNodes.append( node )
# isCommand = True
# break
#
# if not isCommand \
# and ( isinstance(node,Source)
# or isinstance(node,Rule )):
# node.setTarget( symbol )
# self._sourceNodes.append( node )
#
#for node in Node.getAllNodes():
# if node.targetName: continue
# node.setDefaultTargetName()
# if not isinstance(node,Source):
# self._toolNodes.append( node )
return
def _sortNodes ( self ):
self._staticOrder = []
nodeStack = []
for node in self._sourceNodes:
node._depth = 0
nodeStack.append( node )
while nodeStack:
reacheds = 0
for inode in range(len(nodeStack)):
if nodeStack[inode].allDepsReached():
reacheds += 1
node = nodeStack.pop( inode )
self._staticOrder.append( node )
for child in node.getChilds():
if child.getDepth() < 0: nodeStack.append(child)
child.incDepsReached( node.getDepth()+1 )
break
if not reacheds and nodeStack:
raise ErrorMessage( 1, 'Loop in dependency graph.' )
return
def _setMbkEnv ( self ):
for node in self._staticOrder:
node.setMbkEnv()
return
@staticmethod
def run ( args=[] ):
tool = Tools()
tool._findNodes()
tool._sortNodes()
tool._setMbkEnv()
doClean = False
for arg in args:
if arg == 'clean': doClean = True
else:
node = Node.lookup( arg )
if node: node.setActive()
if commandFlags & ShowCommand and not (commandFlags & ShowLog):
print "==========+===============================+============================================"
print " ACTION | TARGET/RULE | COMMAND"
print "==========+===============================+============================================"
if doClean:
Node.allClean()
if commandFlags & ShowCommand and not (commandFlags & ShowLog):
print "----------+-------------------------------+--------------------------------------------"
for node in tool._staticOrder:
#for dep in node.getDependencies():
# print dep.name
# print dep.fileName
if not isinstance(node,Source) and not isinstance(node,Rule):
if node._run(): break
if commandFlags & ShowCommand and not (commandFlags & ShowLog):
print "----------+-------------------------------+--------------------------------------------"
return