raptor.py 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742
  1. #
  2. # Copyright (c) 2006-2011 Nokia Corporation and/or its subsidiary(-ies).
  3. # All rights reserved.
  4. # This component and the accompanying materials are made available
  5. # under the terms of the License "Eclipse Public License v1.0"
  6. # which accompanies this distribution, and is available
  7. # at the URL "http://www.eclipse.org/legal/epl-v10.html".
  8. #
  9. # Initial Contributors:
  10. # Nokia Corporation - initial contribution.
  11. #
  12. # Contributors:
  13. #
  14. # Description:
  15. # raptor module
  16. # This module represents the running Raptor program. Raptor is started
  17. # either by calling the Main() function, which creates an instance of
  18. # the raptor.Raptor class and calls its methods to perform a build based
  19. # on command-line parameters, or by explicitly creating a raptor.Raptor
  20. # instance and calling its methods to set-up and perform a build.
  21. #
  22. name = "sbs" # the public name for the raptor build tool
  23. env = "SBS_HOME" # the environment variable that locates us
  24. xml = "sbs_init.xml" # the primary initialisation file
  25. env2 = "HOME" # the environment variable that locates the user
  26. xml2 = ".sbs_init.xml" # the override initialisation file
  27. import generic_path
  28. import os
  29. import stat
  30. import raptor_cache
  31. import raptor_cli
  32. import raptor_data
  33. import raptor_make
  34. import raptor_makefile
  35. import raptor_meta
  36. import raptor_timing
  37. import raptor_utilities
  38. import raptor_version
  39. import raptor_xml
  40. import filter_list
  41. import subprocess
  42. import sys
  43. import types
  44. import time
  45. import traceback
  46. import pluginbox
  47. from xml.sax.saxutils import escape
  48. from buildrecord import BuildRecord
  49. import json
  50. if not "HOSTPLATFORM" in os.environ or not "HOSTPLATFORM_DIR" in os.environ or not "HOSTPLATFORM32_DIR" in os.environ:
  51. print "Error: HOSTPLATFORM, HOSTPLATFORM_DIR and HOSTPLATFORM32_DIR must be set in the environment (this is usually done automatically by the startup script)."
  52. sys.exit(1)
  53. hostplatform = set(os.environ["HOSTPLATFORM"].split(" "))
  54. unixplatforms = set(['linux','freebsd','darwin','sunos'])
  55. isunix = not hostplatform.isdisjoint(unixplatforms)
  56. hostplatform_dir = os.environ["HOSTPLATFORM_DIR"]
  57. hostplatform32_dir = os.environ["HOSTPLATFORM32_DIR"]
  58. # defaults can use EPOCROOT
  59. if "EPOCROOT" in os.environ:
  60. incoming_epocroot = os.environ["EPOCROOT"]
  61. epocroot = incoming_epocroot.replace("\\","/")
  62. else:
  63. if 'win' in hostplatform:
  64. incoming_epocroot = os.sep
  65. epocroot = "/"
  66. os.environ["EPOCROOT"] = os.sep
  67. else:
  68. epocroot=os.environ['HOME'] + os.sep + "epocroot"
  69. os.environ["EPOCROOT"] = epocroot
  70. incoming_epocroot = epocroot
  71. if "SBS_BUILD_DIR" in os.environ:
  72. sbs_build_dir = os.environ["SBS_BUILD_DIR"]
  73. else:
  74. sbs_build_dir = (epocroot + "/epoc32/build").replace("//","/")
  75. # only use default XML from the epoc32 tree if it exists
  76. defaultSystemConfig = "lib/config"
  77. epoc32UserConfigDir = generic_path.Join(epocroot, "epoc32/sbs_config")
  78. if epoc32UserConfigDir.isDir():
  79. defaultSystemConfig = str(epoc32UserConfigDir) + os.pathsep + defaultSystemConfig
  80. # parameters that can be overriden by the sbs_init.xml file
  81. # or by the command-line.
  82. defaults = {
  83. "allowCommandLineOverrides" : True,
  84. "CLI" : "raptor_cli",
  85. "buildInformation" : generic_path.Path("bld.inf"),
  86. "defaultConfig" : "default",
  87. "jobs": 4,
  88. "keepGoing": False,
  89. "logFileName" : generic_path.Join(sbs_build_dir,"Makefile.%TIME.log"),
  90. "makeEngine" : "make",
  91. "preferBuildInfoToSystemDefinition" : False,
  92. "pruneDuplicateMakefiles": True,
  93. "quiet" : False,
  94. "systemConfig" : defaultSystemConfig,
  95. "systemDefinition" : generic_path.Path("System_Definition.xml"),
  96. "systemDefinitionBase" : generic_path.Path("."),
  97. "systemFLM" : generic_path.Path("lib/flm"),
  98. "systemPlugins" : generic_path.Path("python/plugins"),
  99. "topMakefile" : generic_path.Join(sbs_build_dir,"Makefile.%TIME"),
  100. "tries": 1,
  101. "writeSingleMakefile": True,
  102. "ignoreOsDetection": False,
  103. "toolcheck": "on",
  104. "incremental_parsing": False,
  105. "ignore_zero_flmcall_makefiles": False,
  106. "filterList": "filterterminal,filterlogfile"
  107. }
  108. class ModelNode(object):
  109. """ Represents any node in a a tree of build information
  110. e.g. a tree of bld.infs, mmps and finally things like resource blocks and string table blocks.
  111. This is before they are produced into "build" specs.
  112. """
  113. def __init__(self, id, parent = None):
  114. self.id = id
  115. self.type = type
  116. self.specs = []
  117. self.deps = [] # files that this node depends on
  118. self.depfiles = [] # files with dependencies listed in them in GNU make format
  119. self.children = set()
  120. self.unfurled = False
  121. self.parent = parent
  122. # Allow one to make a set
  123. def __hash__(self):
  124. return hash(self.id)
  125. def __cmp__(self,other):
  126. return cmp(self.id, other)
  127. def __iter__(self):
  128. return iter(self.children)
  129. def __getitem__(self,x):
  130. if isinstance(x, slice):
  131. return self.children[x.start:x.stop]
  132. return self.children[x]
  133. def __setitem__(self,k, v):
  134. self.children[k] = v
  135. def __len__(self):
  136. return len(self.children)
  137. def add(self, item):
  138. return self.children.add(item)
  139. def isunfurled(self, c):
  140. return self.unfurled == False
  141. def unique_filename(self):
  142. """ returns a string that is short enough to add to a filename that is believed to be unique
  143. within a single build. This really should be overridden by children """
  144. # not a great default but we're not supposed to know what self.id contains so we can't e.g. process it like a filename
  145. return raptor_utilities.sanitise(hash(id))
  146. def alldeps(self):
  147. """ All the known simple dependencies of the object represented by this Node.
  148. This doesn't include dependencies that are generated by tools like CPP - alldepfiles() does that"""
  149. for d in self.deps:
  150. yield d
  151. for c in self.children:
  152. for d in c.alldeps():
  153. yield d
  154. def alldepfiles(self):
  155. """Dependencies are sometimes discovered by tools like CPP and then stored in files"""
  156. for d in self.depfiles:
  157. yield d
  158. for c in self.children:
  159. for d in c.alldepfiles():
  160. yield d
  161. def unfurl(self, build):
  162. """Find any children of this node by processing it, produces specs"""
  163. pass
  164. def unfurl_all(self, build):
  165. """Unfurl self and all children - preparatory e.g for realisation"""
  166. if not self.unfurled:
  167. self.unfurl(build)
  168. self.realise_exports(build) # permit communication of dependencies between children
  169. for c in self.children:
  170. c.unfurl_all(build)
  171. def realise_exports(self, build):
  172. """Do the things that are needed such that we can fully unfurl all
  173. sibling nodes. i.e. this step is here to "take care" of the dependencies
  174. between siblings.
  175. """
  176. pass
  177. def makefile_name(self, build):
  178. """use data from the build object to determine the makefilename for this node"""
  179. postfix = "_" + self.unique_filename()
  180. makefilename_base = build.topMakefile.Absolute()
  181. return str(makefilename_base) + postfix
  182. def realise_makefile(self, build, specs):
  183. makefile = self.makefile_name(build)
  184. metadepsfilename = makefile + ".metadeps"
  185. try:
  186. os.makedirs(str(generic_path.Path(makefile).Dir()))
  187. except OSError,e:
  188. pass # if the dir is already there
  189. build.Debug("Layer Deps: {0} with {1} children depfile {2}".format(self.id, len(self.children),metadepsfilename))
  190. build.InfoDiscovery(object_type = "layers", count = 1)
  191. build.InfoStartTime(object_type = "layer", task = "parse",
  192. key = makefile)
  193. makefileset = build.maker.Write(generic_path.Path(makefile), specs, build.buildUnitsToBuild)
  194. makefileset.write_metadeps(self.alldeps(), self.alldepfiles()) # ensure that this makefileset's dependency file has been written out
  195. build.InfoEndTime(object_type = "layer", task = "parse",
  196. key = makefile)
  197. # Tell the buildrecord about this set of makefiles
  198. build.build_record.record_makefileset(makefileset)
  199. return makefileset
  200. def realise(self, build):
  201. """Give the spec trees to the make engine and actually
  202. "build" the product represented by this model node"""
  203. # Must ensure that all children are unfurled at this point
  204. self.unfurl_all(build)
  205. sp = self.specs
  206. build.AssertBuildOK()
  207. makefileset = self.realise_makefile(build, sp)
  208. build.InfoStartTime(object_type = "layer", task = "build",
  209. key = (str(makefileset.directory) + "/" + str(makefileset.filenamebase)))
  210. result = build.Make(makefileset)
  211. build.InfoEndTime(object_type = "layer", task = "build",
  212. key = (str(makefileset.directory) + "/" + str(makefileset.filenamebase)))
  213. return result
  214. class Project(ModelNode):
  215. """A project or, in symbian-speak, an MMP
  216. """
  217. def __init__(self, filename, parent = None):
  218. super(Project,self).__init__(filename, parent = parent)
  219. # Assume that components are specified in mmp files for now
  220. # One day that tyranny might end.
  221. self.mmp_name = str(generic_path.Path.Absolute(filename))
  222. self.id = self.mmp_name
  223. self.unfurled = False
  224. self.deps.append(self.mmp_name)
  225. def makefile(self, makefilename_base, engine, named = False):
  226. """Makefiles for individual mmps not feasible at the moment"""
  227. pass
  228. # Cannot, currently, "unfurl an mmp" directly but do want
  229. # to be able to simulate the overall recursive unfurling of a build.
  230. class Component(ModelNode):
  231. """ An Abstract class for group of projects (where projects are
  232. usually things that represent one program or libary) """
  233. def __init__(self, filename, layername="", componentname=""):
  234. super(Component,self).__init__(filename)
  235. self.filename = filename
  236. self.id = str(filename)
  237. self.exportspecs = []
  238. self.depfiles = []
  239. self.unfurled = False # We can parse this
  240. self.deps.append(str(self.filename))
  241. # Extra metadata optionally supplied with system definition file gathered components
  242. self.layername = layername
  243. self.name = componentname
  244. def render_bldinf(self, build):
  245. raise Exception("Can't render a bld.inf from component {0} - don't know how".format(self.filename))
  246. class BldinfComponent(Component):
  247. """A group of projects or, in symbian-speak, a bld.inf.
  248. """
  249. def __init__(self, filename, layername="", componentname=""):
  250. super(BldinfComponent,self).__init__(filename, layername = layername, componentname=componentname)
  251. # Assume that components are specified in bld.inf files for now
  252. # One day that tyranny might end.
  253. self.bldinf = None # Slot for a bldinf object if we spot one later
  254. self.bldinf_filename = generic_path.Path(str(filename)).Absolute()
  255. def AddMMP(self, filename):
  256. self.children.add(Project(filename))
  257. def render_bldinf(self, build):
  258. return self
  259. class QmakeErrorException(Exception):
  260. def __init__(self, text, output = "", errorcode=1,command=""):
  261. self.output = output
  262. self.errorcode = errorcode
  263. self.command=command
  264. def __str__(self):
  265. return "{0} - while running: {1}".format(self.output,self.command)
  266. class QtProComponent(BldinfComponent):
  267. """ represents a component that is specified in a .pro file. The intention is that it should
  268. be possible to translate it into a bld.inf as we don't intend to parse Qt files directly which
  269. would be an immense and pointless effort."""
  270. def __init__(self, filename, layername="", componentname=""):
  271. self.qtpro_filename = generic_path.Path(filename).Absolute()
  272. super(QtProComponent,self).__init__(filename,layername=layername, componentname=componentname)
  273. # automatically determine the related bld.inf name by putting it in the same dir as the qt file.
  274. self.bldinf_filename = generic_path.Join(self.qtpro_filename.Dir(), "bld.inf")
  275. self.bldinf_produced = False
  276. def render_bldinf(self, build):
  277. self.bldinf_produced = True
  278. qmake = build.metaeval.Get("QMAKE")
  279. moc = build.metaeval.Get("MOC")
  280. uic = build.metaeval.Get("UIC")
  281. rcc = build.metaeval.Get("RCC")
  282. # run qmake and produce the bld.inf immediately.
  283. shell = "/bin/sh" # only needed on linux.
  284. # should really get qmake(.exe)'s absolute location from somewhere
  285. global epocroot
  286. spec = build.metaeval.Get("QMAKESPEC")
  287. incdir = build.metaeval.Get("QMAKE_INCDIR_QT")
  288. headers = build.metaeval.Get("QT_HEADERS")
  289. command = "{0} -spec {1} {2} -o {3} QMAKE_INCDIR_QT={4} QMAKE_MOC={5} QMAKE_UIC={6} QMAKE_RCC={7}".format(qmake, spec, self.qtpro_filename, self.bldinf_filename, headers, moc,uic,rcc)
  290. makeenv = os.environ.copy()
  291. build.Debug("qmake command: {0}".format(command))
  292. if isunix:
  293. p = subprocess.Popen(
  294. args = [shell, '-c', command],
  295. bufsize = 65535,
  296. stdout = subprocess.PIPE,
  297. stderr = subprocess.STDOUT,
  298. shell = False,
  299. universal_newlines = True,
  300. env = makeenv)
  301. else:
  302. p = subprocess.Popen(
  303. args = [command],
  304. bufsize = 65535,
  305. stdout = subprocess.PIPE,
  306. stderr = subprocess.STDOUT,
  307. shell = True,
  308. env = makeenv)
  309. stream = p.stdout
  310. self.qmake_output = []
  311. for l in stream:
  312. self.qmake_output.append(l)
  313. returncode = p.wait()
  314. if returncode != 0:
  315. e = QmakeErrorException("{0} failed for '{1}'".format(qmake, self.qtpro_filename), output = "\n".join(self.qmake_output), errorcode = returncode, command = command)
  316. raise e
  317. return self
  318. class Layer(ModelNode):
  319. """ Some components that should be built togther
  320. e.g. a Layer in the system definition.
  321. Components that come from system definition files can
  322. have extra surrounding metadata that we need to pass
  323. on for use in log output.
  324. """
  325. def __init__(self, name, componentlist=[]):
  326. """ componentlist may be a list of items of type Component xor type raptor_xml.SystemModelComponent
  327. @componentlist must be a list of objects that are derived from the Component class.
  328. """
  329. super(Layer,self).__init__(name)
  330. self.name = name
  331. for c in componentlist:
  332. # this is a component from the plain old command-line and we expect it to be of type "Component" already.
  333. self.children.add(c)
  334. def unique_filename(self):
  335. """ returns a string that is short enough to add to a filename that is believed to be unique
  336. within a single build. """
  337. # the layer name should be unique
  338. return raptor_utilities.sanitise(self.name)
  339. @classmethod
  340. def from_system_model(cls, name, sysmodel_componentlist):
  341. """ A factory method to build a layer from a raptor_xml.SystemModelComponent
  342. this eases the process of working with a "system_definition.xml" file. """
  343. l = cls(name) # Call our class' constructor
  344. for c in sysmodel_componentlist:
  345. l.children.add(BldinfComponent(c, c.GetLayerName(), c.GetContainerName("component")))
  346. return l
  347. def unfurl(self, build):
  348. """Discover the children of this layer. This involves parsing the component MetaData (bld.infs, mmps).
  349. Takes a raptor object as a parameter (build), together with a list of Configurations.
  350. We currently have parsers that work on collections of components/bld.infs and that cannot
  351. parse at a "finer" level. So one can't 'unfurl' an mmp at the moment.
  352. Returns True if the object was successfully unfurled.
  353. """
  354. # setup all our components
  355. for c in self.children:
  356. c.specs = []
  357. self.configs = build.buildUnitsToBuild
  358. # render the components down to bld.inf form (if possible)
  359. # since we don't understand any other component format
  360. components = []
  361. for c in self.children:
  362. try:
  363. components.append(c.render_bldinf(build))
  364. except QmakeErrorException, e:
  365. build.Error(str(e))
  366. if len(components) > 0:
  367. try:
  368. # create a MetaReader that is aware of the list of
  369. # configurations that we are trying to build.
  370. metaReader = raptor_meta.MetaReader(build, build.buildUnitsToBuild)
  371. # convert the list of bld.inf files into a specification
  372. # hierarchy suitable for all the configurations we are using.
  373. self.specs = list(build.generic_specs)
  374. self.specs.extend(metaReader.ReadBldInfFiles(components, doexport = build.doExport, dobuild = not build.doExportOnly))
  375. except raptor_meta.MetaDataError, e:
  376. build.Error(e.Text)
  377. self.unfurled = True
  378. def _split_into_blocks(self, build):
  379. """ Split layer's components into blocks for parallel parsing """
  380. nc = len(self.children)
  381. number_blocks = build.jobs
  382. block_size = (nc / number_blocks) + 1
  383. component_blocks = [] # list of mini-layers, split up for parallel parsing
  384. b = 0
  385. childlist = list(self.children)
  386. while b < nc:
  387. l = Layer(self.name, childlist[b:b+block_size])
  388. component_blocks.append(l)
  389. b += block_size
  390. while len(component_blocks[-1].children) <= 0:
  391. component_blocks.pop()
  392. number_blocks -= 1
  393. build.Info("Parallel Parsing: bld.infs split into {0} blocks\n".format(number_blocks))
  394. return component_blocks
  395. def meta_realise(self, build):
  396. """Generate specs that can be used to "take care of" finding out more
  397. about this metaunit - i.e. one doesn't want to parse it immediately
  398. but to create a makefile that will parse it.
  399. In this case it allows bld.infs to be parsed in parallel by make."""
  400. # insert the start time into the Makefile name?
  401. self.configs = build.buildUnitsToBuild
  402. # Pass certain CLI flags through to the makefile-generating sbs calls
  403. cli_options = ""
  404. if build.debugOutput == True:
  405. cli_options += " -d"
  406. if build.ignoreOsDetection == True:
  407. cli_options += " -i"
  408. if build.keepGoing == True:
  409. cli_options += " -k"
  410. if build.quiet == True:
  411. cli_options += " -q"
  412. if build.noDependInclude == True:
  413. cli_options += " --no-depend-include"
  414. if build.noDependGenerate == True:
  415. cli_options += " --no-depend-generate"
  416. tm = build.topMakefile.Absolute()
  417. # List of all confgurations apart from "build" which
  418. # is used internally for generating makefiles for
  419. # parallel parsing
  420. configList = " ".join([c.name for c in self.configs if c.name != "build" ])
  421. # Cause the binding makefiles to have the toplevel makefile's
  422. # name. The bindee's have __pp appended.
  423. binding_makefiles = raptor_makefile.MakefileSet(str(tm.Dir()), build.maker.selectors, makefiles=None, filenamebase=str(tm.File()))
  424. build.topMakefile = generic_path.Path(str(tm) + "_pp")
  425. component_blocks = self._split_into_blocks(build)
  426. spec_nodes = []
  427. loop_number = 0
  428. for block in component_blocks:
  429. loop_number += 1
  430. specNode = raptor_data.Specification("metadata_" + self.name)
  431. # root path for generated sysdef files and their partnering makefiles
  432. makefile_path = str(build.topMakefile) + "_" + str(loop_number)
  433. try:
  434. os.unlink(makefile_path)
  435. except Exception:
  436. pass
  437. pp_system_definition = makefile_path + ".sysdef.xml"
  438. try:
  439. sys_def_writer = raptor_xml.SystemModel(build, aDoRead=False)
  440. sys_def_writer.AddLayer(block)
  441. sys_def_writer.Write(pp_system_definition)
  442. build.Debug("Wrote intermediate parallel-parsing system definition file " + pp_system_definition)
  443. except Exception as e:
  444. build.Error("Failed to write intermediate parallel-parsing system definition file " + pp_system_definition)
  445. raise
  446. configList = " ".join([c.name for c in self.configs if c.name != "build" ])
  447. # add some basic data in a component-wide variant
  448. var = raptor_data.Variant()
  449. var.AddOperation(raptor_data.Set("PP_SYSTEM_DEFINITION", pp_system_definition))
  450. var.AddOperation(raptor_data.Set("MAKEFILE_PATH", makefile_path))
  451. var.AddOperation(raptor_data.Set("CONFIGS", configList))
  452. var.AddOperation(raptor_data.Set("CLI_OPTIONS", cli_options))
  453. # Allow the flm to skip exports. Note: this parameter
  454. doexport_str = '1'
  455. if not build.doExport:
  456. doexport_str = ''
  457. var.AddOperation(raptor_data.Set("DOEXPORT", doexport_str ))
  458. # Pass on '-n' (if specified) to the makefile-generating sbs calls
  459. if build.noBuild:
  460. var.AddOperation(raptor_data.Set("NO_BUILD", "1"))
  461. specNode.AddVariant(var)
  462. try:
  463. interface = build.cache.FindNamedInterface("build.makefiles")
  464. specNode.SetInterface(interface)
  465. except KeyError:
  466. build.Error("Can't find flm interface 'build.makefiles' ")
  467. spec_nodes.append(specNode)
  468. binding_makefiles.addInclude(str(makefile_path)+"_all")
  469. build.InfoDiscovery(object_type = "layers", count = 1)
  470. build.InfoStartTime(object_type = "layer", task = "parse",
  471. key = str(build.topMakefile))
  472. # Generate the makefileset and build it
  473. mset = self.realise_makefile(build, spec_nodes)
  474. mset.close()
  475. gen_result = build.Make(mset)
  476. build.InfoEndTime(object_type = "layer", task = "parse",
  477. key = str(build.topMakefile))
  478. build.InfoStartTime(object_type = "layer", task = "build",
  479. key = str(build.topMakefile))
  480. build.Debug("Binding Makefile base name is {0} ".format(binding_makefiles.filenamebase))
  481. binding_makefiles.close()
  482. b = build.Make(binding_makefiles)
  483. build.InfoEndTime(object_type = "layer", task = "build",
  484. key = str(build.topMakefile))
  485. return b
  486. class BuildCannotProgressException(Exception):
  487. pass
  488. # raptor module classes
  489. class Raptor(object):
  490. """An instance of a running Raptor program.
  491. When operated from the command-line there is a single Raptor object
  492. created by the Main function. When operated by an IDE several Raptor
  493. objects may be created and operated at the same time.
  494. """
  495. # mission enumeration
  496. M_BUILD = 1
  497. M_QUERY = 2
  498. M_VERSION = 3
  499. def __init__(self, home = None, commandline = [], dotargets = True, logger = None, load_defaults = True):
  500. """
  501. Keyword Arguments:
  502. home - where to load xml settings from (default None indicated the current working directory)
  503. commandline - potentially a commandline full of options to set (default empty list)
  504. targets - when processing a commandline this ensures
  505. that correct make targets are added e.g. "WHAT" if doing --what. (Default True)
  506. logger - a class that provides Debug, Info, Warning and Error
  507. functions ( default is an internal logger )"""
  508. self.args = commandline
  509. self.dotargets = dotargets
  510. self.logger = logger
  511. if self.logger is not None:
  512. # Patching functions out here rather than putting
  513. # an if statement in each function seems
  514. # a little more efficient although it may
  515. # be over optimisation.
  516. self.Info = self.logger.Info
  517. self.Debug = self.logger.Debug
  518. self.Warn = self.logger.Warn
  519. self.load_defaults = load_defaults
  520. self._default_setup(home)
  521. # Load up the all the other XML configuration data:
  522. self.configPath = generic_path.NormalisePathList(self.systemConfig.split(os.pathsep))
  523. # If there are any commandline arguments then apply them
  524. if len(commandline) > 0:
  525. # remember the arguments for the log
  526. self.args = commandline
  527. # assuming self.CLI = "raptor_cli"
  528. if not raptor_cli.GetArgs(self, self.args):
  529. # raise exception quietly since the error
  530. # messages are already printed out from GetArgs
  531. raise BuildCannotProgressException("")
  532. # With incremental parsing which is itself an experimental feature
  533. # it is relatively safe to switch on a feature that doesn't execute
  534. # Makefiles if they have no flm calls in them
  535. if self.incremental_parsing:
  536. self.ignore_zero_flmcall_makefiles = True
  537. # Validate our current state
  538. if self.incremental_parsing and self.doParallelParsing:
  539. raise BuildCannotProgressException("The parallel parsing (--pp=on) and incremental parsing (--ip=on) options cannot be used together at the moment")
  540. if (self.dotargets):
  541. self._check_and_set_build_targets()
  542. def _default_setup(self, home = None):
  543. """the default set-up state"""
  544. self.errorCode = 0
  545. self.skipAll = False
  546. self.summary = True
  547. self.out = sys.stdout # Just until filters get started.
  548. # Create a bootstrap output system.
  549. self.out = filter_list.FilterList()
  550. if home == None:
  551. try:
  552. home = os.environ[env]
  553. except KeyError:
  554. home = os.getcwd()
  555. # make sure the home directory exists
  556. self.home = generic_path.Path(home).Absolute()
  557. if not self.home.isDir():
  558. self.Error("{0} '{1}' is not a directory".format(env, self.home))
  559. raise BuildCannotProgressException("{0} '{1}' is not a directory".format(env, str(self.home)))
  560. # the set-up file location.
  561. # use the override "env2/xml2" if it exists
  562. # else use the primary "env/xml" if it exists
  563. # else keep the hard-coded defaults.
  564. self.raptorXML = self.home.Append(xml)
  565. if env2 in os.environ:
  566. sbs_init = generic_path.Join(os.environ[env2], xml2)
  567. if sbs_init.isFile():
  568. self.raptorXML = sbs_init
  569. # things that can be overridden by the set-up file
  570. for key, value in defaults.items():
  571. self.__dict__[key] = value
  572. # things to initialise
  573. self.args = []
  574. self.layers = []
  575. self.orderLayers = False
  576. self.commandline_layer = Layer('commandline')
  577. self.systemModel = None
  578. self.systemDefinitionFile = None
  579. self.systemDefinitionRequestedLayers = []
  580. self.systemDefinitionOrderLayers = False
  581. self.specGroups = {}
  582. self.configNames = []
  583. self.configsToBuild = set()
  584. self.makeOptions = []
  585. self.maker = None
  586. self.debugOutput = False
  587. self.doExportOnly = False
  588. self.doExport = True
  589. self.noBuild = False
  590. self.noDependInclude = False
  591. self.noDependGenerate = False
  592. self.projects = set()
  593. self.queries = []
  594. self.cache = raptor_cache.Cache(self)
  595. self.override = {env: str(self.home)}
  596. self.targets = []
  597. self.defaultTargets = []
  598. self.doCheck = False
  599. self.doWhat = False
  600. self.doParallelParsing = False
  601. self.doCaseFolding_rsg = False
  602. self.mission = Raptor.M_BUILD
  603. # what platform and filesystem are we running on?
  604. self.filesystem = raptor_utilities.getOSFileSystem()
  605. self.timing = True # Needed by filters such as copy_file to monitor progress
  606. self.toolset = None
  607. self.starttime = time.time()
  608. # Create a unique time id that combines millisecond part of start time
  609. # and id of the process which Raptor python is running on
  610. timeid = str(round(self.starttime, 3)).split('.')[1] + '-' + str(os.getpid())
  611. self.timestring = time.strftime("%Y-%m-%d-%H-%M-%S.") + timeid
  612. self.fatalErrorState = False
  613. if self.load_defaults:
  614. # Load up the raptor defaults from XML (formerly from the ConfigFile function)
  615. if self.raptorXML.isFile():
  616. self.cache.Load(self.raptorXML)
  617. # find the 'defaults.raptor' variant and extract the values
  618. try:
  619. var = self.cache.FindNamedVariant("defaults.init")
  620. evaluator = self.GetEvaluator( None, raptor_data.BuildUnit(var.name,[var]) )
  621. for key, value in defaults.items():
  622. newValue = evaluator.Resolve(key)
  623. if newValue != None:
  624. # got a string for the value
  625. if type(value) == types.BooleanType:
  626. newValue = (newValue.lower() != "false")
  627. elif type(value) == types.IntType:
  628. newValue = int(newValue)
  629. elif isinstance(value, generic_path.Path):
  630. newValue = generic_path.Path(newValue)
  631. self.__dict__[key] = newValue
  632. except KeyError:
  633. # it is OK to not have this but useful to say it wasn't there
  634. self.Info("No 'defaults.init' configuration found in " + str(self.raptorXML))
  635. def _load_cache(self):
  636. """Before initiating any action like a build or query, we should load up all
  637. xml configuration. This function is not intended for use except by other
  638. members of the Raptor class.
  639. """
  640. def mkAbsolute(aGenericPath):
  641. """ internal function to make a generic_path.Path
  642. absolute if required"""
  643. if not aGenericPath.isAbsolute():
  644. return self.home.Append(aGenericPath)
  645. else:
  646. return aGenericPath
  647. # make generic paths absolute (if required)
  648. self.configPath = map(mkAbsolute, self.configPath)
  649. self.cache.Load(self.configPath)
  650. if not self.systemFLM.isAbsolute():
  651. self.systemFLM = self.home.Append(self.systemFLM)
  652. self.cache.Load(self.systemFLM)
  653. # Make it possible to ask this instance about default tools locations without
  654. # doing the evaluator creation repeatedly for no reason
  655. self.metavariant = self.cache.FindNamedVariant("meta")
  656. self.metaeval = self.GetEvaluator(None, raptor_data.BuildUnit(self.metavariant.name, [self.metavariant]) )
  657. def AddConfigList(self, configPathList):
  658. # this function converts cmd line option into a list
  659. # and prepends it to default config.
  660. self.configPath = generic_path.NormalisePathList(configPathList.split(os.pathsep)) + self.configPath
  661. return True
  662. def AddConfigName(self, name):
  663. if name == "build":
  664. traceback.print_stack((sys.stdout))
  665. sys.exit(1)
  666. self.configNames.append(name)
  667. return True
  668. def RunQuietly(self, TrueOrFalse):
  669. self.quiet = TrueOrFalse
  670. return True
  671. def SetCheck(self, TrueOrFalse):
  672. self.doCheck = TrueOrFalse
  673. return True
  674. def SetWhat(self, TrueOrFalse):
  675. self.doWhat = TrueOrFalse
  676. return True
  677. def SetEnv(self, name, value):
  678. self.override[name] = value
  679. def AddTarget(self, target):
  680. if self.doCheck or self.doWhat:
  681. self.Warn("ignoring target {0} because --what or --check is specified.\n".format(target))
  682. else:
  683. self.targets.append(target)
  684. def AddSourceTarget(self, filename):
  685. # source targets are sanitised and then added as if they were a "normal" makefile target
  686. # in addition they have a default, empty, top-level target assigned in order that they can
  687. # be presented to any generated makefile without error
  688. sourceTarget = generic_path.Path(filename).Absolute()
  689. sourceTarget = 'SOURCETARGET_' + raptor_utilities.sanitise(str(sourceTarget))
  690. self.AddTarget(sourceTarget)
  691. self.defaultTargets.append(sourceTarget)
  692. return True
  693. def SetSysDefFile(self, filename):
  694. self.systemDefinitionFile = generic_path.Path(filename)
  695. return True
  696. def SetSysDefBase(self, path):
  697. self.systemDefinitionBase = generic_path.Path(path)
  698. return True
  699. def AddSysDefLayer(self, layer):
  700. self.systemDefinitionRequestedLayers.append(layer)
  701. return True
  702. def SetSysDefOrderLayers(self, TrueOrFalse):
  703. self.systemDefinitionOrderLayers = TrueOrFalse
  704. return True
  705. def AddBuildInfoFile(self, filename):
  706. bldinf = str(generic_path.Path(filename).Absolute())
  707. self.commandline_layer.add(BldinfComponent(bldinf))
  708. return True
  709. def AddQtProFile(self, filename):
  710. qt_pro_file = str(generic_path.Path(filename).Absolute())
  711. self.commandline_layer.add(QtProComponent(qt_pro_file))
  712. return True
  713. def SetTopMakefile(self, filename):
  714. self.topMakefile = generic_path.Path(filename)
  715. return True
  716. def SetDebugOutput(self, TrueOrFalse):
  717. self.debugOutput = TrueOrFalse
  718. return True
  719. def SetExportOnly(self, TrueOrFalse):
  720. self.doExportOnly = TrueOrFalse
  721. if not self.doExport:
  722. self.Error("The --noexport and --export-only options are incompatible - won't to do anything useful")
  723. return False
  724. return True
  725. def SetNoExport(self, TrueOrFalse):
  726. self.doExport = not TrueOrFalse
  727. if self.doExportOnly:
  728. self.Error("The --noexport and --export-only options are incompatible - won't to do anything useful")
  729. return False
  730. return True
  731. def SetNoBuild(self, TrueOrFalse):
  732. self.noBuild = TrueOrFalse
  733. return True
  734. def SetNoDependInclude(self, TrueOrFalse):
  735. self.noDependInclude = TrueOrFalse
  736. return True
  737. def SetNoDependGenerate(self, TrueOrFalse):
  738. self.noDependGenerate = TrueOrFalse
  739. return True
  740. def SetKeepGoing(self, TrueOrFalse):
  741. self.keepGoing = TrueOrFalse
  742. return True
  743. def SetLogFileName(self, logfile):
  744. if logfile == "-":
  745. self.logFileName = None # stdout
  746. else:
  747. self.logFileName = generic_path.Path(logfile)
  748. return True
  749. def SetMakeEngine(self, makeEngine):
  750. self.makeEngine = makeEngine
  751. return True
  752. def AddMakeOption(self, makeOption):
  753. self.makeOptions.append(makeOption)
  754. return True
  755. def SetJobs(self, numberOfJobs):
  756. try:
  757. self.jobs = int(numberOfJobs)
  758. except ValueError:
  759. self.jobs = 0
  760. if self.jobs < 1:
  761. self.Warn("The number of jobs ({0}) must be a positive integer\n".format(numberOfJobs))
  762. self.jobs = 1
  763. return False
  764. return True
  765. def SetTries(self, numberOfTries):
  766. try:
  767. self.tries = int(numberOfTries)
  768. except ValueError:
  769. self.tries = 0
  770. if self.tries < 1:
  771. self.Warn("The number of tries ({0}) must be a positive integer\n".format(numberOfTries))
  772. self.tries = 1
  773. return False
  774. return True
  775. def SetToolCheck(self, type):
  776. type = type.lower()
  777. toolcheck_types= [ "forced", "on", "off" ]
  778. if type in toolcheck_types:
  779. self.toolcheck=type
  780. else:
  781. self.Warn("toolcheck option must be one of: {0}".format(toolcheck_types))
  782. return False
  783. return True
  784. def SetTiming(self, TrueOrFalse):
  785. self.Info("--timing switch no longer has any effect - build timing is now permanently on")
  786. return True
  787. def SetParallelParsing(self, type):
  788. type = type.lower()
  789. if type == "on":
  790. self.doParallelParsing = True
  791. elif type == "slave":
  792. self.isParallelParsingSlave = True
  793. elif type == "off":
  794. self.doParallelParsing = False
  795. else:
  796. self.Warn(" parallel parsing option must be either 'on' or 'off' (was {0})".format(type))
  797. return False
  798. return True
  799. def SetRsgCaseFolding(self, TrueOrFalse):
  800. self.doCaseFolding_rsg = TrueOrFalse
  801. return True
  802. def SetIncrementalParsing(self, type):
  803. if type == "on":
  804. self.incremental_parsing = True
  805. elif type == "off":
  806. self.incremental_parsing = False
  807. else:
  808. self.Warn(" incremental parsing option must be either 'on' or 'off' (was {0})".format(type))
  809. return False
  810. return True
  811. def AddProject(self, projectName):
  812. self.projects.add(projectName.lower())
  813. return True
  814. def AddQuery(self, q):
  815. self.queries.append(q)
  816. self.mission = Raptor.M_QUERY
  817. return True
  818. def FilterList(self, value):
  819. self.filterList = value
  820. return True
  821. def IgnoreOsDetection(self, value):
  822. self.ignoreOsDetection = value
  823. return True
  824. def PrintVersion(self,dummy):
  825. global name
  826. print name, "version", raptor_version.fullversion()
  827. self.mission = Raptor.M_VERSION
  828. return True
  829. # worker methods
  830. def Introduction(self):
  831. """Print a header of useful information about Raptor"""
  832. self.Info("{0}: version {1}".format(name, raptor_version.fullversion()))
  833. self.Info("{0} {1}".format(env, str(self.home)))
  834. self.Info("Set-up {0}".format(str(self.raptorXML)))
  835. self.Info("Command-line-arguments {0}".format(" ".join(self.args)))
  836. self.Info("Current working directory {0}".format(os.getcwd()))
  837. # the inherited environment
  838. for e, value in sorted( os.environ.items() ):
  839. self.Info("Environment {0}={1}".format(e, value.replace("]]>", "]]&gt;")))
  840. # and some general debug stuff
  841. self.Debug("Platform {0}".format("-".join(hostplatform)))
  842. self.Debug("Filesystem {0}".format(self.filesystem))
  843. self.Debug("Python {0}.{1}.{2}".format(*sys.version_info[:3]))
  844. self.Debug("Command-line-parser {0}".format(self.CLI))
  845. for e,value in self.override.items():
  846. self.Debug("Override {0} = {1}".format(e, value))
  847. for t in self.targets:
  848. self.Debug("Target {0}".format(t))
  849. def _check_and_set_build_targets(self):
  850. # resolve inter-argument dependencies.
  851. # --what or --check implies the WHAT target and FilterWhat Filter
  852. if self.doWhat or self.doCheck:
  853. self.targets = ["WHAT"]
  854. self.filterList = "filterwhat"
  855. else:
  856. # 1. CLEAN/CLEANEXPORT/REALLYCLEAN needs the FilterClean filter.
  857. # 2. Targets that clean should not be combined with other targets.
  858. targets = [x.lower() for x in self.targets]
  859. CL = "clean"
  860. CE = "cleanexport"
  861. RC = "reallyclean"
  862. is_clean = 0
  863. is_suspicious_clean = 0
  864. if CL in targets and CE in targets:
  865. is_clean = 1
  866. if len(targets) > 2:
  867. is_suspicious_clean = 1
  868. elif RC in targets or CL in targets or CE in targets:
  869. is_clean = 1
  870. if len(targets) > 1:
  871. is_suspicious_clean = 1
  872. if is_clean:
  873. self.filterList += ",filterclean"
  874. if is_suspicious_clean:
  875. self.Warn('CLEAN, CLEANEXPORT and a REALLYCLEAN should not be combined with other targets as the result is unpredictable.')
  876. else:
  877. """ Copyfile implements the <copy> tag which is primarily useful with cluster builds.
  878. It allows file copying to occur on the primary build host rather than on the cluster.
  879. This is more efficient.
  880. """
  881. self.filterList += ",filtercopyfile"
  882. def GetBuildUnitsToBuild(self, configNames):
  883. """Return a list of the configuration objects that correspond to the
  884. list of configuration names in the configNames parameter.
  885. raptor.GetBuildUnitsToBuild(["armv5", "winscw"])
  886. >>> [ config1, config2, ... , configN ]
  887. """
  888. if len(configNames) == 0:
  889. # use default config
  890. if len(self.defaultConfig) == 0:
  891. self.Warn("No default configuration name")
  892. else:
  893. configNames.append(self.defaultConfig)
  894. buildUnitsToBuild = raptor_data.GetBuildUnits(configNames, self.cache, self)
  895. for b in buildUnitsToBuild:
  896. self.Info("Buildable configuration '{0}'".format(b.name))
  897. if len(buildUnitsToBuild) == 0:
  898. self.Error("No build configurations given")
  899. return buildUnitsToBuild
  900. def CheckToolset(self, evaluator, configname):
  901. """Check the toolset for a particular config, allow other objects access
  902. to the toolset for this build (e.g. the raptor_make class)."""
  903. if self.toolset is None:
  904. if self.toolcheck == 'on':
  905. self.toolset = raptor_data.ToolSet(log=self)
  906. elif self.toolcheck == 'forced' :
  907. self.toolset = raptor_data.ToolSet(log=self, forced=True)
  908. else:
  909. return True
  910. return self.toolset.check(evaluator, configname)
  911. def CheckConfigs(self, configs):
  912. """ Tool checking for all the buildable configurations
  913. NB. We are allowed to use different tool versions for different
  914. configurations."""
  915. tools_ok = True
  916. tool_problems = []
  917. for b in configs:
  918. self.Debug("Tool check for {0}".format(b.name))
  919. config_ok = False #default
  920. try:
  921. evaluator = self.GetEvaluator(None, b, gathertools=True)
  922. config_ok = self.CheckToolset(evaluator, b.name)
  923. except raptor_data.UninitialisedVariableException,e:
  924. tool_problems.append(b.name)
  925. self.Error("{0} is a bad configuration: {1}".format(b.name,str(e)))
  926. tools_ok = tools_ok and config_ok
  927. if len(tool_problems) > 0:
  928. self.FatalError("Build stopped because the following requested configurations are incomplete or invalid: {0}".format(", ".join(tool_problems)))
  929. return tools_ok
  930. def GatherSysModelLayers(self, systemModel, systemDefinitionRequestedLayers):
  931. """Return a list of lists of components to be built.
  932. components = GatherSysModelLayers(self, configurations)
  933. >>> set("abc/group/bld.inf","def/group/bld.inf, ....")
  934. """
  935. layersToBuild = []
  936. if systemModel:
  937. # We either process all available layers in the system model, or a subset of
  938. # layers specified on the command line. In both cases, the processing is the same,
  939. # and can be subject to ordering if explicitly requested.
  940. systemModel.DumpInfo()
  941. if systemDefinitionRequestedLayers:
  942. layersToProcess = systemDefinitionRequestedLayers
  943. else:
  944. layersToProcess = systemModel.GetLayerNames()
  945. for layer in layersToProcess:
  946. systemModel.DumpLayerInfo(layer)
  947. if systemModel.IsLayerBuildable(layer):
  948. layersToBuild.append(Layer.from_system_model(layer,
  949. systemModel.GetLayerComponents(layer)))
  950. return layersToBuild
  951. # Add bld.inf or system definition xml to command line layers (depending on preference)
  952. def FindSysDefIn(self, aDir = None):
  953. # Find a system definition file
  954. if aDir is None:
  955. dir = generic_path.CurrentDir()
  956. else:
  957. dir = generic_path.Path(aDir)
  958. sysDef = dir.Append(self.systemDefinition)
  959. if not sysDef.isFile():
  960. return None
  961. return sysDef
  962. def FindComponentIn(self, aDir = None):
  963. # look for a bld.inf
  964. if aDir is None:
  965. dir = generic_path.CurrentDir()
  966. else:
  967. dir = generic_path.Path(aDir)
  968. bldInf = dir.Append(self.buildInformation)
  969. if bldInf.isFile():
  970. return BldinfComponent(bldInf)
  971. return None
  972. def GenerateGenericSpecs(self, configsToBuild):
  973. # if a Configuration has any config-wide interfaces
  974. # then add a Specification node to call each of them.
  975. configWide = {}
  976. genericSpecs = []
  977. for c in configsToBuild:
  978. evaluator = self.GetEvaluator(None, c)
  979. iface = evaluator.Get("INTERFACE.config")
  980. if iface:
  981. if iface in configWide:
  982. # seen it already, so reuse the node
  983. filter = configWide[iface]
  984. filter.AddConfigCondition(c.name)
  985. else:
  986. # create a new node
  987. filter = raptor_data.Filter(name = "config_wide")
  988. filter.AddConfigCondition(c.name)
  989. for i in iface.split():
  990. spec = raptor_data.Specification(i)
  991. spec.SetInterface(i)
  992. filter.AddChildSpecification(spec)
  993. # remember it, use it
  994. configWide[iface] = filter
  995. genericSpecs.append(filter)
  996. return genericSpecs
  997. def GetEvaluator(self, specification, configuration, gathertools=False):
  998. """ this will perform some caching later """
  999. return raptor_data.Evaluator(specification, configuration, gathertools=gathertools, cache = self.cache)
  1000. def Make(self, makefileset):
  1001. if not self.noBuild and makefileset is not None:
  1002. if self.maker.Make(makefileset, not self.ignore_zero_flmcall_makefiles):
  1003. self.Info("The make-engine exited successfully.")
  1004. return True
  1005. else:
  1006. self.Error("The make-engine exited with errors.")
  1007. return False
  1008. else:
  1009. self.Info("No build performed")
  1010. def Report(self):
  1011. if self.quiet:
  1012. return
  1013. self.endtime = time.time()
  1014. self.runtime = int(0.5 + self.endtime - self.starttime)
  1015. self.raptor_params.runtime = self.runtime
  1016. self.Info("Run time {0} seconds".format(self.runtime))
  1017. def AssertBuildOK(self):
  1018. """Raise a BuildCannotProgressException if no further processing is required
  1019. """
  1020. if self.Skip():
  1021. raise BuildCannotProgressException("")
  1022. return True
  1023. def Skip(self):
  1024. """Indicate not to perform operation if:
  1025. fatalErrorState is set
  1026. an error code is set but we're not in keepgoing mode
  1027. """
  1028. return self.fatalErrorState or ((self.errorCode != 0) and (not self.keepGoing))
  1029. # log file open/close
  1030. def OpenLog(self):
  1031. """Open a log file for the various I/O methods to write to."""
  1032. try:
  1033. # Find all the raptor plugins and put them into a pluginbox.
  1034. if not self.systemPlugins.isAbsolute():
  1035. self.systemPlugins = self.home.Append(self.systemPlugins)
  1036. self.pbox = pluginbox.PluginBox(str(self.systemPlugins))
  1037. self.raptor_params = BuildStats(self)
  1038. # Open the requested plugins using the pluginbox
  1039. self.out.open(self.raptor_params, self.filterList, self.pbox)
  1040. # log header
  1041. self.out.write("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n")
  1042. namespace = "http://symbian.com/xml/build/log"
  1043. progress_namespace = "http://symbian.com/xml/build/log/progress"
  1044. schema = "http://symbian.com/xml/build/log/1_0.xsd"
  1045. self.out.write("<buildlog sbs_version=\"{0}\" xmlns=\"{1}\" xmlns:progress=\"{2}\""
  1046. " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"{3} {4}\">\n".format(
  1047. raptor_version.fullversion(), namespace, progress_namespace, namespace, schema))
  1048. self.logOpen = True
  1049. except Exception,e:
  1050. self.out = sys.stdout # make sure that we can actually get errors out.
  1051. self.logOpen = False
  1052. self.FatalError("Unable to open the output logs: {0}".format(str(e)))
  1053. def CloseLog(self):
  1054. if self.logOpen:
  1055. self.out.summary()
  1056. self.out.write("</buildlog>\n")
  1057. if not self.out.close():
  1058. self.errorCode = 1
  1059. def Cleanup(self):
  1060. # ensure that the toolset cache is flushed.
  1061. if self.toolset is not None:
  1062. self.toolset.write()
  1063. # I/O methods
  1064. @staticmethod
  1065. def attributeString(dictionary):
  1066. "turn a dictionary into a string of XML attributes"
  1067. atts = ""
  1068. for a,v in dictionary.items():
  1069. atts += " " + a + "='" + v + "'"
  1070. return atts
  1071. def Info(self, msg, **attributes):
  1072. """Send an information message to the configured channel
  1073. (XML control characters will be escaped)
  1074. """
  1075. self.out.write("<info{0}>{1}</info>\n".format(self.attributeString(attributes), escape(msg)))
  1076. def InfoDiscovery(self, object_type, count):
  1077. if self.timing:
  1078. try:
  1079. self.out.write(raptor_timing.Timing.discovery_string(object_type = object_type,
  1080. count = count))
  1081. except Exception, exception:
  1082. self.Error(exception.Text, function = "InfoDiscoveryTime")
  1083. def InfoStartTime(self, object_type, task, key):
  1084. if self.timing:
  1085. try:
  1086. self.out.write(raptor_timing.Timing.start_string(object_type = object_type,
  1087. task = task, key = key))
  1088. except Exception, exception:
  1089. self.Error(exception.Text, function = "InfoStartTime")
  1090. def InfoEndTime(self, object_type, task, key):
  1091. if self.timing:
  1092. try:
  1093. self.out.write(raptor_timing.Timing.end_string(object_type = object_type,
  1094. task = task, key = key))
  1095. except Exception, exception:
  1096. self.Error(exception.Text, function = "InfoEndTime")
  1097. def Debug(self, msg, **attributes):
  1098. "Send a debugging message to the configured channel"
  1099. # the debug text is out of our control so wrap it in a CDATA
  1100. # in case it contains characters special to XML... like <>
  1101. if self.debugOutput:
  1102. self.out.write("<debug{0}><![CDATA[\n{1}\n]]></debug>\n".format(self.attributeString(attributes),escape(msg)))
  1103. def Warn(self, msg, **attributes):
  1104. """Send a warning message to the configured channel
  1105. (XML control characters will be escaped)
  1106. """
  1107. self.out.write("<warning{0}>{1}</warning>\n".format(self.attributeString(attributes), escape(msg)))
  1108. def FatalError(self, msg, **attributes):
  1109. """Send an error message to the configured channel. This implies such a serious
  1110. error that the entire build must be shut down asap whilst still finishing off
  1111. correctly whatever housekeeping is possible e.g. producing error reports.
  1112. Remains quiet if the raptor object is already in a fatal state since there
  1113. further errors are probably triggered by the first.
  1114. """
  1115. if not self.fatalErrorState:
  1116. self.out.write("<error{0}>{1}</error>\n".format(self.attributeString(attributes), escape(msg)))
  1117. self.errorCode = 1
  1118. self.fatalErrorState = True
  1119. def Error(self, msg, **attributes):
  1120. """Send an error message to the configured channel
  1121. (XML control characters will be escaped)
  1122. """
  1123. self.out.write("<error{0}>{1}</error>\n".format(self.attributeString(attributes), escape(msg)))
  1124. self.errorCode = 1
  1125. def PrintXML(self, format, *extras):
  1126. "Print to configured channel (no newline is added) (assumes valid xml)"
  1127. if format:
  1128. self.out.write(format % extras)
  1129. def GetLayersFromCLI(self):
  1130. """Returns the list of layers as specified by the
  1131. commandline interface to Raptor e.g. parameters
  1132. or the current directory"""
  1133. layers=[]
  1134. # Look for bld.infs or sysdefs in the current dir if none were specified
  1135. if self.systemDefinitionFile == None and len(self.commandline_layer) == 0:
  1136. if not self.preferBuildInfoToSystemDefinition:
  1137. cwd = os.getcwd()
  1138. self.systemDefinitionFile = self.FindSysDefIn(cwd)
  1139. if self.systemDefinitionFile == None:
  1140. aComponent = self.FindComponentIn(cwd)
  1141. if aComponent is not None:
  1142. layers.append(Layer('default',[aComponent]))
  1143. else:
  1144. aComponent = self.FindComponentIn(cwd)
  1145. if aComponent is None:
  1146. self.systemDefinitionFile = self.FindSysDefIn(cwd)
  1147. else:
  1148. layers.append(Layer('default',[aComponent]))
  1149. if len(layers) <= 0 and self.systemDefinitionFile == None:
  1150. self.Warn("No default bld.inf or system definition file found in current directory ({0})".format(cwd))
  1151. # If we now have a System Definition to parse then get the layers of components
  1152. if self.systemDefinitionFile != None:
  1153. systemModel = raptor_xml.SystemModel(self, self.systemDefinitionFile, self.systemDefinitionBase)
  1154. layers = self.GatherSysModelLayers(systemModel, self.systemDefinitionRequestedLayers)
  1155. # Now get components specified on a commandline - build them after any
  1156. # layers in the system definition.
  1157. if len(self.commandline_layer) > 0:
  1158. layers.append(self.commandline_layer)
  1159. # If we aren't building components in order then flatten down
  1160. # the groups
  1161. if not self.systemDefinitionOrderLayers:
  1162. # Flatten the layers into one group of components if
  1163. # we are not required to build them in order.
  1164. newcg = Layer("all")
  1165. for cg in layers:
  1166. for c in cg:
  1167. newcg.add(c)
  1168. layers = [newcg]
  1169. return layers
  1170. def Query(self):
  1171. "process command-line queries."
  1172. if self.mission != Raptor.M_QUERY:
  1173. return 0
  1174. # establish an object cache based on the current settings
  1175. self._load_cache()
  1176. # our "self" is a valid object for initialising an API Context
  1177. import raptor_api
  1178. api = raptor_api.Context(self)
  1179. print "<sbs version='{0}'>".format(raptor_version.numericversion())
  1180. for q in self.queries:
  1181. try:
  1182. print api.stringquery(q)
  1183. except Exception, e:
  1184. self.Error("exception '{0}' with query '{1}'".format(str(e), q))
  1185. print "</sbs>"
  1186. return self.errorCode
  1187. def Build(self):
  1188. if self.mission != Raptor.M_BUILD: # help or version requested instead.
  1189. return 0
  1190. # open the log file
  1191. self.OpenLog()
  1192. try:
  1193. self.AssertBuildOK()
  1194. # show the command and platform info
  1195. self.Introduction()
  1196. # load the cache of configurations etc
  1197. self._load_cache()
  1198. # establish an object cache
  1199. self.AssertBuildOK()
  1200. # find out what configurations to build
  1201. buildUnitsToBuild = self.GetBuildUnitsToBuild(self.configNames)
  1202. if len(buildUnitsToBuild) == 0:
  1203. raise BuildCannotProgressException("No configurations to build.")
  1204. self.buildUnitsToBuild = buildUnitsToBuild
  1205. self.AssertBuildOK()
  1206. ###### insert the start time into the Makefile name
  1207. makefile = self.topMakefile.Absolute()
  1208. makefile.path = makefile.path.replace("%TIME", self.timestring)
  1209. self.topMakefile = makefile
  1210. ######
  1211. # Create a build record as non-parallel parsed builds can take advantage of incremental
  1212. # makefile generation with some level of safety:
  1213. tm_dir = str(makefile.Dir())
  1214. tm_file = str(makefile.File())
  1215. environment = ";".join(["{0}={1}".format(k,os.environ[k]) for k in BuildRecord.sensed_environment_variables])
  1216. must_create_makefiles = True
  1217. if self.incremental_parsing:
  1218. self.build_record = BuildRecord.from_old(adir = str(self.topMakefile.Dir()), commandline=" ".join(self.args), environment = environment, topmakefile = str(makefile))
  1219. must_create_makefiles = not self.build_record.reused
  1220. if must_create_makefiles:
  1221. if len(self.build_record.new_metadata) > 0:
  1222. self.Info("incremental makefile generation: out of date items: {0}".format(" ".join(set(self.build_record.new_metadata))))
  1223. else:
  1224. self.build_record = BuildRecord(commandline=" ".join(self.args), environment = environment, topmakefilename = str(makefile), makefilesets=[])
  1225. if must_create_makefiles:
  1226. if self.incremental_parsing:
  1227. self.Info("incremental makefile generation: cannot reuse any pre-existing makefiles")
  1228. # find out what components to build, and in what way
  1229. layers = []
  1230. self.AssertBuildOK()
  1231. if len(buildUnitsToBuild) >= 0:
  1232. layers = self.GetLayersFromCLI()
  1233. componentCount = reduce(lambda x,y : x + y, [len(cg) for cg in layers])
  1234. if not componentCount > 0:
  1235. raise BuildCannotProgressException("No components to build.")
  1236. # check the configurations (tools versions)
  1237. self.AssertBuildOK()
  1238. if self.toolcheck != 'off':
  1239. self.CheckConfigs(buildUnitsToBuild)
  1240. else:
  1241. self.Info("Not Checking Tool Versions")
  1242. self.AssertBuildOK()
  1243. else:
  1244. # Don't use the makefile name specified on the commmandline - use the one from the build record.
  1245. self.Info("incremental makefile generation: pre-existing makefiles will be reused: {0}".format(self.build_record.topmakefilename))
  1246. # Setup a make engine.
  1247. if not self.maker:
  1248. try:
  1249. self.maker = raptor_make.MakeEngine(self, self.makeEngine)
  1250. except raptor_make.BadMakeEngineException,e:
  1251. self.Error("Unable to use make engine: {0} ".format(str(e)))
  1252. self.AssertBuildOK()
  1253. # if self.doParallelParsing and not (len(layers) == 1 and len(layers[0]) == 1):
  1254. # rebuilding and parallel parsing are not compatible at the moment. There is
  1255. # a validation check for that earlier.
  1256. if self.doParallelParsing:
  1257. # Create a Makefile to parse components in parallel and build them
  1258. self.build_record = BuildRecord(commandline=" ".join(self.args), environment=environment, topmakefilename=str(makefile), makefilesets=[])
  1259. for l in layers:
  1260. l.meta_realise(self)
  1261. elif must_create_makefiles:
  1262. # Parse components serially, creating one set of makefiles
  1263. # create non-component specs
  1264. self.generic_specs = self.GenerateGenericSpecs(buildUnitsToBuild)
  1265. self.AssertBuildOK()
  1266. self.build_record = BuildRecord(commandline=" ".join(self.args), environment=environment, topmakefilename=str(makefile), makefilesets=[])
  1267. for l in layers:
  1268. # create specs for a specific group of components
  1269. try:
  1270. l.realise(self)
  1271. except raptor_make.CannotWriteMakefileException,e:
  1272. pass # raptor_make will report these errors itself
  1273. try:
  1274. self.build_record.to_file()
  1275. except Exception,e:
  1276. self.Info("Couldn't write build record file: {0}".format(str(e)))
  1277. else:
  1278. # Reusing old makefiles
  1279. for makefileset in self.build_record.makefilesets:
  1280. self.InfoStartTime(object_type = "makefileset", task = "build",
  1281. key = makefileset.metadepsfilename)
  1282. result = self.Make(makefileset)
  1283. self.InfoEndTime(object_type = "makefileset", task = "build",
  1284. key = makefileset.metadepsfilename)
  1285. except BuildCannotProgressException,b:
  1286. if str(b) != "":
  1287. self.Info(str(b))
  1288. # final report
  1289. if not self.fatalErrorState:
  1290. self.Report()
  1291. self.Cleanup()
  1292. # close the log file
  1293. self.CloseLog()
  1294. return self.errorCode
  1295. @classmethod
  1296. def CreateCommandlineAnalysis(cls, argv):
  1297. """ Perform an analysis run where a build is not performed.
  1298. Don't parse command line targets - they don't make any sense if you're not doing a build"""
  1299. build = Raptor(commandline=argv, dotargets = False)
  1300. return build
  1301. # Class for passing constricted parameters to filters
  1302. class BuildStats(object):
  1303. def __init__(self, raptor_instance):
  1304. self.incoming_epocroot = incoming_epocroot
  1305. self.epocroot = epocroot
  1306. self.logFileName = raptor_instance.logFileName
  1307. self.configPath = raptor_instance.configPath
  1308. self.home = raptor_instance.home
  1309. self.quiet = raptor_instance.quiet
  1310. self.doCheck = raptor_instance.doCheck
  1311. self.doWhat = raptor_instance.doWhat
  1312. self.platform = hostplatform
  1313. self.skipAll = raptor_instance.fatalErrorState
  1314. self.timestring = raptor_instance.timestring
  1315. self.targets = raptor_instance.targets
  1316. self.runtime = 0
  1317. self.name = name
  1318. self.topMakefile = raptor_instance.topMakefile
  1319. # raptor module functions
  1320. def Main(argv):
  1321. """The main entry point for Raptor.
  1322. argv is a list of command-line parameters,
  1323. NOT including the name of the calling script.
  1324. The return value is zero for success and non-zero for failure."""
  1325. DisplayBanner()
  1326. try:
  1327. # object which represents a build
  1328. b = Raptor(commandline=argv)
  1329. if b.mission == Raptor.M_QUERY:
  1330. return b.Query()
  1331. return b.Build()
  1332. except BuildCannotProgressException, e:
  1333. t = str(e)
  1334. if t != "":
  1335. print("sbs error: {0:s}".format(t))
  1336. return 1
  1337. def DisplayBanner():
  1338. """Stuff that needs printing out for every command."""
  1339. pass
  1340. # end of the raptor module