#
# 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("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n")
namespace = "http://symbian.com/xml/build/log"
schema = "http://symbian.com/xml/build/log/1_0.xsd"
self.out.write("<buildlog sbs_version=\"%s\" xmlns=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"%s %s\">\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("</buildlog>\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("<info" + self.attributeString(attributes) + ">" +
escape(format % extras) + "</info>\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("<debug" + self.attributeString(attributes) + ">" +
"><![CDATA[\n" + (format % extras) + "\n]]></debug>\n")
def Warn(self, format, *extras, **attributes):
"""Send a warning message to the configured channel
(XML control characters will be escaped)
"""
self.out.write("<warning" + self.attributeString(attributes) + ">" +
escape(format % extras) + "</warning>\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("<error" + self.attributeString(attributes) + ">" +
(format % extras) + "</error>\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("<error" + self.attributeString(attributes) + ">" +
escape(format % extras) + "</error>\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