diff -r 000000000000 -r 044383f39525 sbsv2/raptor/python/raptor.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sbsv2/raptor/python/raptor.py Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,1234 @@
+#
+# 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 module
+# This module represents the running Raptor program. Raptor is started
+# either by calling the Main() function, which creates an instance of
+# the raptor.Raptor class and calls its methods to perform a build based
+# on command-line parameters, or by explicitly creating a raptor.Raptor
+# instance and calling its methods to set-up and perform a build.
+#
+
+name = "sbs" # the public name for the raptor build tool
+env = "SBS_HOME" # the environment variable that locates us
+xml = "sbs_init.xml" # the primary initialisation file
+env2 = "HOME" # the environment variable that locates the user
+xml2 = ".sbs_init.xml" # the override initialisation file
+
+import generic_path
+import os
+import raptor_cache
+import raptor_cli
+import raptor_data
+import raptor_make
+import raptor_meta
+import raptor_utilities
+import raptor_version
+import raptor_xml
+import filter_list
+import sys
+import types
+import time
+import re
+import traceback
+import pluginbox
+from xml.sax.saxutils import escape
+
+
+if not "HOSTPLATFORM" in os.environ or not "HOSTPLATFORM_DIR" in os.environ:
+ print "Error: HOSTPLATFORM and HOSTPLATFORM_DIR must be set in the environment (this is usually done automatically by the startup script)."
+ sys.exit(1)
+
+hostplatform = os.environ["HOSTPLATFORM"].split(" ")
+hostplatform_dir = os.environ["HOSTPLATFORM_DIR"]
+
+# defaults can use EPOCROOT
+if "EPOCROOT" in os.environ:
+ epocroot = os.environ["EPOCROOT"].replace("\\","/")
+else:
+ if 'linux' in hostplatform:
+ epocroot=os.environ['HOME'] + os.sep + "epocroot"
+ os.environ["EPOCROOT"] = epocroot
+ else:
+ epocroot = "/"
+ os.environ["EPOCROOT"] = os.sep
+
+if "SBS_BUILD_DIR" in os.environ:
+ sbs_build_dir = os.environ["SBS_BUILD_DIR"]
+else:
+ sbs_build_dir = (epocroot + "/epoc32/build").replace("//","/")
+
+
+
+# only use default XML from the epoc32 tree if it exists
+defaultSystemConfig = "lib/config"
+epoc32UserConfigDir = generic_path.Join(epocroot, "epoc32/sbs_config")
+if epoc32UserConfigDir.isDir():
+ defaultSystemConfig = str(epoc32UserConfigDir) + os.pathsep + defaultSystemConfig
+
+# parameters that can be overriden by the sbs_init.xml file
+# or by the command-line.
+defaults = {
+ "allowCommandLineOverrides" : True,
+ "CLI" : "raptor_cli",
+ "buildInformation" : generic_path.Path("bld.inf"),
+ "defaultConfig" : "default",
+ "jobs": 4,
+ "keepGoing": False,
+ "logFileName" : generic_path.Join(sbs_build_dir,"Makefile.%TIME.log"),
+ "makeEngine" : "make",
+ "preferBuildInfoToSystemDefinition" : False,
+ "pruneDuplicateMakefiles": True,
+ "quiet" : False,
+ "systemConfig" : defaultSystemConfig,
+ "systemDefinition" : generic_path.Path("System_Definition.xml"),
+ "systemDefinitionBase" : generic_path.Path("."),
+ "systemFLM" : generic_path.Path("lib/flm"),
+ "systemPlugins" : generic_path.Path("python/plugins"),
+ "topMakefile" : generic_path.Join(sbs_build_dir,"Makefile"),
+ "tries": 1,
+ "writeSingleMakefile": True,
+ "ignoreOsDetection": False,
+ "toolcheck": "on",
+ "filterList": "filterterminal,filterlogfile"
+ }
+
+
+class ComponentGroup(object):
+ """ Some components that should be built togther
+ e.g. a Layer in the system definition.
+ """
+ def __init__(self, name, componentlist=[]):
+ self.components = componentlist
+ self.name = name
+
+ def __iter__(self):
+ return iter(self.components)
+
+ def __getitem__(self,x):
+ if isinstance(x, slice):
+ return self.components[x.start:x.stop]
+ return self.components[x]
+
+ def __setitem__(self,k, v):
+ self.components[k] = v
+
+ def __len__(self):
+ return len(self.components)
+
+ def extend(self, c):
+ self.components.extend(c)
+
+ def append(self, c):
+ self.components.append(c)
+
+ def GenerateSpecs(self, genericspecs, configs):
+ """Return a build spec hierarchy for a ComponentGroup. This involves parsing the component MetaData (bld.infs, mmps).
+ Takes a raptor object as a parameter (build), together with a list of Configurations.
+
+ Returns a tuple consisting of a list of specification objects and a list of dependency files
+ that relate to these specs.
+ """
+
+ self.specs = []
+ self.specs.extend(genericspecs)
+ self.configs = configs
+ self.dependencies = set()
+
+ metaReader = None
+ if len (self.components):
+ try:
+ # create a MetaReader that is aware of the list of
+ # configurations that we are trying to build.
+ metaReader = raptor_meta.MetaReader(build, configs)
+
+ # convert the list of bld.inf files into a specification
+ # hierarchy suitable for all the configurations we are using.
+ self.specs.extend(metaReader.ReadBldInfFiles(self.components,build.doExportOnly))
+
+ except raptor_meta.MetaDataError, e:
+ log.Error(e.Text)
+
+ log.Info("Buildable specification group '%s'", name)
+ build.AttachSpecs(self.specs)
+
+ # Get a unique list of the dependency files that were created
+ if metaReader:
+ for c in metaReader.BuildPlatforms:
+ self.dependencies.update(c["METADEPS"])
+
+
+ def CreateMakefile(self, makefilename_base, engine, named = False):
+ if len(self.specs) <= 0:
+ return None
+
+ if named:
+ makefile = generic_path.Path(str(makefilename_base) + "_" + raptor_utilities.sanitise(self.name))
+ else:
+ makefile = generic_path.Path(str(makefilename_base))
+
+ # insert the start time into the Makefile name?
+ makefile.path = makefile.path.replace("%TIME", build.timestring)
+
+ engine.Write(makefile, self.specs, self.configs)
+
+ return makefile
+
+
+ def GenerateMetadataSpecs(self, configs):
+ # insert the start time into the Makefile name?
+
+ self.configs = build.GetConfig("build").GenerateBuildUnits()
+
+ # Pass certain CLI flags through to the makefile-generating sbs calls
+ cli_options = ""
+
+ if build.debugOutput == True:
+ cli_options += " -d"
+
+ if build.ignoreOsDetection == True:
+ cli_options += " -i"
+
+ if build.keepGoing == True:
+ cli_options += " -k"
+
+ if build.quiet == True:
+ cli_options += " -q"
+
+
+ nc = len(self.components)
+ number_blocks = 16
+ block_size = (nc / number_blocks) + 1
+ component_blocks = []
+ spec_nodes = []
+
+ b = 0
+ while b < nc:
+ component_blocks.append(self.components[b:b+block_size])
+ b += block_size
+
+ if len(component_blocks[-1]) <= 0:
+ component_blocks.pop()
+
+ loop_number = 0
+ for block in component_blocks:
+ loop_number += 1
+ specNode = raptor_data.Specification("metadata_" + self.name)
+
+ componentList = " ".join([str(c) for c in block])
+ configList = " ".join([c.name for c in configs])
+
+ makefile_path = str(build.topMakefile) + "_" + str(loop_number)
+ try:
+ os.unlink(makefile_path) # until we have dependencies working properly
+ except Exception,e:
+ # print "couldn't unlink %s: %s" %(componentMakefileName, str(e))
+ pass
+
+ # add some basic data in a component-wide variant
+ var = raptor_data.Variant()
+ var.AddOperation(raptor_data.Set("COMPONENT_PATHS", componentList))
+ var.AddOperation(raptor_data.Set("MAKEFILE_PATH", makefile_path))
+ var.AddOperation(raptor_data.Set("CONFIGS", configList))
+ var.AddOperation(raptor_data.Set("CLI_OPTIONS", cli_options))
+ # Pass on '-n' (if specified) to the makefile-generating sbs calls
+ if build.noBuild:
+ var.AddOperation(raptor_data.Set("NO_BUILD", "1"))
+ specNode.AddVariant(var)
+
+
+
+ try:
+ interface = build.cache.FindNamedInterface("build.makefiles")
+ specNode.SetInterface(interface)
+ except KeyError:
+ build.Error("Can't find flm interface 'build.makefiles' ")
+
+ spec_nodes.append(specNode)
+
+
+
+ ## possibly some error handling here?
+
+ self.specs = spec_nodes
+
+
+class BuildCompleteException(Exception):
+ pass
+
+# raptor module classes
+
+class Raptor(object):
+ """An instance of a running Raptor program.
+
+ When operated from the command-line there is a single Raptor object
+ created by the Main function. When operated by an IDE several Raptor
+ objects may be created and operated at the same time."""
+
+
+ M_BUILD = 1
+ M_VERSION = 2
+
+ def __init__(self, home = None):
+
+ self.DefaultSetUp(home)
+
+
+ def DefaultSetUp(self, home = None):
+ "revert to the default set-up state"
+ self.errorCode = 0
+ self.skipAll = False
+ self.summary = True
+ self.out = sys.stdout # Just until filters get started.
+
+ # Create a bootstrap output system.
+ self.out = filter_list.FilterList()
+
+ if home == None:
+ try:
+ home = os.environ[env]
+ except KeyError:
+ home = os.getcwd()
+
+ # make sure the home directory exists
+ self.home = generic_path.Path(home).Absolute()
+
+ if not self.home.isDir():
+ self.Error("%s '%s' is not a directory", env, self.home)
+ return
+
+ # the set-up file location.
+ # use the override "env2/xml2" if it exists
+ # else use the primary "env/xml" if it exists
+ # else keep the hard-coded defaults.
+ self.raptorXML = self.home.Append(xml)
+
+ if env2 in os.environ:
+ sbs_init = generic_path.Join(os.environ[env2], xml2)
+ if sbs_init.isFile():
+ self.raptorXML = sbs_init
+
+ # things that can be overridden by the set-up file
+ for key, value in defaults.items():
+ self.__dict__[key] = value
+
+ # things to initialise
+ self.args = []
+
+ self.componentGroups = []
+ self.orderComponentGroups = False
+ self.commandlineComponents = []
+
+ self.systemModel = None
+ self.systemDefinitionFile = None
+ self.systemDefinitionRequestedLayers = []
+ self.systemDefinitionOrderLayers = False
+
+ self.specGroups = {}
+
+ self.configNames = []
+ self.configsToBuild = set()
+ self.makeOptions = []
+ self.maker = None
+ self.debugOutput = False
+ self.doExportOnly = False
+ self.noBuild = False
+ self.noDependInclude = False
+ self.projects = set()
+
+ self.cache = raptor_cache.Cache(self)
+ self.override = {env: str(self.home)}
+ self.targets = []
+ self.defaultTargets = []
+
+ self.doCheck = False
+ self.doWhat = False
+ self.doParallelParsing = False
+ self.mission = Raptor.M_BUILD
+
+ # what platform and filesystem are we running on?
+ self.filesystem = raptor_utilities.getOSFileSystem()
+
+ self.toolset = None
+
+ self.starttime = time.time()
+ self.timestring = time.strftime("%Y-%m-%d-%H-%M-%S")
+
+ self.fatalErrorState = False
+
+ def AddConfigList(self, configPathList):
+ # this function converts cmd line option into a list
+ # and prepends it to default config.
+ self.configPath = generic_path.NormalisePathList(configPathList.split(os.pathsep)) + self.configPath
+ return True
+
+ def AddConfigName(self, name):
+ self.configNames.append(name)
+ return True
+
+ def RunQuietly(self, TrueOrFalse):
+ self.quiet = TrueOrFalse
+ return True
+
+ def SetCheck(self, TrueOrFalse):
+ self.doCheck = TrueOrFalse
+ return True
+
+ def SetWhat(self, TrueOrFalse):
+ self.doWhat = TrueOrFalse
+ return True
+
+ def SetEnv(self, name, value):
+ self.override[name] = value
+
+ def AddTarget(self, target):
+ if self.doCheck or self.doWhat:
+ self.Warn("ignoring target %s because --what or --check is specified.\n", target)
+ else:
+ self.targets.append(target)
+
+ def AddSourceTarget(self, filename):
+ # source targets are sanitised and then added as if they were a "normal" makefile target
+ # in addition they have a default, empty, top-level target assigned in order that they can
+ # be presented to any generated makefile without error
+ sourceTarget = generic_path.Path(filename).Absolute()
+ sourceTarget = 'SOURCETARGET_' + raptor_utilities.sanitise(str(sourceTarget))
+ self.AddTarget(sourceTarget)
+ self.defaultTargets.append(sourceTarget)
+ return True
+
+ def SetSysDefFile(self, filename):
+ self.systemDefinitionFile = generic_path.Path(filename)
+ return True
+
+ def SetSysDefBase(self, path):
+ self.systemDefinitionBase = generic_path.Path(path)
+ return True
+
+ def AddSysDefLayer(self, layer):
+ self.systemDefinitionRequestedLayers.append(layer)
+ return True
+
+ def SetSysDefOrderLayers(self, TrueOrFalse):
+ self.systemDefinitionOrderLayers = TrueOrFalse
+ return True
+
+ def AddBuildInfoFile(self, filename):
+ bldinf = generic_path.Path(filename).Absolute()
+ self.commandlineComponents.append(bldinf)
+ return True
+
+ def SetTopMakefile(self, filename):
+ self.topMakefile = generic_path.Path(filename)
+ return True
+
+ def SetDebugOutput(self, TrueOrFalse):
+ self.debugOutput = TrueOrFalse
+ return True
+
+ def SetExportOnly(self, TrueOrFalse):
+ self.doExportOnly = TrueOrFalse
+ return True
+
+ def SetNoBuild(self, TrueOrFalse):
+ self.noBuild = TrueOrFalse
+ return True
+
+ def SetNoDependInclude(self, TrueOrFalse):
+ self.noDependInclude = TrueOrFalse
+ return True
+
+ def SetKeepGoing(self, TrueOrFalse):
+ self.keepGoing = TrueOrFalse
+ return True
+
+ def SetLogFileName(self, logfile):
+ if logfile == "-":
+ self.logFileName = None # stdout
+ else:
+ self.logFileName = generic_path.Path(logfile)
+ return True
+
+ def SetMakeEngine(self, makeEngine):
+ self.makeEngine = makeEngine
+ return True
+
+ def AddMakeOption(self, makeOption):
+ self.makeOptions.append(makeOption)
+ return True
+
+ def SetJobs(self, numberOfJobs):
+ try:
+ self.jobs = int(numberOfJobs)
+ except ValueError:
+ self.jobs = 0
+
+ if self.jobs < 1:
+ self.Warn("The number of jobs (%s) must be a positive integer\n", numberOfJobs)
+ self.jobs = 1
+ return False
+ return True
+
+ def SetTries(self, numberOfTries):
+ try:
+ self.tries = int(numberOfTries)
+ except ValueError:
+ self.tries = 0
+
+ if self.tries < 1:
+ self.Warn("The number of tries (%s) must be a positive integer\n", numberOfTries)
+ self.tries = 1
+ return False
+ return True
+
+ def SetToolCheck(self, type):
+ type = type.lower()
+ toolcheck_types= [ "forced", "on", "off" ]
+ if type in toolcheck_types:
+ self.toolcheck=type
+ else:
+ self.Warn("toolcheck option must be one of: %s" % toolcheck_types)
+ return False
+
+ return True
+
+ def SetParallelParsing(self, type):
+ type = type.lower()
+ if type == "on":
+ self.doParallelParsing = True
+ elif type == "off":
+ self.doParallelParsing = False
+ else:
+ self.Warn(" parallel parsing option must be either 'on' or 'off' (was %s)" % type)
+ return False
+
+ return True
+
+ def AddProject(self, projectName):
+ self.projects.add(projectName.lower())
+ return True
+
+ def FilterList(self, value):
+ self.filterList = value
+ return True
+
+ def IgnoreOsDetection(self, value):
+ self.ignoreOsDetection = value
+ return True
+
+ def PrintVersion(self,dummy):
+ global name
+ print name, "version", raptor_version.Version()
+ self.mission = Raptor.M_VERSION
+ return False
+
+ # worker methods
+
+ def Introduction(self):
+ """Print a header of useful information about Raptor"""
+
+ self.Info("%s: version %s\n", name, raptor_version.Version())
+
+ self.Info("%s %s", env, str(self.home))
+ self.Info("Set-up %s", str(self.raptorXML))
+ self.Info("Command-line-arguments %s", " ".join(self.args))
+ self.Info("Current working directory %s", os.getcwd())
+
+ # the inherited environment
+ for e, value in os.environ.items():
+ self.Info("Environment %s=%s", e, value)
+
+ # and some general debug stuff
+ self.Debug("Platform %s", "-".join(hostplatform))
+ self.Debug("Filesystem %s", self.filesystem)
+ self.Debug("Python %d.%d.%d", *sys.version_info[:3])
+ self.Debug("Command-line-parser %s", self.CLI)
+
+ for e,value in self.override.items():
+ self.Debug("Override %s = %s", e, value)
+
+ for t in self.targets:
+ self.Debug("Target %s", t)
+
+
+ def ConfigFile(self):
+ if not self.raptorXML.isFile():
+ return
+
+ self.cache.Load(self.raptorXML)
+
+ # find the 'defaults.raptor' variant and extract the values
+ try:
+ var = self.cache.FindNamedVariant("defaults.init")
+ evaluator = self.GetEvaluator( None, raptor_data.BuildUnit(var.name,[var]) )
+
+ for key, value in defaults.items():
+ newValue = evaluator.Resolve(key)
+
+ if newValue != None:
+ # got a string for the value
+ if type(value) == types.BooleanType:
+ newValue = (newValue.lower() != "false")
+ elif type(value) == types.IntType:
+ newValue = int(newValue)
+ elif isinstance(value, generic_path.Path):
+ newValue = generic_path.Path(newValue)
+
+ self.__dict__[key] = newValue
+
+ except KeyError:
+ # it is OK to not have this but useful to say it wasn't there
+ self.Info("No 'defaults.init' configuration found in " + str(self.raptorXML))
+
+
+ def CommandLine(self, args):
+ # remember the arguments for the log
+ self.args = args
+
+ # assuming self.CLI = "raptor_cli"
+ more_to_do = raptor_cli.GetArgs(self, args)
+
+ # resolve inter-argument dependencies.
+ # --what or --check implies the WHAT target and FilterWhat Filter
+ if self.doWhat or self.doCheck:
+ self.targets = ["WHAT"]
+ self.filterList = "filterwhat"
+
+ else:
+ # 1. CLEAN/CLEANEXPORT/REALLYCLEAN needs the FilterClean filter.
+ # 2. Targets that clean should not be combined with other targets.
+
+ targets = [x.lower() for x in self.targets]
+
+ CL = "clean"
+ CE = "cleanexport"
+ RC = "reallyclean"
+
+ is_clean = 0
+ is_suspicious_clean = 0
+
+ if CL in targets and CE in targets:
+ is_clean = 1
+ if len(targets) > 2:
+ is_suspicious_clean = 1
+ elif RC in targets or CL in targets or CE in targets:
+ is_clean = 1
+ if len(targets) > 1:
+ is_suspicious_clean = 1
+
+ if is_clean:
+ self.filterList += ",filterclean"
+ if is_suspicious_clean:
+ self.Warn('CLEAN, CLEANEXPORT and a REALLYCLEAN should not be combined with other targets as the result is unpredictable.')
+
+ if not more_to_do:
+ self.skipAll = True # nothing else to do
+
+ def ProcessConfig(self):
+ # this function will perform additional processing of config
+
+ # create list of generic paths
+ self.configPath = generic_path.NormalisePathList(self.systemConfig.split(os.pathsep))
+
+ def LoadCache(self):
+ def mkAbsolute(aGenericPath):
+ """ internal function to make a generic_path.Path
+ absolute if required"""
+ if not aGenericPath.isAbsolute():
+ return self.home.Append(aGenericPath)
+ else:
+ return aGenericPath
+
+ # make generic paths absolute (if required)
+ self.configPath = map(mkAbsolute, self.configPath)
+ self.cache.Load(self.configPath)
+
+ if not self.systemFLM.isAbsolute():
+ self.systemFLM = self.home.Append(self.systemFLM)
+
+ self.cache.Load(self.systemFLM)
+
+ def GetConfig(self, configname):
+ names = configname.split(".")
+
+ cache = self.cache
+
+ base = names[0]
+ mods = names[1:]
+
+ if base in cache.groups:
+ x = cache.FindNamedGroup(base)
+ elif base in cache.aliases:
+ x = cache.FindNamedAlias(base)
+ elif base in cache.variants:
+ x = cache.FindNamedVariant(base)
+ else:
+ raise Exception("Unknown build configuration '%s'" % configname)
+
+ x.ClearModifiers()
+
+
+ try:
+ for m in mods: x.AddModifier( cache.FindNamedVariant(m) )
+ except KeyError:
+ raise Exception("Unknown build configuration '%s'" % configname)
+ return x
+
+ def GetBuildUnitsToBuild(self, configNames):
+ """Return a list of the configuration objects that correspond to the
+ list of configuration names in the configNames parameter.
+
+ raptor.GetBuildUnitsToBuild(["armv5", "winscw"])
+ >>> [ config1, config2, ... , configN ]
+ """
+
+ if len(configNames) == 0:
+ # use default config
+ if len(self.defaultConfig) == 0:
+ self.Warn("No default configuration name")
+ else:
+ configNames.append(self.defaultConfig)
+
+ buildUnitsToBuild = set()
+
+
+ for c in set(configNames):
+ try:
+ x = self.GetConfig(c)
+ buildUnitsToBuild.update( x.GenerateBuildUnits() )
+ except Exception, e:
+ self.FatalError(str(e))
+
+ for b in buildUnitsToBuild:
+ self.Info("Buildable configuration '%s'", b.name)
+
+ if len(buildUnitsToBuild) == 0:
+ self.Error("No build configurations given")
+
+ return buildUnitsToBuild
+
+ def CheckToolset(self, evaluator, configname):
+ """Check the toolset for a particular config, allow other objects access
+ to the toolset for this build (e.g. the raptor_make class)."""
+ if self.toolset is None:
+ if self.toolcheck == 'on':
+ self.toolset = raptor_data.ToolSet(log=self)
+ elif self.toolcheck == 'forced' :
+ self.toolset = raptor_data.ToolSet(log=self, forced=True)
+ else:
+ return True
+
+ return self.toolset.check(evaluator, configname)
+
+
+ def CheckConfigs(self, configs):
+ """ Tool checking for all the buildable configurations
+ NB. We are allowed to use different tool versions for different
+ configurations."""
+
+ tools_ok = True
+ for b in configs:
+ self.Debug("Tool check for %s", b.name)
+ evaluator = self.GetEvaluator(None, b, gathertools=True)
+ tools_ok = tools_ok and self.CheckToolset(evaluator, b.name)
+
+ return tools_ok
+
+
+
+ def GatherSysModelLayers(self, systemModel, systemDefinitionRequestedLayers):
+ """Return a list of lists of components to be built.
+
+ components = GatherSysModelLayers(self, configurations)
+ >>> set("abc/group/bld.inf","def/group/bld.inf, ....")
+ """
+ layersToBuild = []
+
+ if systemModel:
+ # We either process all available layers in the system model, or a subset of
+ # layers specified on the command line. In both cases, the processing is the same,
+ # and can be subject to ordering if explicitly requested.
+ systemModel.DumpInfo()
+
+ if systemDefinitionRequestedLayers:
+ layersToProcess = systemDefinitionRequestedLayers
+ else:
+ layersToProcess = systemModel.GetLayerNames()
+
+ for layer in layersToProcess:
+ systemModel.DumpLayerInfo(layer)
+
+ if systemModel.IsLayerBuildable(layer):
+ layersToBuild.append(ComponentGroup(layer,
+ systemModel.GetLayerComponents(layer)))
+
+ return layersToBuild
+
+
+ # Add bld.inf or system definition xml to command line componentGroups (depending on preference)
+ def FindSysDefIn(self, aDir = None):
+ # Find a system definition file
+
+ if aDir is None:
+ dir = generic_path.CurrentDir()
+ else:
+ dir = generic_path.Path(aDir)
+
+ sysDef = dir.Append(self.systemDefinition)
+ if not sysDef.isFile():
+ return None
+
+ return sysDef
+
+
+ def FindComponentIn(self, aDir = None):
+ # look for a bld.inf
+
+ if aDir is None:
+ dir = generic_path.CurrentDir()
+ else:
+ dir = generic_path.Path(aDir)
+
+ bldInf = dir.Append(self.buildInformation)
+ componentgroup = []
+
+ if bldInf.isFile():
+ return bldInf
+
+ return None
+
+ def AttachSpecs(self, groups):
+ # tell the specs which Raptor object they work for (so that they can
+ # access the cache and issue warnings and errors)
+ for spec in groups:
+ spec.SetOwner(self)
+ self.Info("Buildable specification '%s'", spec.name)
+ if self.debugOutput:
+ spec.DebugPrint()
+
+ def GenerateGenericSpecs(self, configsToBuild):
+ # if a Configuration has any config-wide interfaces
+ # then add a Specification node to call each of them.
+ configWide = {}
+ genericSpecs = []
+ for c in configsToBuild:
+ evaluator = self.GetEvaluator(None, c)
+ iface = evaluator.Get("INTERFACE.config")
+ if iface:
+ if iface in configWide:
+ # seen it already, so reuse the node
+ filter = configWide[iface]
+ filter.AddConfigCondition(c.name)
+ else:
+ # create a new node
+ filter = raptor_data.Filter("config_wide")
+ filter.AddConfigCondition(c.name)
+ for i in iface.split():
+ spec = raptor_data.Specification(i)
+ spec.SetInterface(i)
+ filter.AddChildSpecification(spec)
+ # remember it, use it
+ configWide[iface] = filter
+ genericSpecs.append(filter)
+
+ self.AttachSpecs(genericSpecs)
+
+ return genericSpecs
+
+
+ def WriteMetadataDepsMakefile(self, component_group):
+ """ Takes a list of (filename, target) tuples that indicate where """
+ # Create a Makefile that includes all the dependency information for this spec group
+ build_metamakefile_name = \
+ os.path.abspath(sbs_build_dir).replace('\\','/').rstrip('/') + \
+ '/metadata_%s.mk' % component_group.name.lower()
+ bmkmf = open(build_metamakefile_name, "w+")
+ bmkmf.write("# Build Metamakefile - Dependencies for metadata during the 'previous' build\n\n")
+ bmkmf.write("PARSETARGET:=%s\n" % build_metamakefile_name)
+ bmkmf.write("%s: \n" % build_metamakefile_name)
+ bmkmf.write("\t@echo -e \"\\nRE-RUNNING SBS with previous parameters\"\n")
+ bmkmf.write("\t@echo pretend-sbs %s\n" % " ".join(self.args))
+ try:
+ for m in component_group.dependencies:
+ filename, target = m
+ bmkmf.write("-include %s\n\n" % filename)
+ finally:
+ bmkmf.close()
+
+ return build_metamakefile_name
+
+
+ def GetEvaluator(self, specification, configuration, gathertools=False):
+ """ this will perform some caching later """
+ return raptor_data.Evaluator(self, specification, configuration, gathertools=gathertools)
+
+
+ def areMakefilesUptodate(self):
+ return False
+
+
+ def Make(self, makefile):
+
+ if self.maker.Make(makefile):
+ self.Info("The make-engine exited successfully.")
+ return True
+ else:
+ self.Error("The make-engine exited with errors.")
+ return False
+
+
+ def Report(self):
+ if self.quiet:
+ return
+
+ self.endtime = time.time()
+ self.runtime = int(0.5 + self.endtime - self.starttime)
+ self.raptor_params.runtime = self.runtime
+ self.Info("Run time %s seconds" % self.runtime)
+
+ def AssertBuildOK(self):
+ """Raise a BuildCompleteException if no further processing is required
+ """
+ if self.Skip():
+ raise BuildCompleteException("")
+
+ return True
+
+ def Skip(self):
+ """Indicate not to perform operation if:
+ fatalErrorState is set
+ an error code is set but we're not in keepgoing mode
+ """
+ return self.fatalErrorState or ((self.errorCode != 0) and (not self.keepGoing))
+
+
+ # log file open/close
+
+ def OpenLog(self):
+ """Open a log file for the various I/O methods to write to."""
+
+ try:
+ # Find all the raptor plugins and put them into a pluginbox.
+ if not self.systemPlugins.isAbsolute():
+ self.systemPlugins = self.home.Append(self.systemPlugins)
+
+ self.pbox = pluginbox.PluginBox(str(self.systemPlugins))
+
+ self.raptor_params = BuildStats(self)
+
+ # Open the requested plugins using the pluginbox
+ self.out.open(self.raptor_params, self.filterList.split(','), self.pbox)
+
+ # log header
+ self.out.write("\n")
+
+ namespace = "http://symbian.com/xml/build/log"
+ schema = "http://symbian.com/xml/build/log/1_0.xsd"
+
+ self.out.write("\n"
+ % (raptor_version.Version(), namespace, namespace, schema))
+ self.logOpen = True
+ except Exception,e:
+ self.out = sys.stdout # make sure that we can actually get errors out.
+ self.logOpen = False
+ self.FatalError("Unable to open the output logs: %s" % str(e))
+
+
+ def CloseLog(self):
+ if self.logOpen:
+ self.out.summary()
+ self.out.write("\n")
+
+ if not self.out.close():
+ self.errorCode = 1
+
+
+ def Cleanup(self):
+ # ensure that the toolset cache is flushed.
+ if self.toolset is not None:
+ self.toolset.write()
+
+ # I/O methods
+
+ @staticmethod
+ def attributeString(dictionary):
+ "turn a dictionary into a string of XML attributes"
+ atts = ""
+ for a,v in dictionary.items():
+ atts += " " + a + "='" + v + "'"
+ return atts
+
+ def Info(self, format, *extras, **attributes):
+ """Send an information message to the configured channel
+ (XML control characters will be escaped)
+ """
+ self.out.write("" +
+ escape(format % extras) + "\n")
+
+ def Debug(self, format, *extras, **attributes):
+ "Send a debugging message to the configured channel"
+
+ # the debug text is out of our control so wrap it in a CDATA
+ # in case it contains characters special to XML... like <>
+ if self.debugOutput:
+ self.out.write("" +
+ ">\n")
+
+ def Warn(self, format, *extras, **attributes):
+ """Send a warning message to the configured channel
+ (XML control characters will be escaped)
+ """
+ self.out.write("" +
+ escape(format % extras) + "\n")
+
+ def FatalError(self, format, *extras, **attributes):
+ """Send an error message to the configured channel. This implies such a serious
+ error that the entire build must be shut down asap whilst still finishing off
+ correctly whatever housekeeping is possible e.g. producing error reports.
+ Remains quiet if the raptor object is already in a fatal state since there
+ further errors are probably triggered by the first.
+ """
+ if not self.fatalErrorState:
+ self.out.write("" +
+ (format % extras) + "\n")
+ self.errorCode = 1
+ self.fatalErrorState = True
+
+ def Error(self, format, *extras, **attributes):
+ """Send an error message to the configured channel
+ (XML control characters will be escaped)
+ """
+ self.out.write("" +
+ escape(format % extras) + "\n")
+ self.errorCode = 1
+
+
+ def PrintXML(self, format, *extras):
+ "Print to configured channel (no newline is added) (assumes valid xml)"
+ if format:
+ self.out.write(format % extras)
+
+
+ def MakeComponentGroup(self, cg):
+ if not self.maker:
+ self.maker = raptor_make.MakeEngine(self)
+
+ if self.maker == None:
+ self.Error("No make engine present")
+ return None
+
+ makefile = cg.CreateMakefile(self.topMakefile, self.maker, self.systemDefinitionOrderLayers)
+ if (not self.noBuild and makefile is not None) \
+ or self.doParallelParsing:
+ # run the build for a single group of specs
+ self.Make(makefile)
+ else:
+ self.Info("No build performed for %s" % cg.name)
+
+ def GetComponentGroupsFromCLI(self):
+ """Returns the list of componentGroups as specified by the
+ commandline interface to Raptor e.g. parameters
+ or the current directory"""
+ componentGroups=[]
+ # Look for bld.infs or sysdefs in the current dir if none were specified
+ if self.systemDefinitionFile == None and len(self.commandlineComponents) == 0:
+ if not self.preferBuildInfoToSystemDefinition:
+ cwd = os.getcwd()
+ self.systemDefinitionFile = self.FindSysDefIn(cwd)
+ if self.systemDefinitionFile == None:
+ aComponent = self.FindComponentIn(cwd)
+ if aComponent:
+ componentGroups.append(ComponentGroup('default',[aComponent]))
+ else:
+ aComponent = self.FindComponentIn(cwd)
+ if aComponent is None:
+ self.systemDefinitionFile = self.FindSysDefIn(cwd)
+ else:
+ componentGroups.append(ComponentGroup('default',[aComponent]))
+
+ if len(componentGroups) <= 0 and self.systemDefinitionFile == None:
+ self.Warn("No default bld.inf or system definition file found in current directory (%s)", cwd)
+
+ # If we now have a System Definition to parse then get the layers of components
+ if self.systemDefinitionFile != None:
+ systemModel = raptor_xml.SystemModel(self, self.systemDefinitionFile, self.systemDefinitionBase)
+ componentGroups = self.GatherSysModelLayers(systemModel, self.systemDefinitionRequestedLayers)
+
+ # Now get components specified on a commandline - build them after any
+ # layers in the system definition.
+ if len(self.commandlineComponents) > 0:
+ componentGroups.append(ComponentGroup('commandline',self.commandlineComponents))
+
+ # If we aren't building components in order then flatten down
+ # the groups
+ if not self.systemDefinitionOrderLayers:
+ # Flatten the layers into one group of components if
+ # we are not required to build them in order.
+ newcg = ComponentGroup("all")
+ for cg in componentGroups:
+ newcg.extend(cg)
+ componentGroups = [newcg]
+
+ return componentGroups
+
+ def Build(self):
+
+ if self.mission != Raptor.M_BUILD: # help or version requested instead.
+ return 0
+
+ # open the log file
+ self.OpenLog()
+
+
+ try:
+ # show the command and platform info
+ self.AssertBuildOK()
+ self.Introduction()
+ # establish an object cache
+ self.AssertBuildOK()
+
+ self.LoadCache()
+
+ # find out what configurations to build
+ self.AssertBuildOK()
+ buildUnitsToBuild = set()
+ buildUnitsToBuild = self.GetBuildUnitsToBuild(self.configNames)
+
+ # find out what components to build, and in what way
+ componentGroups = []
+
+ self.AssertBuildOK()
+ if len(buildUnitsToBuild) >= 0:
+ componentGroups = self.GetComponentGroupsFromCLI()
+
+ componentCount = reduce(lambda x,y : x + y, [len(cg) for cg in componentGroups])
+
+ if not componentCount > 0:
+ raise BuildCompleteException("No components to build.")
+
+ # check the configurations (tools versions)
+ self.AssertBuildOK()
+
+ if self.toolcheck != 'off':
+ self.CheckConfigs(buildUnitsToBuild)
+ else:
+ self.Info(" Not Checking Tool Versions")
+
+ self.AssertBuildOK()
+
+
+ # if self.doParallelParsing and not (len(componentGroups) == 1 and len(componentGroups[0]) == 1):
+ if self.doParallelParsing:
+ # Create a Makefile to parse components in parallel and build them
+ for cg in componentGroups:
+ cg.GenerateMetadataSpecs(buildUnitsToBuild)
+ self.MakeComponentGroup(cg)
+ if self.noBuild:
+ self.Info("No build performed")
+ else:
+ # Parse components serially, creating one set of makefiles
+ # create non-component specs
+ self.AssertBuildOK()
+ generic_specs = self.GenerateGenericSpecs(buildUnitsToBuild)
+
+ self.AssertBuildOK()
+ for cg in componentGroups:
+ # create specs for a specific group of components
+ cg.GenerateSpecs(generic_specs, buildUnitsToBuild)
+ self.WriteMetadataDepsMakefile(cg)
+
+ # generate the makefiles for one group of specs
+ self.MakeComponentGroup(cg)
+
+ except BuildCompleteException,b:
+ if str(b) != "":
+ self.Info(str(b))
+
+ # final report
+ if not self.fatalErrorState:
+ self.Report()
+
+ self.Cleanup()
+
+ # close the log file
+ self.CloseLog()
+
+ return self.errorCode
+
+ @classmethod
+ def CreateCommandlineBuild(cls, argv):
+ """ Perform a 'typical' build. """
+ # configure the framework
+
+ build = Raptor()
+ build.AssertBuildOK()
+ build.ConfigFile()
+ build.ProcessConfig()
+ build.CommandLine(argv)
+
+ return build
+
+
+
+# Class for passing constricted parameters to filters
+class BuildStats(object):
+
+ def __init__(self, raptor_instance):
+ self.logFileName = raptor_instance.logFileName
+ self.quiet = raptor_instance.quiet
+ self.doCheck = raptor_instance.doCheck
+ self.doWhat = raptor_instance.doWhat
+ self.platform = hostplatform
+ self.skipAll = raptor_instance.fatalErrorState
+ self.timestring = raptor_instance.timestring
+ self.targets = raptor_instance.targets
+ self.runtime = 0
+ self.name = name
+
+
+# raptor module functions
+
+def Main(argv):
+ """The main entry point for Raptor.
+
+ argv is a list of command-line parameters,
+ NOT including the name of the calling script.
+
+ The return value is zero for success and non-zero for failure."""
+
+ DisplayBanner()
+
+ # object which represents a build
+ b = Raptor.CreateCommandlineBuild(argv)
+
+ # allow all objects to log to the
+ # build they're being used in
+ global build
+ global log
+ build = b
+ log = b
+
+
+ result = b.Build()
+
+ return result
+
+
+def DisplayBanner():
+ """Stuff that needs printing out for every command."""
+ pass
+
+
+
+# end of the raptor module