blob: 144e803b4f4d8ac15e90d8ab73f0a9810dde620e [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
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#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012import logging
Patrick Williamsc0f7c042017-02-23 20:41:17 -060013import os
14import re
15import sys
16from functools import wraps
Patrick Williamsc124f4f2015-09-15 14:41:29 -050017import bb
18from bb import data
19import bb.parse
20
21logger = logging.getLogger("BitBake")
22parselog = logging.getLogger("BitBake.Parsing")
23
24class ConfigParameters(object):
25 def __init__(self, argv=sys.argv):
26 self.options, targets = self.parseCommandLine(argv)
27 self.environment = self.parseEnvironment()
28
29 self.options.pkgs_to_build = targets or []
30
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031 for key, val in self.options.__dict__.items():
32 setattr(self, key, val)
33
34 def parseCommandLine(self, argv=sys.argv):
35 raise Exception("Caller must implement commandline option parsing")
36
37 def parseEnvironment(self):
38 return os.environ.copy()
39
40 def updateFromServer(self, server):
41 if not self.options.cmd:
42 defaulttask, error = server.runCommand(["getVariable", "BB_DEFAULT_TASK"])
43 if error:
44 raise Exception("Unable to get the value of BB_DEFAULT_TASK from the server: %s" % error)
45 self.options.cmd = defaulttask or "build"
46 _, error = server.runCommand(["setConfig", "cmd", self.options.cmd])
47 if error:
48 raise Exception("Unable to set configuration option 'cmd' on the server: %s" % error)
49
50 if not self.options.pkgs_to_build:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050051 bbpkgs, error = server.runCommand(["getVariable", "BBTARGETS"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050052 if error:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050053 raise Exception("Unable to get the value of BBTARGETS from the server: %s" % error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054 if bbpkgs:
55 self.options.pkgs_to_build.extend(bbpkgs.split())
56
57 def updateToServer(self, server, environment):
58 options = {}
Brad Bishopd7bf8c12018-02-25 22:55:05 -050059 for o in ["abort", "force", "invalidate_stamp",
60 "verbose", "debug", "dry_run", "dump_signatures",
Patrick Williamsc124f4f2015-09-15 14:41:29 -050061 "debug_domains", "extra_assume_provided", "profile",
Brad Bishopd7bf8c12018-02-25 22:55:05 -050062 "prefile", "postfile", "server_timeout"]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050063 options[o] = getattr(self.options, o)
64
Brad Bishop6e60e8b2018-02-01 10:27:11 -050065 ret, error = server.runCommand(["updateConfig", options, environment, sys.argv])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050066 if error:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050067 raise Exception("Unable to update the server configuration with local parameters: %s" % error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068
69 def parseActions(self):
70 # Parse any commandline into actions
71 action = {'action':None, 'msg':None}
72 if self.options.show_environment:
73 if 'world' in self.options.pkgs_to_build:
74 action['msg'] = "'world' is not a valid target for --environment."
75 elif 'universe' in self.options.pkgs_to_build:
76 action['msg'] = "'universe' is not a valid target for --environment."
77 elif len(self.options.pkgs_to_build) > 1:
78 action['msg'] = "Only one target can be used with the --environment option."
79 elif self.options.buildfile and len(self.options.pkgs_to_build) > 0:
80 action['msg'] = "No target should be used with the --environment and --buildfile options."
81 elif len(self.options.pkgs_to_build) > 0:
82 action['action'] = ["showEnvironmentTarget", self.options.pkgs_to_build]
83 else:
84 action['action'] = ["showEnvironment", self.options.buildfile]
85 elif self.options.buildfile is not None:
86 action['action'] = ["buildFile", self.options.buildfile, self.options.cmd]
87 elif self.options.revisions_changed:
88 action['action'] = ["compareRevisions"]
89 elif self.options.show_versions:
90 action['action'] = ["showVersions"]
91 elif self.options.parse_only:
92 action['action'] = ["parseFiles"]
93 elif self.options.dot_graph:
94 if self.options.pkgs_to_build:
95 action['action'] = ["generateDotGraph", self.options.pkgs_to_build, self.options.cmd]
96 else:
97 action['msg'] = "Please specify a package name for dependency graph generation."
98 else:
99 if self.options.pkgs_to_build:
100 action['action'] = ["buildTargets", self.options.pkgs_to_build, self.options.cmd]
101 else:
102 #action['msg'] = "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information."
103 action = None
104 self.options.initialaction = action
105 return action
106
107class CookerConfiguration(object):
108 """
109 Manages build options and configurations for one run
110 """
111
112 def __init__(self):
113 self.debug_domains = []
114 self.extra_assume_provided = []
115 self.prefile = []
116 self.postfile = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117 self.debug = 0
118 self.cmd = None
119 self.abort = True
120 self.force = False
121 self.profile = False
122 self.nosetscene = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500123 self.setsceneonly = False
Brad Bishop96ff1982019-08-19 13:50:42 -0400124 self.skipsetscene = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 self.invalidate_stamp = False
126 self.dump_signatures = []
127 self.dry_run = False
128 self.tracking = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500129 self.xmlrpcinterface = []
130 self.server_timeout = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131 self.writeeventlog = False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500132 self.server_only = False
133 self.limited_deps = False
Brad Bishop316dfdd2018-06-25 12:45:53 -0400134 self.runall = []
135 self.runonly = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136
137 self.env = {}
138
139 def setConfigParameters(self, parameters):
140 for key in self.__dict__.keys():
141 if key in parameters.options.__dict__:
142 setattr(self, key, parameters.options.__dict__[key])
143 self.env = parameters.environment.copy()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144
145 def setServerRegIdleCallback(self, srcb):
146 self.server_register_idlecallback = srcb
147
148 def __getstate__(self):
149 state = {}
150 for key in self.__dict__.keys():
151 if key == "server_register_idlecallback":
152 state[key] = None
153 else:
154 state[key] = getattr(self, key)
155 return state
156
157 def __setstate__(self,state):
158 for k in state:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500159 setattr(self, k, state[k])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500160
161
162def catch_parse_error(func):
163 """Exception handling bits for our parsing"""
164 @wraps(func)
165 def wrapped(fn, *args):
166 try:
167 return func(fn, *args)
168 except IOError as exc:
169 import traceback
170 parselog.critical(traceback.format_exc())
171 parselog.critical("Unable to parse %s: %s" % (fn, exc))
172 sys.exit(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500173 except bb.data_smart.ExpansionError as exc:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174 import traceback
175
176 bbdir = os.path.dirname(__file__) + os.sep
177 exc_class, exc, tb = sys.exc_info()
178 for tb in iter(lambda: tb.tb_next, None):
179 # Skip frames in bitbake itself, we only want the metadata
180 fn, _, _, _ = traceback.extract_tb(tb, 1)[0]
181 if not fn.startswith(bbdir):
182 break
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600183 parselog.critical("Unable to parse %s" % fn, exc_info=(exc_class, exc, tb))
184 sys.exit(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500185 except bb.parse.ParseError as exc:
186 parselog.critical(str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187 sys.exit(1)
188 return wrapped
189
190@catch_parse_error
191def parse_config_file(fn, data, include=True):
192 return bb.parse.handle(fn, data, include)
193
194@catch_parse_error
195def _inherit(bbclass, data):
196 bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
197 return data
198
199def findConfigFile(configfile, data):
200 search = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500201 bbpath = data.getVar("BBPATH")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500202 if bbpath:
203 for i in bbpath.split(":"):
204 search.append(os.path.join(i, "conf", configfile))
205 path = os.getcwd()
206 while path != "/":
207 search.append(os.path.join(path, "conf", configfile))
208 path, _ = os.path.split(path)
209
210 for i in search:
211 if os.path.exists(i):
212 return i
213
214 return None
215
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500216#
217# We search for a conf/bblayers.conf under an entry in BBPATH or in cwd working
218# up to /. If that fails, we search for a conf/bitbake.conf in BBPATH.
219#
220
221def findTopdir():
222 d = bb.data.init()
223 bbpath = None
224 if 'BBPATH' in os.environ:
225 bbpath = os.environ['BBPATH']
226 d.setVar('BBPATH', bbpath)
227
228 layerconf = findConfigFile("bblayers.conf", d)
229 if layerconf:
230 return os.path.dirname(os.path.dirname(layerconf))
231 if bbpath:
232 bitbakeconf = bb.utils.which(bbpath, "conf/bitbake.conf")
233 if bitbakeconf:
234 return os.path.dirname(os.path.dirname(bitbakeconf))
235 return None
236
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500237class CookerDataBuilder(object):
238
239 def __init__(self, cookercfg, worker = False):
240
241 self.prefiles = cookercfg.prefile
242 self.postfiles = cookercfg.postfile
243 self.tracking = cookercfg.tracking
244
245 bb.utils.set_context(bb.utils.clean_context())
246 bb.event.set_class_handlers(bb.event.clean_class_handlers())
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600247 self.basedata = bb.data.init()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500248 if self.tracking:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600249 self.basedata.enableTracking()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250
251 # Keep a datastore of the initial environment variables and their
252 # values from when BitBake was launched to enable child processes
253 # to use environment variables which have been cleaned from the
254 # BitBake processes env
255 self.savedenv = bb.data.init()
256 for k in cookercfg.env:
257 self.savedenv.setVar(k, cookercfg.env[k])
258
259 filtered_keys = bb.utils.approved_variables()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600260 bb.data.inheritFromOS(self.basedata, self.savedenv, filtered_keys)
261 self.basedata.setVar("BB_ORIGENV", self.savedenv)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500262
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500263 if worker:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600264 self.basedata.setVar("BB_WORKERCONTEXT", "1")
265
266 self.data = self.basedata
267 self.mcdata = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500268
269 def parseBaseConfiguration(self):
270 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600271 bb.parse.init_parser(self.basedata)
272 self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
273
274 if self.data.getVar("BB_WORKERCONTEXT", False) is None:
275 bb.fetch.fetcher_init(self.data)
276 bb.codeparser.parser_cache_init(self.data)
277
278 bb.event.fire(bb.event.ConfigParsed(), self.data)
279
280 reparse_cnt = 0
281 while self.data.getVar("BB_INVALIDCONF", False) is True:
282 if reparse_cnt > 20:
283 logger.error("Configuration has been re-parsed over 20 times, "
284 "breaking out of the loop...")
285 raise Exception("Too deep config re-parse loop. Check locations where "
286 "BB_INVALIDCONF is being set (ConfigParsed event handlers)")
287 self.data.setVar("BB_INVALIDCONF", False)
288 self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
289 reparse_cnt += 1
290 bb.event.fire(bb.event.ConfigParsed(), self.data)
291
292 bb.parse.init_parser(self.data)
293 self.data_hash = self.data.get_hash()
294 self.mcdata[''] = self.data
295
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500296 multiconfig = (self.data.getVar("BBMULTICONFIG") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 for config in multiconfig:
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500298 mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600299 bb.event.fire(bb.event.ConfigParsed(), mcdata)
300 self.mcdata[config] = mcdata
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500301 if multiconfig:
302 bb.event.fire(bb.event.MultiConfigParsed(self.mcdata), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600303
304 except (SyntaxError, bb.BBHandledException):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500305 raise bb.BBHandledException
306 except bb.data_smart.ExpansionError as e:
307 logger.error(str(e))
308 raise bb.BBHandledException
309 except Exception:
310 logger.exception("Error parsing configuration files")
311 raise bb.BBHandledException
312
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500313 # Create a copy so we can reset at a later date when UIs disconnect
314 self.origdata = self.data
315 self.data = bb.data.createCopy(self.origdata)
316 self.mcdata[''] = self.data
317
318 def reset(self):
319 # We may not have run parseBaseConfiguration() yet
320 if not hasattr(self, 'origdata'):
321 return
322 self.data = bb.data.createCopy(self.origdata)
323 self.mcdata[''] = self.data
324
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500325 def _findLayerConf(self, data):
326 return findConfigFile("bblayers.conf", data)
327
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500328 def parseConfigurationFiles(self, prefiles, postfiles, mc = "default"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600329 data = bb.data.createCopy(self.basedata)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500330 data.setVar("BB_CURRENT_MC", mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500331
332 # Parse files for loading *before* bitbake.conf and any includes
333 for f in prefiles:
334 data = parse_config_file(f, data)
335
336 layerconf = self._findLayerConf(data)
337 if layerconf:
338 parselog.debug(2, "Found bblayers.conf (%s)", layerconf)
339 # By definition bblayers.conf is in conf/ of TOPDIR.
340 # We may have been called with cwd somewhere else so reset TOPDIR
341 data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf)))
342 data = parse_config_file(layerconf, data)
343
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500344 layers = (data.getVar('BBLAYERS') or "").split()
Brad Bishop15ae2502019-06-18 21:44:24 -0400345 broken_layers = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500346
347 data = bb.data.createCopy(data)
348 approved = bb.utils.approved_variables()
Brad Bishop15ae2502019-06-18 21:44:24 -0400349
350 # Check whether present layer directories exist
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500351 for layer in layers:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600352 if not os.path.isdir(layer):
Brad Bishop15ae2502019-06-18 21:44:24 -0400353 broken_layers.append(layer)
354
355 if broken_layers:
356 parselog.critical("The following layer directories do not exist:")
357 for layer in broken_layers:
358 parselog.critical(" %s", layer)
359 parselog.critical("Please check BBLAYERS in %s" % (layerconf))
360 sys.exit(1)
361
362 for layer in layers:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500363 parselog.debug(2, "Adding layer %s", layer)
364 if 'HOME' in approved and '~' in layer:
365 layer = os.path.expanduser(layer)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500366 if layer.endswith('/'):
367 layer = layer.rstrip('/')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500368 data.setVar('LAYERDIR', layer)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600369 data.setVar('LAYERDIR_RE', re.escape(layer))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500370 data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data)
371 data.expandVarref('LAYERDIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600372 data.expandVarref('LAYERDIR_RE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500373
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600374 data.delVar('LAYERDIR_RE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500375 data.delVar('LAYERDIR')
376
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500377 bbfiles_dynamic = (data.getVar('BBFILES_DYNAMIC') or "").split()
378 collections = (data.getVar('BBFILE_COLLECTIONS') or "").split()
379 invalid = []
380 for entry in bbfiles_dynamic:
381 parts = entry.split(":", 1)
382 if len(parts) != 2:
383 invalid.append(entry)
384 continue
385 l, f = parts
386 if l in collections:
387 data.appendVar("BBFILES", " " + f)
388 if invalid:
389 bb.fatal("BBFILES_DYNAMIC entries must be of the form <collection name>:<filename pattern>, not:\n %s" % "\n ".join(invalid))
390
391 layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split())
Brad Bishop19323692019-04-05 15:28:33 -0400392 collections_tmp = collections[:]
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500393 for c in collections:
Brad Bishop19323692019-04-05 15:28:33 -0400394 collections_tmp.remove(c)
395 if c in collections_tmp:
396 bb.fatal("Found duplicated BBFILE_COLLECTIONS '%s', check bblayers.conf or layer.conf to fix it." % c)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500397 compat = set((data.getVar("LAYERSERIES_COMPAT_%s" % c) or "").split())
398 if compat and not (compat & layerseries):
399 bb.fatal("Layer %s is not compatible with the core layer which only supports these series: %s (layer is compatible with %s)"
400 % (c, " ".join(layerseries), " ".join(compat)))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400401 elif not compat and not data.getVar("BB_WORKERCONTEXT"):
402 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))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500403
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500404 if not data.getVar("BBPATH"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500405 msg = "The BBPATH variable is not set"
406 if not layerconf:
407 msg += (" and bitbake did not find a conf/bblayers.conf file in"
408 " the expected location.\nMaybe you accidentally"
409 " invoked bitbake from the wrong directory?")
410 raise SystemExit(msg)
411
412 data = parse_config_file(os.path.join("conf", "bitbake.conf"), data)
413
414 # Parse files for loading *after* bitbake.conf and any includes
415 for p in postfiles:
416 data = parse_config_file(p, data)
417
418 # Handle any INHERITs and inherit the base class
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500419 bbclasses = ["base"] + (data.getVar('INHERIT') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500420 for bbclass in bbclasses:
421 data = _inherit(bbclass, data)
422
423 # Nomally we only register event handlers at the end of parsing .bb files
424 # We register any handlers we've found so far here...
425 for var in data.getVar('__BBHANDLERS', False) or []:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500426 handlerfn = data.getVarFlag(var, "filename", False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600427 if not handlerfn:
428 parselog.critical("Undefined event handler function '%s'" % var)
429 sys.exit(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500430 handlerln = int(data.getVarFlag(var, "lineno", False))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500431 bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500432
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500433 data.setVar('BBINCLUDED',bb.parse.get_file_depends(data))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500434
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600435 return data
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436