blob: 09412e28cf9a6299eccc90042d6d25a6cd2881bb [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# Copyright (C) 2003, 2004 Chris Larson
6# Copyright (C) 2003, 2004 Phil Blundell
7# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8# Copyright (C) 2005 Holger Hans Peter Freyther
9# Copyright (C) 2005 ROAD GmbH
10# Copyright (C) 2006 Richard Purdie
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License version 2 as
14# published by the Free Software Foundation.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License along
22# with this program; if not, write to the Free Software Foundation, Inc.,
23# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025import logging
Patrick Williamsc0f7c042017-02-23 20:41:17 -060026import os
27import re
28import sys
29from functools import wraps
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030import bb
31from bb import data
32import bb.parse
33
34logger = logging.getLogger("BitBake")
35parselog = logging.getLogger("BitBake.Parsing")
36
37class ConfigParameters(object):
38 def __init__(self, argv=sys.argv):
39 self.options, targets = self.parseCommandLine(argv)
40 self.environment = self.parseEnvironment()
41
42 self.options.pkgs_to_build = targets or []
43
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044 for key, val in self.options.__dict__.items():
45 setattr(self, key, val)
46
47 def parseCommandLine(self, argv=sys.argv):
48 raise Exception("Caller must implement commandline option parsing")
49
50 def parseEnvironment(self):
51 return os.environ.copy()
52
53 def updateFromServer(self, server):
54 if not self.options.cmd:
55 defaulttask, error = server.runCommand(["getVariable", "BB_DEFAULT_TASK"])
56 if error:
57 raise Exception("Unable to get the value of BB_DEFAULT_TASK from the server: %s" % error)
58 self.options.cmd = defaulttask or "build"
59 _, error = server.runCommand(["setConfig", "cmd", self.options.cmd])
60 if error:
61 raise Exception("Unable to set configuration option 'cmd' on the server: %s" % error)
62
63 if not self.options.pkgs_to_build:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050064 bbpkgs, error = server.runCommand(["getVariable", "BBTARGETS"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065 if error:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050066 raise Exception("Unable to get the value of BBTARGETS from the server: %s" % error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050067 if bbpkgs:
68 self.options.pkgs_to_build.extend(bbpkgs.split())
69
70 def updateToServer(self, server, environment):
71 options = {}
Brad Bishopd7bf8c12018-02-25 22:55:05 -050072 for o in ["abort", "force", "invalidate_stamp",
73 "verbose", "debug", "dry_run", "dump_signatures",
Patrick Williamsc124f4f2015-09-15 14:41:29 -050074 "debug_domains", "extra_assume_provided", "profile",
Brad Bishopd7bf8c12018-02-25 22:55:05 -050075 "prefile", "postfile", "server_timeout"]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 options[o] = getattr(self.options, o)
77
Brad Bishop6e60e8b2018-02-01 10:27:11 -050078 ret, error = server.runCommand(["updateConfig", options, environment, sys.argv])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050079 if error:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050080 raise Exception("Unable to update the server configuration with local parameters: %s" % error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050081
82 def parseActions(self):
83 # Parse any commandline into actions
84 action = {'action':None, 'msg':None}
85 if self.options.show_environment:
86 if 'world' in self.options.pkgs_to_build:
87 action['msg'] = "'world' is not a valid target for --environment."
88 elif 'universe' in self.options.pkgs_to_build:
89 action['msg'] = "'universe' is not a valid target for --environment."
90 elif len(self.options.pkgs_to_build) > 1:
91 action['msg'] = "Only one target can be used with the --environment option."
92 elif self.options.buildfile and len(self.options.pkgs_to_build) > 0:
93 action['msg'] = "No target should be used with the --environment and --buildfile options."
94 elif len(self.options.pkgs_to_build) > 0:
95 action['action'] = ["showEnvironmentTarget", self.options.pkgs_to_build]
96 else:
97 action['action'] = ["showEnvironment", self.options.buildfile]
98 elif self.options.buildfile is not None:
99 action['action'] = ["buildFile", self.options.buildfile, self.options.cmd]
100 elif self.options.revisions_changed:
101 action['action'] = ["compareRevisions"]
102 elif self.options.show_versions:
103 action['action'] = ["showVersions"]
104 elif self.options.parse_only:
105 action['action'] = ["parseFiles"]
106 elif self.options.dot_graph:
107 if self.options.pkgs_to_build:
108 action['action'] = ["generateDotGraph", self.options.pkgs_to_build, self.options.cmd]
109 else:
110 action['msg'] = "Please specify a package name for dependency graph generation."
111 else:
112 if self.options.pkgs_to_build:
113 action['action'] = ["buildTargets", self.options.pkgs_to_build, self.options.cmd]
114 else:
115 #action['msg'] = "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information."
116 action = None
117 self.options.initialaction = action
118 return action
119
120class CookerConfiguration(object):
121 """
122 Manages build options and configurations for one run
123 """
124
125 def __init__(self):
126 self.debug_domains = []
127 self.extra_assume_provided = []
128 self.prefile = []
129 self.postfile = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500130 self.debug = 0
131 self.cmd = None
132 self.abort = True
133 self.force = False
134 self.profile = False
135 self.nosetscene = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500136 self.setsceneonly = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137 self.invalidate_stamp = False
138 self.dump_signatures = []
139 self.dry_run = False
140 self.tracking = False
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500141 self.xmlrpcinterface = []
142 self.server_timeout = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500143 self.writeeventlog = False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500144 self.server_only = False
145 self.limited_deps = False
Brad Bishop316dfdd2018-06-25 12:45:53 -0400146 self.runall = []
147 self.runonly = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148
149 self.env = {}
150
151 def setConfigParameters(self, parameters):
152 for key in self.__dict__.keys():
153 if key in parameters.options.__dict__:
154 setattr(self, key, parameters.options.__dict__[key])
155 self.env = parameters.environment.copy()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500156
157 def setServerRegIdleCallback(self, srcb):
158 self.server_register_idlecallback = srcb
159
160 def __getstate__(self):
161 state = {}
162 for key in self.__dict__.keys():
163 if key == "server_register_idlecallback":
164 state[key] = None
165 else:
166 state[key] = getattr(self, key)
167 return state
168
169 def __setstate__(self,state):
170 for k in state:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500171 setattr(self, k, state[k])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172
173
174def catch_parse_error(func):
175 """Exception handling bits for our parsing"""
176 @wraps(func)
177 def wrapped(fn, *args):
178 try:
179 return func(fn, *args)
180 except IOError as exc:
181 import traceback
182 parselog.critical(traceback.format_exc())
183 parselog.critical("Unable to parse %s: %s" % (fn, exc))
184 sys.exit(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500185 except bb.data_smart.ExpansionError as exc:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500186 import traceback
187
188 bbdir = os.path.dirname(__file__) + os.sep
189 exc_class, exc, tb = sys.exc_info()
190 for tb in iter(lambda: tb.tb_next, None):
191 # Skip frames in bitbake itself, we only want the metadata
192 fn, _, _, _ = traceback.extract_tb(tb, 1)[0]
193 if not fn.startswith(bbdir):
194 break
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600195 parselog.critical("Unable to parse %s" % fn, exc_info=(exc_class, exc, tb))
196 sys.exit(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500197 except bb.parse.ParseError as exc:
198 parselog.critical(str(exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500199 sys.exit(1)
200 return wrapped
201
202@catch_parse_error
203def parse_config_file(fn, data, include=True):
204 return bb.parse.handle(fn, data, include)
205
206@catch_parse_error
207def _inherit(bbclass, data):
208 bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
209 return data
210
211def findConfigFile(configfile, data):
212 search = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500213 bbpath = data.getVar("BBPATH")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500214 if bbpath:
215 for i in bbpath.split(":"):
216 search.append(os.path.join(i, "conf", configfile))
217 path = os.getcwd()
218 while path != "/":
219 search.append(os.path.join(path, "conf", configfile))
220 path, _ = os.path.split(path)
221
222 for i in search:
223 if os.path.exists(i):
224 return i
225
226 return None
227
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500228#
229# We search for a conf/bblayers.conf under an entry in BBPATH or in cwd working
230# up to /. If that fails, we search for a conf/bitbake.conf in BBPATH.
231#
232
233def findTopdir():
234 d = bb.data.init()
235 bbpath = None
236 if 'BBPATH' in os.environ:
237 bbpath = os.environ['BBPATH']
238 d.setVar('BBPATH', bbpath)
239
240 layerconf = findConfigFile("bblayers.conf", d)
241 if layerconf:
242 return os.path.dirname(os.path.dirname(layerconf))
243 if bbpath:
244 bitbakeconf = bb.utils.which(bbpath, "conf/bitbake.conf")
245 if bitbakeconf:
246 return os.path.dirname(os.path.dirname(bitbakeconf))
247 return None
248
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500249class CookerDataBuilder(object):
250
251 def __init__(self, cookercfg, worker = False):
252
253 self.prefiles = cookercfg.prefile
254 self.postfiles = cookercfg.postfile
255 self.tracking = cookercfg.tracking
256
257 bb.utils.set_context(bb.utils.clean_context())
258 bb.event.set_class_handlers(bb.event.clean_class_handlers())
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600259 self.basedata = bb.data.init()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500260 if self.tracking:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600261 self.basedata.enableTracking()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262
263 # Keep a datastore of the initial environment variables and their
264 # values from when BitBake was launched to enable child processes
265 # to use environment variables which have been cleaned from the
266 # BitBake processes env
267 self.savedenv = bb.data.init()
268 for k in cookercfg.env:
269 self.savedenv.setVar(k, cookercfg.env[k])
270
271 filtered_keys = bb.utils.approved_variables()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600272 bb.data.inheritFromOS(self.basedata, self.savedenv, filtered_keys)
273 self.basedata.setVar("BB_ORIGENV", self.savedenv)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500274
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500275 if worker:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600276 self.basedata.setVar("BB_WORKERCONTEXT", "1")
277
278 self.data = self.basedata
279 self.mcdata = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280
281 def parseBaseConfiguration(self):
282 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600283 bb.parse.init_parser(self.basedata)
284 self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
285
286 if self.data.getVar("BB_WORKERCONTEXT", False) is None:
287 bb.fetch.fetcher_init(self.data)
288 bb.codeparser.parser_cache_init(self.data)
289
290 bb.event.fire(bb.event.ConfigParsed(), self.data)
291
292 reparse_cnt = 0
293 while self.data.getVar("BB_INVALIDCONF", False) is True:
294 if reparse_cnt > 20:
295 logger.error("Configuration has been re-parsed over 20 times, "
296 "breaking out of the loop...")
297 raise Exception("Too deep config re-parse loop. Check locations where "
298 "BB_INVALIDCONF is being set (ConfigParsed event handlers)")
299 self.data.setVar("BB_INVALIDCONF", False)
300 self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles)
301 reparse_cnt += 1
302 bb.event.fire(bb.event.ConfigParsed(), self.data)
303
304 bb.parse.init_parser(self.data)
305 self.data_hash = self.data.get_hash()
306 self.mcdata[''] = self.data
307
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500308 multiconfig = (self.data.getVar("BBMULTICONFIG") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600309 for config in multiconfig:
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500310 mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600311 bb.event.fire(bb.event.ConfigParsed(), mcdata)
312 self.mcdata[config] = mcdata
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500313 if multiconfig:
314 bb.event.fire(bb.event.MultiConfigParsed(self.mcdata), self.data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600315
316 except (SyntaxError, bb.BBHandledException):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500317 raise bb.BBHandledException
318 except bb.data_smart.ExpansionError as e:
319 logger.error(str(e))
320 raise bb.BBHandledException
321 except Exception:
322 logger.exception("Error parsing configuration files")
323 raise bb.BBHandledException
324
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500325 # Create a copy so we can reset at a later date when UIs disconnect
326 self.origdata = self.data
327 self.data = bb.data.createCopy(self.origdata)
328 self.mcdata[''] = self.data
329
330 def reset(self):
331 # We may not have run parseBaseConfiguration() yet
332 if not hasattr(self, 'origdata'):
333 return
334 self.data = bb.data.createCopy(self.origdata)
335 self.mcdata[''] = self.data
336
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500337 def _findLayerConf(self, data):
338 return findConfigFile("bblayers.conf", data)
339
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500340 def parseConfigurationFiles(self, prefiles, postfiles, mc = "default"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600341 data = bb.data.createCopy(self.basedata)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500342 data.setVar("BB_CURRENT_MC", mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500343
344 # Parse files for loading *before* bitbake.conf and any includes
345 for f in prefiles:
346 data = parse_config_file(f, data)
347
348 layerconf = self._findLayerConf(data)
349 if layerconf:
350 parselog.debug(2, "Found bblayers.conf (%s)", layerconf)
351 # By definition bblayers.conf is in conf/ of TOPDIR.
352 # We may have been called with cwd somewhere else so reset TOPDIR
353 data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf)))
354 data = parse_config_file(layerconf, data)
355
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500356 layers = (data.getVar('BBLAYERS') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500357
358 data = bb.data.createCopy(data)
359 approved = bb.utils.approved_variables()
360 for layer in layers:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600361 if not os.path.isdir(layer):
362 parselog.critical("Layer directory '%s' does not exist! "
363 "Please check BBLAYERS in %s" % (layer, layerconf))
364 sys.exit(1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500365 parselog.debug(2, "Adding layer %s", layer)
366 if 'HOME' in approved and '~' in layer:
367 layer = os.path.expanduser(layer)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500368 if layer.endswith('/'):
369 layer = layer.rstrip('/')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500370 data.setVar('LAYERDIR', layer)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600371 data.setVar('LAYERDIR_RE', re.escape(layer))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500372 data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data)
373 data.expandVarref('LAYERDIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600374 data.expandVarref('LAYERDIR_RE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500375
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600376 data.delVar('LAYERDIR_RE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500377 data.delVar('LAYERDIR')
378
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500379 bbfiles_dynamic = (data.getVar('BBFILES_DYNAMIC') or "").split()
380 collections = (data.getVar('BBFILE_COLLECTIONS') or "").split()
381 invalid = []
382 for entry in bbfiles_dynamic:
383 parts = entry.split(":", 1)
384 if len(parts) != 2:
385 invalid.append(entry)
386 continue
387 l, f = parts
388 if l in collections:
389 data.appendVar("BBFILES", " " + f)
390 if invalid:
391 bb.fatal("BBFILES_DYNAMIC entries must be of the form <collection name>:<filename pattern>, not:\n %s" % "\n ".join(invalid))
392
393 layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split())
Brad Bishop19323692019-04-05 15:28:33 -0400394 collections_tmp = collections[:]
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500395 for c in collections:
Brad Bishop19323692019-04-05 15:28:33 -0400396 collections_tmp.remove(c)
397 if c in collections_tmp:
398 bb.fatal("Found duplicated BBFILE_COLLECTIONS '%s', check bblayers.conf or layer.conf to fix it." % c)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500399 compat = set((data.getVar("LAYERSERIES_COMPAT_%s" % c) or "").split())
400 if compat and not (compat & layerseries):
401 bb.fatal("Layer %s is not compatible with the core layer which only supports these series: %s (layer is compatible with %s)"
402 % (c, " ".join(layerseries), " ".join(compat)))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400403 elif not compat and not data.getVar("BB_WORKERCONTEXT"):
404 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 -0500405
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500406 if not data.getVar("BBPATH"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407 msg = "The BBPATH variable is not set"
408 if not layerconf:
409 msg += (" and bitbake did not find a conf/bblayers.conf file in"
410 " the expected location.\nMaybe you accidentally"
411 " invoked bitbake from the wrong directory?")
412 raise SystemExit(msg)
413
414 data = parse_config_file(os.path.join("conf", "bitbake.conf"), data)
415
416 # Parse files for loading *after* bitbake.conf and any includes
417 for p in postfiles:
418 data = parse_config_file(p, data)
419
420 # Handle any INHERITs and inherit the base class
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500421 bbclasses = ["base"] + (data.getVar('INHERIT') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500422 for bbclass in bbclasses:
423 data = _inherit(bbclass, data)
424
425 # Nomally we only register event handlers at the end of parsing .bb files
426 # We register any handlers we've found so far here...
427 for var in data.getVar('__BBHANDLERS', False) or []:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500428 handlerfn = data.getVarFlag(var, "filename", False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600429 if not handlerfn:
430 parselog.critical("Undefined event handler function '%s'" % var)
431 sys.exit(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500432 handlerln = int(data.getVarFlag(var, "lineno", False))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500433 bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500434
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435 data.setVar('BBINCLUDED',bb.parse.get_file_depends(data))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600437 return data
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500438