sbsv2/raptor/python/raptor_make.py
changeset 3 e1eecf4d390d
parent 0 044383f39525
child 5 593a8820b912
--- a/sbsv2/raptor/python/raptor_make.py	Wed Oct 28 14:39:48 2009 +0000
+++ b/sbsv2/raptor/python/raptor_make.py	Mon Nov 16 09:46:46 2009 +0000
@@ -1,563 +1,563 @@
-#
-# Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
-# All rights reserved.
-# This component and the accompanying materials are made available
-# under the terms of the License "Eclipse Public License v1.0"
-# which accompanies this distribution, and is available
-# at the URL "http://www.eclipse.org/legal/epl-v10.html".
-#
-# Initial Contributors:
-# Nokia Corporation - initial contribution.
-#
-# Contributors:
-#
-# Description: 
-# raptor_make module
-# This module contains the classes that write and call Makefile wrappers.
-#
-
-import hashlib
-import os
-import random
-import raptor
-import raptor_data
-import raptor_utilities
-import raptor_version
-import re
-import subprocess
-import time
-from raptor_makefile import *
-
-# raptor_make module classes
-
-class MakeEngine(object):
-
-	def __init__(self, Raptor):
-		self.raptor = Raptor
-		self.valid = True
-		self.makefileset = None
-		self.descrambler = None
-		self.descrambler_started = False
-
-		engine = Raptor.makeEngine
-		
-		# look for an alias first as this gives end-users a chance to modify
-		# the shipped variant rather than completely replacing it.
-		if engine in Raptor.cache.aliases:
-			avar = Raptor.cache.FindNamedAlias(engine)
-		elif engine in Raptor.cache.variants:
-			avar = Raptor.cache.FindNamedVariant(engine)
-		else:
-			Raptor.Error("No settings found for build engine '%s'", engine)
-			return
-					
-		# find the variant and extract the values
-		try:
-			units = avar.GenerateBuildUnits()
-			evaluator = Raptor.GetEvaluator( None, units[0] , gathertools=True)
-
-			# shell
-			self.shellpath = evaluator.Get("DEFAULT_SHELL")
-			usetalon_s = evaluator.Get("USE_TALON") 
-			self.usetalon = usetalon_s is not None and usetalon_s != ""
-			self.talonshell = str(evaluator.Get("TALON_SHELL"))
-			self.talontimeout = str(evaluator.Get("TALON_TIMEOUT"))
-			self.talonretries = str(evaluator.Get("TALON_RETRIES"))
-
-			# commands
-			self.initCommand = evaluator.Get("initialise")
-			self.buildCommand = evaluator.Get("build")
-			self.shutdownCommand = evaluator.Get("shutdown")
-
-			# options
-			self.makefileOption = evaluator.Get("makefile")
-			self.keepGoingOption = evaluator.Get("keep_going")
-			self.jobsOption = evaluator.Get("jobs")
-			self.defaultMakeOptions = evaluator.Get("defaultoptions")
-
-			# buffering
-			self.scrambled = (evaluator.Get("scrambled") == "true")
-
-			# check tool versions
-			Raptor.CheckToolset(evaluator, avar.name)
-			
-			# default targets (can vary per-invocation)
-			self.defaultTargets = Raptor.defaultTargets
-
-			# work out how to split up makefiles
-			try:
-				selectorNames = [ x.strip() for x in evaluator.Get("selectors").split(',') if x.strip() != "" ]
-				self.selectors = []
-
-
-				if len(selectorNames) > 0:
-					for name in selectorNames:
-						pattern = evaluator.Get(name.strip() + ".selector.iface")
-						target = evaluator.Get(name.strip() + ".selector.target")
-						ignoretargets = evaluator.Get(name.strip() + ".selector.ignoretargets")
-						self.selectors.append(MakefileSelector(name,pattern,target,ignoretargets))
-			except KeyError:
-				Raptor.Error("%s.selector.iface, %s.selector.target not found in make engine configuration", name, name)
-				self.selectors = []
-
-		except KeyError:
-			Raptor.Error("Bad '%s' configuration found.", engine)
-			self.valid = False
-			return
-
-		# there must at least be a build command...
-		if not self.buildCommand:
-				Raptor.Error("No build command for '%s'", engine)
-				self.valid = False
-
-
-		if self.usetalon:
-			talon_settings="""
-TALON_SHELL:=%s
-TALON_TIMEOUT:=%s
-TALON_RECIPEATTRIBUTES:=\
- name='$$RECIPE'\
- target='$$TARGET'\
- host='$$HOSTNAME'\
- layer='$$COMPONENT_LAYER'\
- component='$$COMPONENT_NAME'\
- bldinf='$$COMPONENT_META' mmp='$$PROJECT_META'\
- config='$$SBS_CONFIGURATION' platform='$$PLATFORM'\
- phase='$$MAKEFILE_GROUP' source='$$SOURCE
-export TALON_RECIPEATTRIBUTES TALON_SHELL TALON_TIMEOUT
-USE_TALON:=%s
-
-""" % (self.talonshell, self.talontimeout, "1")
-		else:
-			talon_settings="""
-USE_TALON:=
-
-"""
-		
-
-		self.makefile_prologue = """
-# generated by %s %s
-
-HOSTPLATFORM:=%s
-HOSTPLATFORM_DIR:=%s
-OSTYPE:=%s
-FLMHOME:=%s
-SHELL:=%s
-
-%s
-
-include %s
-
-""" 		% (  raptor.name, raptor_version.Version(),
-			 " ".join(raptor.hostplatform),
-			 raptor.hostplatform_dir,
-			 self.raptor.filesystem,
-			 str(self.raptor.systemFLM),
-			 self.shellpath,
-			 talon_settings,
-			 self.raptor.systemFLM.Append('globals.mk') )
-
-
-		self.makefile_epilogue = """
-
-include %s
-
-""" 			% (self.raptor.systemFLM.Append('final.mk') )
-
-	def Write(self, toplevel, specs, configs):
-		"""Generate a set of makefiles, or one big Makefile."""
-
-		if not self.valid:
-			return
-
-		self.toplevel = toplevel
-
-		# create the top-level makefiles
-
-		try:
-			self.makefileset = MakefileSet(directory = str(toplevel.Dir()),
-										   selectors = self.selectors,
-										   filenamebase = str(toplevel.File()),
-										   prologue = self.makefile_prologue,
-										   epilogue = self.makefile_epilogue,
-										   defaulttargets = self.defaultTargets)
-
-			# are we pruning duplicates?
-			self.prune = self.raptor.pruneDuplicateMakefiles
-			self.hashes = set()
-
-			# are we writing one Makefile or lots?
-			self.many = not self.raptor.writeSingleMakefile
-
-			# add a makefile for each spec under each config
-			config_makefileset = self.makefileset
-
-			for c in configs:
-				if self.many:
-					config_makefileset = self.makefileset.createChild(c.name)
-
-				# make sure the config_wide spec item is put out first so that it
-				# can affect everything.
-				ordered_specs=[]
-				config_wide_spec = None
-				for s in specs:
-					if s.name == "config_wide":
-						config_wide_spec = s
-					else:
-						ordered_specs.append(s)
-
-				if config_wide_spec is not None:
-					config_wide_spec.Configure(c)
-					self.WriteConfiguredSpec(config_makefileset, config_wide_spec, c, True)
-
-				for s in ordered_specs:
-					s.Configure(c)
-					self.WriteConfiguredSpec(config_makefileset, s, c, False)
-
-			self.makefileset.close()
-		except Exception,e:
-			self.raptor.Error("Failed to write makefile '%s': %s" % (str(toplevel),str(e)))
-
-
-	def WriteConfiguredSpec(self, parentMakefileSet, spec, config, useAllInterfaces):
-		# ignore this spec if it is empty
-		hasInterface = spec.HasInterface()
-		childSpecs = spec.GetChildSpecs()
-
-		if not hasInterface and not childSpecs:
-			return
-
-		parameters = []
-		dupe = True
-		iface = None
-		guard = None
-		if hasInterface:
-			# find the Interface (it may be a ref)
-			iface = spec.GetInterface()
-
-			if iface == None:
-				self.raptor.Error("No interface for '%s'", spec.name)
-				return
-
-			if iface.abstract:
-				self.raptor.Error("Abstract interface '%s' for '%s'",
-								  iface.name, spec.name)
-				return
-
-			# we need to guard the FLM call with a hash based on all the
-			# parameter values so that duplicate calls cannot be made.
-			# So we need to find all the values before we can write
-			# anything out.
-			md5hash = hashlib.md5()
-			md5hash.update(iface.name)
-
-			# we need an Evaluator to get parameter values for this
-			# Specification in the context of this Configuration
-			evaluator = self.raptor.GetEvaluator(spec, config)
-
-			def addparam(k, value, default):
-				if value == None:
-					if p.default != None:
-						value = p.default
-					else:
-						self.raptor.Error("%s undefined for '%s'",
-										  k, spec.name)
-						value = ""
-
-				parameters.append((k, value))
-				md5hash.update(value)
-
-			# parameters required by the interface
-			for p in iface.GetParams():
-				val = evaluator.Resolve(p.name)
-				addparam(p.name,val,p.default)
-
-			# Use Patterns to fetch a group of parameters
-			for g in iface.GetParamGroups():
-				for k,v in evaluator.ResolveMatching(g.patternre):
-					addparam(k,v,g.default)
-
-			hash = md5hash.hexdigest()
-			dupe = hash in self.hashes
-
-			self.hashes.add(hash)
-
-		# we only create a Makefile if we have a new FLM call to contribute,
-		# OR we are not pruning duplicates (guarding instead)
-		# OR we have some child specs that need something to include them.
-		if dupe and self.prune and not childSpecs:
-			return
-
-		makefileset = parentMakefileSet
-		# Create a new layer of makefiles?
-		if self.many:
-			makefileset = makefileset.createChild(spec.name)
-
-		if not (self.prune and dupe):
-			if self.prune:
-				guard = ""
-			else:
-				guard = "guard_" + hash
-
-		# generate the call to the FLM
-		if iface is not None:
-			makefileset.addCall(spec.name, config.name, iface.name, useAllInterfaces, iface.GetFLMIncludePath(), parameters, guard)
-
-		# recursive includes
-
-		for child in childSpecs:
-			self.WriteConfiguredSpec(makefileset, child, config, useAllInterfaces)
-
-		if self.many:
-			makefileset.close() # close child set of makefiles as we'll never see them again.
-
-	def Make(self, makefileset):
-		"run the make command"
-
-		if not self.valid:
-			return False
-	
-		if self.usetalon:
-			# Always use Talon since it does the XML not
-			# just descrambling
-			if not self.StartTalon() and not self.raptor.keepGoing:
-				self.Tidy()
-				return False
-		else:
-			# use the descrambler if we are doing a parallel build on
-			# a make engine which does not buffer each agent's output
-			if self.raptor.jobs > 1 and self.scrambled:
-				self.StartDescrambler()
-				if  not self.descrambler_started and not self.raptor.keepGoing:
-					self.Tidy()
-					return False
-			
-		# run any initialisation script
-		if self.initCommand:
-			self.raptor.Info("Running %s", self.initCommand)
-			if os.system(self.initCommand) != 0:
-				self.raptor.Error("Failed in %s", self.initCommand)
-				self.Tidy()
-				return False
-
-		# Save file names to a list, to allow the order to be reversed
-		fileName_list = list(self.makefileset.makefileNames())
-
-		# Iterate through args passed to raptor, searching for CLEAN or REALLYCLEAN
-		clean_flag = False
-		for arg in self.raptor.args:
-			clean_flag = ("CLEAN" in self.raptor.args) or \
-			            ("REALLYCLEAN" in self.raptor.args)
-
-		# Files should be deleted in the opposite order to the order
-		# they were built. So reverse file order if cleaning
-		if clean_flag:
-			fileName_list.reverse()
-
-		# Process each file in turn
-		for makefile in fileName_list:
-			if not os.path.exists(makefile):
-				self.raptor.Info("Skipping makefile %s", makefile)
-				continue
-			self.raptor.Info("Making %s", makefile)
-			# assemble the build command line
-			command = self.buildCommand
-
-			if self.makefileOption:
-				command += " " + self.makefileOption + " " + '"' + str(makefile) + '"'
-
-			if self.raptor.keepGoing and self.keepGoingOption:
-				command += " " + self.keepGoingOption
-
-			if self.raptor.jobs > 1 and self.jobsOption:
-				command += " " + self.jobsOption +" "+ str(self.raptor.jobs)
-
-			# Set default options first so that they can be overridden by
-			# ones set by the --mo option on the raptor commandline:
-			command += " " + self.defaultMakeOptions
-			# Can supply options on the commandline to override default settings.
-			if len(self.raptor.makeOptions) > 0:
-				command += " " + " ".join(self.raptor.makeOptions)
-
-			# Switch off dependency file including?
-			if self.raptor.noDependInclude:
-				command += " NO_DEPEND_INCLUDE=1"
-			
-			if self.usetalon:
-				# use the descrambler if we set it up
-				command += ' TALON_DESCRAMBLE=' 
-				if self.scrambled:
-					command += '1 '
-				else:
-					command += '0 '
-			else:
-				if self.descrambler_started:
-					command += ' DESCRAMBLE="' + self.descrambler + '"'
-			
-			# use the retry mechanism if requested
-			if self.raptor.tries > 1:
-				command += ' RECIPETRIES=' + str(self.raptor.tries)
-				command += ' TALON_RETRIES=' + str(self.raptor.tries - 1)
-
-			# targets go at the end, if the makefile supports them
-			addTargets = self.raptor.targets[:]
-			ignoreTargets = self.makefileset.ignoreTargets(makefile)
-			if addTargets and ignoreTargets:
-				for target in self.raptor.targets:
-					if re.match(ignoreTargets, target):
-						addTargets.remove(target)
-
-			if addTargets:
-				command += " " + " ".join(addTargets)
-
-			self.raptor.Info("Executing '%s'", command)
-
-			# execute the build.
-			# the actual call differs between Windows and Unix.
-			# bufsize=1 means "line buffered"
-			#
-			try:
-				makeenv=os.environ.copy()
-				if self.usetalon:
-					makeenv['TALON_RECIPEATTRIBUTES']="none"
-					makeenv['TALON_SHELL']=self.talonshell
-					makeenv['TALON_BUILDID']=str(self.buildID)
-					makeenv['TALON_TIMEOUT']=str(self.talontimeout)
-				if self.raptor.filesystem == "unix":
-					p = subprocess.Popen(command, bufsize=65535,
-									     stdout=subprocess.PIPE,
-									     stderr=subprocess.STDOUT,
-									     close_fds=True, env=makeenv, shell=True)
-				else:
-					p = subprocess.Popen(command, bufsize=65535,
-									     stdout=subprocess.PIPE,
-									     stderr=subprocess.STDOUT,
-									     universal_newlines=True, env=makeenv)
-				stream = p.stdout
-
-
-				line = " "
-				while line:
-					line = stream.readline()
-					self.raptor.out.write(line)
-
-				# should be done now
-				returncode = p.wait()
-
-
-				if returncode != 0  and not self.raptor.keepGoing:
-					self.Tidy()
-					return False
-
-			except Exception,e:
-				self.raptor.Error("Exception '%s' during '%s'", str(e), command)
-				self.Tidy()
-				return False
-
-		# run any shutdown script
-		if self.shutdownCommand != None and self.shutdownCommand != "":
-			self.raptor.Info("Running %s", self.shutdownCommand)
-			if os.system(self.shutdownCommand) != 0:
-				self.raptor.Error("Failed in %s", self.shutdownCommand)
-				self.Tidy()
-				return False
-
-		self.Tidy()
-		return True
-
-	def Tidy(self):
-		if self.usetalon:
-			self.StopTalon() 
-		else:
-			"clean up after the make command"
-			self.StopDescrambler()
-
-	def StartTalon(self):
-		# the talon command
-		beginning = raptor.hostplatform_dir + "/bin"
-		if "win" in raptor.hostplatform:
-			end = ".exe"
-		else:
-			end = ""
-			
-		self.talonctl = str(self.raptor.home.Append(beginning, "talonctl"+end))
-			
-		# generate a unique build number
-		random.seed()
-		looking = True
-		tries = 0
-		while looking and tries < 100:
-			self.buildID = raptor.name + str(random.getrandbits(32))
-			
-			command = self.talonctl + " start"
-
-			os.environ["TALON_BUILDID"] = self.buildID
-			self.raptor.Info("Running %s", command)
-			looking = (os.system(command) != 0)
-			tries += 1
-		if looking:
-			self.raptor.Error("Failed to initilaise the talon shell for this build")
-			self.talonctl = ""
-			return False
-		
-		return True
-	
-	def StopTalon(self):
-		if self.talonctl:
-			command = self.talonctl + " stop"
-			self.talonctl = ""
-			
-			self.raptor.Info("Running %s", command)
-			if os.system(command) != 0:
-				self.raptor.Error("Failed in %s", command)
-				return False
-			
-		return True
-	
-	def StartDescrambler(self):
-		# the descrambler command
-		beginning = raptor.hostplatform_dir + "/bin"
-		if "win" in raptor.hostplatform:
-			end = ".exe"
-		else:
-			end = ""
-
-		self.descrambler = str(self.raptor.home.Append(beginning, "sbs_descramble"+end))
-			
-		# generate a unique build number
-		random.seed()
-		looking = True
-		tries = 0
-		while looking and tries < 100:
-			buildID = raptor.name + str(random.getrandbits(32))
-
-			command = self.descrambler + " " + buildID + " start"
-			self.raptor.Info("Running %s", command)
-			looking = (os.system(command) != 0)
-			tries += 1
-
-		if looking:
-			self.raptor.Error("Failed to start the log descrambler")
-			self.descrambler_started = True
-			return False
-
-		self.descrambler_started = True
-		self.descrambler +=	" " + buildID
-
-		return  True
-
-	def StopDescrambler(self):
-		if self.descrambler_started:
-			command = self.descrambler + " stop"
-			self.descrambler = ""
-
-			self.raptor.Info("Running %s", command)
-			if os.system(command) != 0:
-				self.raptor.Error("Failed in %s", command)
-				return False
-		return True
-
-# raptor_make module functions
-
-
-# end of the raptor_make module
+#
+# Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+# raptor_make module
+# This module contains the classes that write and call Makefile wrappers.
+#
+
+import hashlib
+import os
+import random
+import raptor
+import raptor_data
+import raptor_utilities
+import raptor_version
+import re
+import subprocess
+import time
+from raptor_makefile import *
+
+# raptor_make module classes
+
+class MakeEngine(object):
+
+	def __init__(self, Raptor):
+		self.raptor = Raptor
+		self.valid = True
+		self.makefileset = None
+		self.descrambler = None
+		self.descrambler_started = False
+
+		engine = Raptor.makeEngine
+		
+		# look for an alias first as this gives end-users a chance to modify
+		# the shipped variant rather than completely replacing it.
+		if engine in Raptor.cache.aliases:
+			avar = Raptor.cache.FindNamedAlias(engine)
+		elif engine in Raptor.cache.variants:
+			avar = Raptor.cache.FindNamedVariant(engine)
+		else:
+			Raptor.Error("No settings found for build engine '%s'", engine)
+			return
+					
+		# find the variant and extract the values
+		try:
+			units = avar.GenerateBuildUnits()
+			evaluator = Raptor.GetEvaluator( None, units[0] , gathertools=True)
+
+			# shell
+			self.shellpath = evaluator.Get("DEFAULT_SHELL")
+			usetalon_s = evaluator.Get("USE_TALON") 
+			self.usetalon = usetalon_s is not None and usetalon_s != ""
+			self.talonshell = str(evaluator.Get("TALON_SHELL"))
+			self.talontimeout = str(evaluator.Get("TALON_TIMEOUT"))
+			self.talonretries = str(evaluator.Get("TALON_RETRIES"))
+
+			# commands
+			self.initCommand = evaluator.Get("initialise")
+			self.buildCommand = evaluator.Get("build")
+			self.shutdownCommand = evaluator.Get("shutdown")
+
+			# options
+			self.makefileOption = evaluator.Get("makefile")
+			self.keepGoingOption = evaluator.Get("keep_going")
+			self.jobsOption = evaluator.Get("jobs")
+			self.defaultMakeOptions = evaluator.Get("defaultoptions")
+
+			# buffering
+			self.scrambled = (evaluator.Get("scrambled") == "true")
+
+			# check tool versions
+			Raptor.CheckToolset(evaluator, avar.name)
+			
+			# default targets (can vary per-invocation)
+			self.defaultTargets = Raptor.defaultTargets
+
+			# work out how to split up makefiles
+			try:
+				selectorNames = [ x.strip() for x in evaluator.Get("selectors").split(',') if x.strip() != "" ]
+				self.selectors = []
+
+
+				if len(selectorNames) > 0:
+					for name in selectorNames:
+						pattern = evaluator.Get(name.strip() + ".selector.iface")
+						target = evaluator.Get(name.strip() + ".selector.target")
+						ignoretargets = evaluator.Get(name.strip() + ".selector.ignoretargets")
+						self.selectors.append(MakefileSelector(name,pattern,target,ignoretargets))
+			except KeyError:
+				Raptor.Error("%s.selector.iface, %s.selector.target not found in make engine configuration", name, name)
+				self.selectors = []
+
+		except KeyError:
+			Raptor.Error("Bad '%s' configuration found.", engine)
+			self.valid = False
+			return
+
+		# there must at least be a build command...
+		if not self.buildCommand:
+				Raptor.Error("No build command for '%s'", engine)
+				self.valid = False
+
+
+		if self.usetalon:
+			talon_settings="""
+TALON_SHELL:=%s
+TALON_TIMEOUT:=%s
+TALON_RECIPEATTRIBUTES:=\
+ name='$$RECIPE'\
+ target='$$TARGET'\
+ host='$$HOSTNAME'\
+ layer='$$COMPONENT_LAYER'\
+ component='$$COMPONENT_NAME'\
+ bldinf='$$COMPONENT_META' mmp='$$PROJECT_META'\
+ config='$$SBS_CONFIGURATION' platform='$$PLATFORM'\
+ phase='$$MAKEFILE_GROUP' source='$$SOURCE
+export TALON_RECIPEATTRIBUTES TALON_SHELL TALON_TIMEOUT
+USE_TALON:=%s
+
+""" % (self.talonshell, self.talontimeout, "1")
+		else:
+			talon_settings="""
+USE_TALON:=
+
+"""
+		
+
+		self.makefile_prologue = """
+# generated by %s %s
+
+HOSTPLATFORM:=%s
+HOSTPLATFORM_DIR:=%s
+OSTYPE:=%s
+FLMHOME:=%s
+SHELL:=%s
+
+%s
+
+include %s
+
+""" 		% (  raptor.name, raptor_version.Version(),
+			 " ".join(raptor.hostplatform),
+			 raptor.hostplatform_dir,
+			 self.raptor.filesystem,
+			 str(self.raptor.systemFLM),
+			 self.shellpath,
+			 talon_settings,
+			 self.raptor.systemFLM.Append('globals.mk') )
+
+
+		self.makefile_epilogue = """
+
+include %s
+
+""" 			% (self.raptor.systemFLM.Append('final.mk') )
+
+	def Write(self, toplevel, specs, configs):
+		"""Generate a set of makefiles, or one big Makefile."""
+
+		if not self.valid:
+			return
+
+		self.toplevel = toplevel
+
+		# create the top-level makefiles
+
+		try:
+			self.makefileset = MakefileSet(directory = str(toplevel.Dir()),
+										   selectors = self.selectors,
+										   filenamebase = str(toplevel.File()),
+										   prologue = self.makefile_prologue,
+										   epilogue = self.makefile_epilogue,
+										   defaulttargets = self.defaultTargets)
+
+			# are we pruning duplicates?
+			self.prune = self.raptor.pruneDuplicateMakefiles
+			self.hashes = set()
+
+			# are we writing one Makefile or lots?
+			self.many = not self.raptor.writeSingleMakefile
+
+			# add a makefile for each spec under each config
+			config_makefileset = self.makefileset
+
+			for c in configs:
+				if self.many:
+					config_makefileset = self.makefileset.createChild(c.name)
+
+				# make sure the config_wide spec item is put out first so that it
+				# can affect everything.
+				ordered_specs=[]
+				config_wide_spec = None
+				for s in specs:
+					if s.name == "config_wide":
+						config_wide_spec = s
+					else:
+						ordered_specs.append(s)
+
+				if config_wide_spec is not None:
+					config_wide_spec.Configure(c)
+					self.WriteConfiguredSpec(config_makefileset, config_wide_spec, c, True)
+
+				for s in ordered_specs:
+					s.Configure(c)
+					self.WriteConfiguredSpec(config_makefileset, s, c, False)
+
+			self.makefileset.close()
+		except Exception,e:
+			self.raptor.Error("Failed to write makefile '%s': %s" % (str(toplevel),str(e)))
+
+
+	def WriteConfiguredSpec(self, parentMakefileSet, spec, config, useAllInterfaces):
+		# ignore this spec if it is empty
+		hasInterface = spec.HasInterface()
+		childSpecs = spec.GetChildSpecs()
+
+		if not hasInterface and not childSpecs:
+			return
+
+		parameters = []
+		dupe = True
+		iface = None
+		guard = None
+		if hasInterface:
+			# find the Interface (it may be a ref)
+			iface = spec.GetInterface()
+
+			if iface == None:
+				self.raptor.Error("No interface for '%s'", spec.name)
+				return
+
+			if iface.abstract:
+				self.raptor.Error("Abstract interface '%s' for '%s'",
+								  iface.name, spec.name)
+				return
+
+			# we need to guard the FLM call with a hash based on all the
+			# parameter values so that duplicate calls cannot be made.
+			# So we need to find all the values before we can write
+			# anything out.
+			md5hash = hashlib.md5()
+			md5hash.update(iface.name)
+
+			# we need an Evaluator to get parameter values for this
+			# Specification in the context of this Configuration
+			evaluator = self.raptor.GetEvaluator(spec, config)
+
+			def addparam(k, value, default):
+				if value == None:
+					if p.default != None:
+						value = p.default
+					else:
+						self.raptor.Error("%s undefined for '%s'",
+										  k, spec.name)
+						value = ""
+
+				parameters.append((k, value))
+				md5hash.update(value)
+
+			# parameters required by the interface
+			for p in iface.GetParams():
+				val = evaluator.Resolve(p.name)
+				addparam(p.name,val,p.default)
+
+			# Use Patterns to fetch a group of parameters
+			for g in iface.GetParamGroups():
+				for k,v in evaluator.ResolveMatching(g.patternre):
+					addparam(k,v,g.default)
+
+			hash = md5hash.hexdigest()
+			dupe = hash in self.hashes
+
+			self.hashes.add(hash)
+
+		# we only create a Makefile if we have a new FLM call to contribute,
+		# OR we are not pruning duplicates (guarding instead)
+		# OR we have some child specs that need something to include them.
+		if dupe and self.prune and not childSpecs:
+			return
+
+		makefileset = parentMakefileSet
+		# Create a new layer of makefiles?
+		if self.many:
+			makefileset = makefileset.createChild(spec.name)
+
+		if not (self.prune and dupe):
+			if self.prune:
+				guard = ""
+			else:
+				guard = "guard_" + hash
+
+		# generate the call to the FLM
+		if iface is not None:
+			makefileset.addCall(spec.name, config.name, iface.name, useAllInterfaces, iface.GetFLMIncludePath(), parameters, guard)
+
+		# recursive includes
+
+		for child in childSpecs:
+			self.WriteConfiguredSpec(makefileset, child, config, useAllInterfaces)
+
+		if self.many:
+			makefileset.close() # close child set of makefiles as we'll never see them again.
+
+	def Make(self, makefileset):
+		"run the make command"
+
+		if not self.valid:
+			return False
+	
+		if self.usetalon:
+			# Always use Talon since it does the XML not
+			# just descrambling
+			if not self.StartTalon() and not self.raptor.keepGoing:
+				self.Tidy()
+				return False
+		else:
+			# use the descrambler if we are doing a parallel build on
+			# a make engine which does not buffer each agent's output
+			if self.raptor.jobs > 1 and self.scrambled:
+				self.StartDescrambler()
+				if  not self.descrambler_started and not self.raptor.keepGoing:
+					self.Tidy()
+					return False
+			
+		# run any initialisation script
+		if self.initCommand:
+			self.raptor.Info("Running %s", self.initCommand)
+			if os.system(self.initCommand) != 0:
+				self.raptor.Error("Failed in %s", self.initCommand)
+				self.Tidy()
+				return False
+
+		# Save file names to a list, to allow the order to be reversed
+		fileName_list = list(self.makefileset.makefileNames())
+
+		# Iterate through args passed to raptor, searching for CLEAN or REALLYCLEAN
+		clean_flag = False
+		for arg in self.raptor.args:
+			clean_flag = ("CLEAN" in self.raptor.args) or \
+			            ("REALLYCLEAN" in self.raptor.args)
+
+		# Files should be deleted in the opposite order to the order
+		# they were built. So reverse file order if cleaning
+		if clean_flag:
+			fileName_list.reverse()
+
+		# Process each file in turn
+		for makefile in fileName_list:
+			if not os.path.exists(makefile):
+				self.raptor.Info("Skipping makefile %s", makefile)
+				continue
+			self.raptor.Info("Making %s", makefile)
+			# assemble the build command line
+			command = self.buildCommand
+
+			if self.makefileOption:
+				command += " " + self.makefileOption + " " + '"' + str(makefile) + '"'
+
+			if self.raptor.keepGoing and self.keepGoingOption:
+				command += " " + self.keepGoingOption
+
+			if self.raptor.jobs > 1 and self.jobsOption:
+				command += " " + self.jobsOption +" "+ str(self.raptor.jobs)
+
+			# Set default options first so that they can be overridden by
+			# ones set by the --mo option on the raptor commandline:
+			command += " " + self.defaultMakeOptions
+			# Can supply options on the commandline to override default settings.
+			if len(self.raptor.makeOptions) > 0:
+				command += " " + " ".join(self.raptor.makeOptions)
+
+			# Switch off dependency file including?
+			if self.raptor.noDependInclude:
+				command += " NO_DEPEND_INCLUDE=1"
+			
+			if self.usetalon:
+				# use the descrambler if we set it up
+				command += ' TALON_DESCRAMBLE=' 
+				if self.scrambled:
+					command += '1 '
+				else:
+					command += '0 '
+			else:
+				if self.descrambler_started:
+					command += ' DESCRAMBLE="' + self.descrambler + '"'
+			
+			# use the retry mechanism if requested
+			if self.raptor.tries > 1:
+				command += ' RECIPETRIES=' + str(self.raptor.tries)
+				command += ' TALON_RETRIES=' + str(self.raptor.tries - 1)
+
+			# targets go at the end, if the makefile supports them
+			addTargets = self.raptor.targets[:]
+			ignoreTargets = self.makefileset.ignoreTargets(makefile)
+			if addTargets and ignoreTargets:
+				for target in self.raptor.targets:
+					if re.match(ignoreTargets, target):
+						addTargets.remove(target)
+
+			if addTargets:
+				command += " " + " ".join(addTargets)
+
+			self.raptor.Info("Executing '%s'", command)
+
+			# execute the build.
+			# the actual call differs between Windows and Unix.
+			# bufsize=1 means "line buffered"
+			#
+			try:
+				makeenv=os.environ.copy()
+				if self.usetalon:
+					makeenv['TALON_RECIPEATTRIBUTES']="none"
+					makeenv['TALON_SHELL']=self.talonshell
+					makeenv['TALON_BUILDID']=str(self.buildID)
+					makeenv['TALON_TIMEOUT']=str(self.talontimeout)
+				if self.raptor.filesystem == "unix":
+					p = subprocess.Popen(command, bufsize=65535,
+									     stdout=subprocess.PIPE,
+									     stderr=subprocess.STDOUT,
+									     close_fds=True, env=makeenv, shell=True)
+				else:
+					p = subprocess.Popen(command, bufsize=65535,
+									     stdout=subprocess.PIPE,
+									     stderr=subprocess.STDOUT,
+									     universal_newlines=True, env=makeenv)
+				stream = p.stdout
+
+
+				line = " "
+				while line:
+					line = stream.readline()
+					self.raptor.out.write(line)
+
+				# should be done now
+				returncode = p.wait()
+
+
+				if returncode != 0  and not self.raptor.keepGoing:
+					self.Tidy()
+					return False
+
+			except Exception,e:
+				self.raptor.Error("Exception '%s' during '%s'", str(e), command)
+				self.Tidy()
+				return False
+
+		# run any shutdown script
+		if self.shutdownCommand != None and self.shutdownCommand != "":
+			self.raptor.Info("Running %s", self.shutdownCommand)
+			if os.system(self.shutdownCommand) != 0:
+				self.raptor.Error("Failed in %s", self.shutdownCommand)
+				self.Tidy()
+				return False
+
+		self.Tidy()
+		return True
+
+	def Tidy(self):
+		if self.usetalon:
+			self.StopTalon() 
+		else:
+			"clean up after the make command"
+			self.StopDescrambler()
+
+	def StartTalon(self):
+		# the talon command
+		beginning = raptor.hostplatform_dir + "/bin"
+		if "win" in raptor.hostplatform:
+			end = ".exe"
+		else:
+			end = ""
+			
+		self.talonctl = str(self.raptor.home.Append(beginning, "talonctl"+end))
+			
+		# generate a unique build number
+		random.seed()
+		looking = True
+		tries = 0
+		while looking and tries < 100:
+			self.buildID = raptor.name + str(random.getrandbits(32))
+			
+			command = self.talonctl + " start"
+
+			os.environ["TALON_BUILDID"] = self.buildID
+			self.raptor.Info("Running %s", command)
+			looking = (os.system(command) != 0)
+			tries += 1
+		if looking:
+			self.raptor.Error("Failed to initilaise the talon shell for this build")
+			self.talonctl = ""
+			return False
+		
+		return True
+	
+	def StopTalon(self):
+		if self.talonctl:
+			command = self.talonctl + " stop"
+			self.talonctl = ""
+			
+			self.raptor.Info("Running %s", command)
+			if os.system(command) != 0:
+				self.raptor.Error("Failed in %s", command)
+				return False
+			
+		return True
+	
+	def StartDescrambler(self):
+		# the descrambler command
+		beginning = raptor.hostplatform_dir + "/bin"
+		if "win" in raptor.hostplatform:
+			end = ".exe"
+		else:
+			end = ""
+
+		self.descrambler = str(self.raptor.home.Append(beginning, "sbs_descramble"+end))
+			
+		# generate a unique build number
+		random.seed()
+		looking = True
+		tries = 0
+		while looking and tries < 100:
+			buildID = raptor.name + str(random.getrandbits(32))
+
+			command = self.descrambler + " " + buildID + " start"
+			self.raptor.Info("Running %s", command)
+			looking = (os.system(command) != 0)
+			tries += 1
+
+		if looking:
+			self.raptor.Error("Failed to start the log descrambler")
+			self.descrambler_started = True
+			return False
+
+		self.descrambler_started = True
+		self.descrambler +=	" " + buildID
+
+		return  True
+
+	def StopDescrambler(self):
+		if self.descrambler_started:
+			command = self.descrambler + " stop"
+			self.descrambler = ""
+
+			self.raptor.Info("Running %s", command)
+			if os.system(command) != 0:
+				self.raptor.Error("Failed in %s", command)
+				return False
+		return True
+
+# raptor_make module functions
+
+
+# end of the raptor_make module