cookerdata.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. #
  2. # Copyright (C) 2003, 2004 Chris Larson
  3. # Copyright (C) 2003, 2004 Phil Blundell
  4. # Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
  5. # Copyright (C) 2005 Holger Hans Peter Freyther
  6. # Copyright (C) 2005 ROAD GmbH
  7. # Copyright (C) 2006 Richard Purdie
  8. #
  9. # SPDX-License-Identifier: GPL-2.0-only
  10. #
  11. import logging
  12. import os
  13. import re
  14. import sys
  15. import hashlib
  16. from functools import wraps
  17. import bb
  18. from bb import data
  19. import bb.parse
  20. logger = logging.getLogger("BitBake")
  21. parselog = logging.getLogger("BitBake.Parsing")
  22. class ConfigParameters(object):
  23. def __init__(self, argv=None):
  24. self.options, targets = self.parseCommandLine(argv or sys.argv)
  25. self.environment = self.parseEnvironment()
  26. self.options.pkgs_to_build = targets or []
  27. for key, val in self.options.__dict__.items():
  28. setattr(self, key, val)
  29. def parseCommandLine(self, argv=sys.argv):
  30. raise Exception("Caller must implement commandline option parsing")
  31. def parseEnvironment(self):
  32. return os.environ.copy()
  33. def updateFromServer(self, server):
  34. if not self.options.cmd:
  35. defaulttask, error = server.runCommand(["getVariable", "BB_DEFAULT_TASK"])
  36. if error:
  37. raise Exception("Unable to get the value of BB_DEFAULT_TASK from the server: %s" % error)
  38. self.options.cmd = defaulttask or "build"
  39. _, error = server.runCommand(["setConfig", "cmd", self.options.cmd])
  40. if error:
  41. raise Exception("Unable to set configuration option 'cmd' on the server: %s" % error)
  42. if not self.options.pkgs_to_build:
  43. bbpkgs, error = server.runCommand(["getVariable", "BBTARGETS"])
  44. if error:
  45. raise Exception("Unable to get the value of BBTARGETS from the server: %s" % error)
  46. if bbpkgs:
  47. self.options.pkgs_to_build.extend(bbpkgs.split())
  48. def updateToServer(self, server, environment):
  49. options = {}
  50. for o in ["halt", "force", "invalidate_stamp",
  51. "dry_run", "dump_signatures",
  52. "extra_assume_provided", "profile",
  53. "prefile", "postfile", "server_timeout",
  54. "nosetscene", "setsceneonly", "skipsetscene",
  55. "runall", "runonly", "writeeventlog"]:
  56. options[o] = getattr(self.options, o)
  57. options['build_verbose_shell'] = self.options.verbose
  58. options['build_verbose_stdout'] = self.options.verbose
  59. options['default_loglevel'] = bb.msg.loggerDefaultLogLevel
  60. options['debug_domains'] = bb.msg.loggerDefaultDomains
  61. ret, error = server.runCommand(["updateConfig", options, environment, sys.argv])
  62. if error:
  63. raise Exception("Unable to update the server configuration with local parameters: %s" % error)
  64. def parseActions(self):
  65. # Parse any commandline into actions
  66. action = {'action':None, 'msg':None}
  67. if self.options.show_environment:
  68. if 'world' in self.options.pkgs_to_build:
  69. action['msg'] = "'world' is not a valid target for --environment."
  70. elif 'universe' in self.options.pkgs_to_build:
  71. action['msg'] = "'universe' is not a valid target for --environment."
  72. elif len(self.options.pkgs_to_build) > 1:
  73. action['msg'] = "Only one target can be used with the --environment option."
  74. elif self.options.buildfile and len(self.options.pkgs_to_build) > 0:
  75. action['msg'] = "No target should be used with the --environment and --buildfile options."
  76. elif self.options.pkgs_to_build:
  77. action['action'] = ["showEnvironmentTarget", self.options.pkgs_to_build]
  78. else:
  79. action['action'] = ["showEnvironment", self.options.buildfile]
  80. elif self.options.buildfile is not None:
  81. action['action'] = ["buildFile", self.options.buildfile, self.options.cmd]
  82. elif self.options.revisions_changed:
  83. action['action'] = ["compareRevisions"]
  84. elif self.options.show_versions:
  85. action['action'] = ["showVersions"]
  86. elif self.options.parse_only:
  87. action['action'] = ["parseFiles"]
  88. elif self.options.dot_graph:
  89. if self.options.pkgs_to_build:
  90. action['action'] = ["generateDotGraph", self.options.pkgs_to_build, self.options.cmd]
  91. else:
  92. action['msg'] = "Please specify a package name for dependency graph generation."
  93. else:
  94. if self.options.pkgs_to_build:
  95. action['action'] = ["buildTargets", self.options.pkgs_to_build, self.options.cmd]
  96. else:
  97. #action['msg'] = "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information."
  98. action = None
  99. self.options.initialaction = action
  100. return action
  101. class CookerConfiguration(object):
  102. """
  103. Manages build options and configurations for one run
  104. """
  105. def __init__(self):
  106. self.debug_domains = bb.msg.loggerDefaultDomains
  107. self.default_loglevel = bb.msg.loggerDefaultLogLevel
  108. self.extra_assume_provided = []
  109. self.prefile = []
  110. self.postfile = []
  111. self.cmd = None
  112. self.halt = True
  113. self.force = False
  114. self.profile = False
  115. self.nosetscene = False
  116. self.setsceneonly = False
  117. self.skipsetscene = False
  118. self.invalidate_stamp = False
  119. self.dump_signatures = []
  120. self.build_verbose_shell = False
  121. self.build_verbose_stdout = False
  122. self.dry_run = False
  123. self.tracking = False
  124. self.writeeventlog = False
  125. self.limited_deps = False
  126. self.runall = []
  127. self.runonly = []
  128. self.env = {}
  129. def __getstate__(self):
  130. state = {}
  131. for key in self.__dict__.keys():
  132. state[key] = getattr(self, key)
  133. return state
  134. def __setstate__(self,state):
  135. for k in state:
  136. setattr(self, k, state[k])
  137. def catch_parse_error(func):
  138. """Exception handling bits for our parsing"""
  139. @wraps(func)
  140. def wrapped(fn, *args):
  141. try:
  142. return func(fn, *args)
  143. except IOError as exc:
  144. import traceback
  145. parselog.critical(traceback.format_exc())
  146. parselog.critical("Unable to parse %s: %s" % (fn, exc))
  147. raise bb.BBHandledException()
  148. except bb.data_smart.ExpansionError as exc:
  149. import traceback
  150. bbdir = os.path.dirname(__file__) + os.sep
  151. exc_class, exc, tb = sys.exc_info()
  152. for tb in iter(lambda: tb.tb_next, None):
  153. # Skip frames in bitbake itself, we only want the metadata
  154. fn, _, _, _ = traceback.extract_tb(tb, 1)[0]
  155. if not fn.startswith(bbdir):
  156. break
  157. parselog.critical("Unable to parse %s" % fn, exc_info=(exc_class, exc, tb))
  158. raise bb.BBHandledException()
  159. except bb.parse.ParseError as exc:
  160. parselog.critical(str(exc))
  161. raise bb.BBHandledException()
  162. return wrapped
  163. @catch_parse_error
  164. def parse_config_file(fn, data, include=True):
  165. return bb.parse.handle(fn, data, include)
  166. @catch_parse_error
  167. def _inherit(bbclass, data):
  168. bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
  169. return data
  170. def findConfigFile(configfile, data):
  171. search = []
  172. bbpath = data.getVar("BBPATH")
  173. if bbpath:
  174. for i in bbpath.split(":"):
  175. search.append(os.path.join(i, "conf", configfile))
  176. path = os.getcwd()
  177. while path != "/":
  178. search.append(os.path.join(path, "conf", configfile))
  179. path, _ = os.path.split(path)
  180. for i in search:
  181. if os.path.exists(i):
  182. return i
  183. return None
  184. #
  185. # We search for a conf/bblayers.conf under an entry in BBPATH or in cwd working
  186. # up to /. If that fails, bitbake would fall back to cwd.
  187. #
  188. def findTopdir():
  189. d = bb.data.init()
  190. bbpath = None
  191. if 'BBPATH' in os.environ:
  192. bbpath = os.environ['BBPATH']
  193. d.setVar('BBPATH', bbpath)
  194. layerconf = findConfigFile("bblayers.conf", d)
  195. if layerconf:
  196. return os.path.dirname(os.path.dirname(layerconf))
  197. return os.path.abspath(os.getcwd())
  198. class CookerDataBuilder(object):
  199. def __init__(self, cookercfg, worker = False):
  200. self.prefiles = cookercfg.prefile
  201. self.postfiles = cookercfg.postfile
  202. self.tracking = cookercfg.tracking
  203. bb.utils.set_context(bb.utils.clean_context())
  204. bb.event.set_class_handlers(bb.event.clean_class_handlers())
  205. self.basedata = bb.data.init()
  206. if self.tracking:
  207. self.basedata.enableTracking()
  208. # Keep a datastore of the initial environment variables and their
  209. # values from when BitBake was launched to enable child processes
  210. # to use environment variables which have been cleaned from the
  211. # BitBake processes env
  212. self.savedenv = bb.data.init()
  213. for k in cookercfg.env:
  214. self.savedenv.setVar(k, cookercfg.env[k])
  215. if k in bb.data_smart.bitbake_renamed_vars:
  216. bb.error('Shell environment variable %s has been renamed to %s' % (k, bb.data_smart.bitbake_renamed_vars[k]))
  217. bb.fatal("Exiting to allow enviroment variables to be corrected")
  218. filtered_keys = bb.utils.approved_variables()
  219. bb.data.inheritFromOS(self.basedata, self.savedenv, filtered_keys)
  220. self.basedata.setVar("BB_ORIGENV", self.savedenv)
  221. self.basedata.setVar("__bbclasstype", "global")
  222. if worker:
  223. self.basedata.setVar("BB_WORKERCONTEXT", "1")
  224. self.data = self.basedata
  225. self.mcdata = {}
  226. def parseBaseConfiguration(self, worker=False):
  227. data_hash = hashlib.sha256()
  228. try:
  229. self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
  230. if self.data.getVar("BB_WORKERCONTEXT", False) is None and not worker:
  231. bb.fetch.fetcher_init(self.data)
  232. bb.parse.init_parser(self.data)
  233. bb.codeparser.parser_cache_init(self.data)
  234. bb.event.fire(bb.event.ConfigParsed(), self.data)
  235. reparse_cnt = 0
  236. while self.data.getVar("BB_INVALIDCONF", False) is True:
  237. if reparse_cnt > 20:
  238. logger.error("Configuration has been re-parsed over 20 times, "
  239. "breaking out of the loop...")
  240. raise Exception("Too deep config re-parse loop. Check locations where "
  241. "BB_INVALIDCONF is being set (ConfigParsed event handlers)")
  242. self.data.setVar("BB_INVALIDCONF", False)
  243. self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
  244. reparse_cnt += 1
  245. bb.event.fire(bb.event.ConfigParsed(), self.data)
  246. bb.parse.init_parser(self.data)
  247. data_hash.update(self.data.get_hash().encode('utf-8'))
  248. self.mcdata[''] = self.data
  249. multiconfig = (self.data.getVar("BBMULTICONFIG") or "").split()
  250. for config in multiconfig:
  251. if config[0].isdigit():
  252. bb.fatal("Multiconfig name '%s' is invalid as multiconfigs cannot start with a digit" % config)
  253. mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config)
  254. bb.event.fire(bb.event.ConfigParsed(), mcdata)
  255. self.mcdata[config] = mcdata
  256. data_hash.update(mcdata.get_hash().encode('utf-8'))
  257. if multiconfig:
  258. bb.event.fire(bb.event.MultiConfigParsed(self.mcdata), self.data)
  259. self.data_hash = data_hash.hexdigest()
  260. except (SyntaxError, bb.BBHandledException):
  261. raise bb.BBHandledException()
  262. except bb.data_smart.ExpansionError as e:
  263. logger.error(str(e))
  264. raise bb.BBHandledException()
  265. except Exception:
  266. logger.exception("Error parsing configuration files")
  267. raise bb.BBHandledException()
  268. # Handle obsolete variable names
  269. d = self.data
  270. renamedvars = d.getVarFlags('BB_RENAMED_VARIABLES') or {}
  271. renamedvars.update(bb.data_smart.bitbake_renamed_vars)
  272. issues = False
  273. for v in renamedvars:
  274. if d.getVar(v) != None or d.hasOverrides(v):
  275. issues = True
  276. loginfo = {}
  277. history = d.varhistory.get_variable_refs(v)
  278. for h in history:
  279. for line in history[h]:
  280. loginfo = {'file' : h, 'line' : line}
  281. bb.data.data_smart._print_rename_error(v, loginfo, renamedvars)
  282. if not history:
  283. bb.data.data_smart._print_rename_error(v, loginfo, renamedvars)
  284. if issues:
  285. raise bb.BBHandledException()
  286. # Create a copy so we can reset at a later date when UIs disconnect
  287. self.origdata = self.data
  288. self.data = bb.data.createCopy(self.origdata)
  289. self.mcdata[''] = self.data
  290. def reset(self):
  291. # We may not have run parseBaseConfiguration() yet
  292. if not hasattr(self, 'origdata'):
  293. return
  294. self.data = bb.data.createCopy(self.origdata)
  295. self.mcdata[''] = self.data
  296. def _findLayerConf(self, data):
  297. return findConfigFile("bblayers.conf", data)
  298. def parseConfigurationFiles(self, prefiles, postfiles, mc = "default"):
  299. data = bb.data.createCopy(self.basedata)
  300. data.setVar("BB_CURRENT_MC", mc)
  301. # Parse files for loading *before* bitbake.conf and any includes
  302. for f in prefiles:
  303. data = parse_config_file(f, data)
  304. layerconf = self._findLayerConf(data)
  305. if layerconf:
  306. parselog.debug(2, "Found bblayers.conf (%s)", layerconf)
  307. # By definition bblayers.conf is in conf/ of TOPDIR.
  308. # We may have been called with cwd somewhere else so reset TOPDIR
  309. data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf)))
  310. data = parse_config_file(layerconf, data)
  311. layers = (data.getVar('BBLAYERS') or "").split()
  312. broken_layers = []
  313. if not layers:
  314. bb.fatal("The bblayers.conf file doesn't contain any BBLAYERS definition")
  315. data = bb.data.createCopy(data)
  316. approved = bb.utils.approved_variables()
  317. # Check whether present layer directories exist
  318. for layer in layers:
  319. if not os.path.isdir(layer):
  320. broken_layers.append(layer)
  321. if broken_layers:
  322. parselog.critical("The following layer directories do not exist:")
  323. for layer in broken_layers:
  324. parselog.critical(" %s", layer)
  325. parselog.critical("Please check BBLAYERS in %s" % (layerconf))
  326. raise bb.BBHandledException()
  327. for layer in layers:
  328. parselog.debug(2, "Adding layer %s", layer)
  329. if 'HOME' in approved and '~' in layer:
  330. layer = os.path.expanduser(layer)
  331. if layer.endswith('/'):
  332. layer = layer.rstrip('/')
  333. data.setVar('LAYERDIR', layer)
  334. data.setVar('LAYERDIR_RE', re.escape(layer))
  335. data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data)
  336. data.expandVarref('LAYERDIR')
  337. data.expandVarref('LAYERDIR_RE')
  338. data.delVar('LAYERDIR_RE')
  339. data.delVar('LAYERDIR')
  340. bbfiles_dynamic = (data.getVar('BBFILES_DYNAMIC') or "").split()
  341. collections = (data.getVar('BBFILE_COLLECTIONS') or "").split()
  342. invalid = []
  343. for entry in bbfiles_dynamic:
  344. parts = entry.split(":", 1)
  345. if len(parts) != 2:
  346. invalid.append(entry)
  347. continue
  348. l, f = parts
  349. invert = l[0] == "!"
  350. if invert:
  351. l = l[1:]
  352. if (l in collections and not invert) or (l not in collections and invert):
  353. data.appendVar("BBFILES", " " + f)
  354. if invalid:
  355. bb.fatal("BBFILES_DYNAMIC entries must be of the form {!}<collection name>:<filename pattern>, not:\n %s" % "\n ".join(invalid))
  356. layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split())
  357. collections_tmp = collections[:]
  358. for c in collections:
  359. collections_tmp.remove(c)
  360. if c in collections_tmp:
  361. bb.fatal("Found duplicated BBFILE_COLLECTIONS '%s', check bblayers.conf or layer.conf to fix it." % c)
  362. compat = set((data.getVar("LAYERSERIES_COMPAT_%s" % c) or "").split())
  363. if compat and not layerseries:
  364. bb.fatal("No core layer found to work with layer '%s'. Missing entry in bblayers.conf?" % c)
  365. if compat and not (compat & layerseries):
  366. bb.fatal("Layer %s is not compatible with the core layer which only supports these series: %s (layer is compatible with %s)"
  367. % (c, " ".join(layerseries), " ".join(compat)))
  368. elif not compat and not data.getVar("BB_WORKERCONTEXT"):
  369. bb.warn("Layer %s should set LAYERSERIES_COMPAT_%s in its conf/layer.conf file to list the core layer names it is compatible with." % (c, c))
  370. if not data.getVar("BBPATH"):
  371. msg = "The BBPATH variable is not set"
  372. if not layerconf:
  373. msg += (" and bitbake did not find a conf/bblayers.conf file in"
  374. " the expected location.\nMaybe you accidentally"
  375. " invoked bitbake from the wrong directory?")
  376. raise SystemExit(msg)
  377. if not data.getVar("TOPDIR"):
  378. data.setVar("TOPDIR", os.path.abspath(os.getcwd()))
  379. data = parse_config_file(os.path.join("conf", "bitbake.conf"), data)
  380. # Parse files for loading *after* bitbake.conf and any includes
  381. for p in postfiles:
  382. data = parse_config_file(p, data)
  383. # Handle any INHERITs and inherit the base class
  384. bbclasses = ["base"] + (data.getVar('INHERIT') or "").split()
  385. for bbclass in bbclasses:
  386. data = _inherit(bbclass, data)
  387. # Normally we only register event handlers at the end of parsing .bb files
  388. # We register any handlers we've found so far here...
  389. for var in data.getVar('__BBHANDLERS', False) or []:
  390. handlerfn = data.getVarFlag(var, "filename", False)
  391. if not handlerfn:
  392. parselog.critical("Undefined event handler function '%s'" % var)
  393. raise bb.BBHandledException()
  394. handlerln = int(data.getVarFlag(var, "lineno", False))
  395. bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln, data)
  396. data.setVar('BBINCLUDED',bb.parse.get_file_depends(data))
  397. return data