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