ass="bp">self.data.setVar("BB_INVALIDCONF", False) self.data = self.parseConfigurationFiles(self.prefiles, self.postfiles) reparse_cnt += 1 bb.event.fire(bb.event.ConfigParsed(), self.data) bb.parse.init_parser(self.data) data_hash.update(self.data.get_hash().encode('utf-8')) mcdata[''] = self.data multiconfig = (self.data.getVar("BBMULTICONFIG") or "").split() for config in multiconfig: if config[0].isdigit(): bb.fatal("Multiconfig name '%s' is invalid as multiconfigs cannot start with a digit" % config) parsed_mcdata = self.parseConfigurationFiles(self.prefiles, self.postfiles, config) bb.event.fire(bb.event.ConfigParsed(), parsed_mcdata) mcdata[config] = parsed_mcdata data_hash.update(parsed_mcdata.get_hash().encode('utf-8')) if multiconfig: bb.event.fire(bb.event.MultiConfigParsed(mcdata), self.data) self.data_hash = data_hash.hexdigest() except bb.data_smart.ExpansionError as e: logger.error(str(e)) raise bb.BBHandledException() bb.codeparser.update_module_dependencies(self.data) # Handle obsolete variable names d = self.data renamedvars = d.getVarFlags('BB_RENAMED_VARIABLES') or {} renamedvars.update(bb.data_smart.bitbake_renamed_vars) issues = False for v in renamedvars: if d.getVar(v) != None or d.hasOverrides(v): issues = True loginfo = {} history = d.varhistory.get_variable_refs(v) for h in history: for line in history[h]: loginfo = {'file' : h, 'line' : line} bb.data.data_smart._print_rename_error(v, loginfo, renamedvars) if not history: bb.data.data_smart._print_rename_error(v, loginfo, renamedvars) if issues: raise bb.BBHandledException() for mc in mcdata: mcdata[mc].renameVar("__depends", "__base_depends") mcdata[mc].setVar("__bbclasstype", "recipe") # Create a copy so we can reset at a later date when UIs disconnect self.mcorigdata = mcdata for mc in mcdata: self.mcdata[mc] = bb.data.createCopy(mcdata[mc]) self.data = self.mcdata[''] def reset(self): # We may not have run parseBaseConfiguration() yet if not hasattr(self, 'mcorigdata'): return for mc in self.mcorigdata: self.mcdata[mc] = bb.data.createCopy(self.mcorigdata[mc]) self.data = self.mcdata[''] def _findLayerConf(self, data): return findConfigFile("bblayers.conf", data) def parseConfigurationFiles(self, prefiles, postfiles, mc = "default"): data = bb.data.createCopy(self.basedata) data.setVar("BB_CURRENT_MC", mc) # Parse files for loading *before* bitbake.conf and any includes for f in prefiles: data = parse_config_file(f, data) layerconf = self._findLayerConf(data) if layerconf: parselog.debug2("Found bblayers.conf (%s)", layerconf) # By definition bblayers.conf is in conf/ of TOPDIR. # We may have been called with cwd somewhere else so reset TOPDIR data.setVar("TOPDIR", os.path.dirname(os.path.dirname(layerconf))) data = parse_config_file(layerconf, data) if not data.getVar("BB_CACHEDIR"): data.setVar("BB_CACHEDIR", "${TOPDIR}/cache") bb.codeparser.parser_cache_init(data.getVar("BB_CACHEDIR")) layers = (data.getVar('BBLAYERS') or "").split() broken_layers = [] if not layers: bb.fatal("The bblayers.conf file doesn't contain any BBLAYERS definition") data = bb.data.createCopy(data) approved = bb.utils.approved_variables() # Check whether present layer directories exist for layer in layers: if not os.path.isdir(layer): broken_layers.append(layer) if broken_layers: parselog.critical("The following layer directories do not exist:") for layer in broken_layers: parselog.critical(" %s", layer) parselog.critical("Please check BBLAYERS in %s" % (layerconf)) raise bb.BBHandledException() layerseries = None compat_entries = {} for layer in layers: parselog.debug2("Adding layer %s", layer) if 'HOME' in approved and '~' in layer: layer = os.path.expanduser(layer) if layer.endswith('/'): layer = layer.rstrip('/') data.setVar('LAYERDIR', layer) data.setVar('LAYERDIR_RE', re.escape(layer)) data = parse_config_file(os.path.join(layer, "conf", "layer.conf"), data) data.expandVarref('LAYERDIR') data.expandVarref('LAYERDIR_RE') # Sadly we can't have nice things. # Some layers think they're going to be 'clever' and copy the values from # another layer, e.g. using ${LAYERSERIES_COMPAT_core}. The whole point of # this mechanism is to make it clear which releases a layer supports and # show when a layer master branch is bitrotting and is unmaintained. # We therefore avoid people doing this here. collections = (data.getVar('BBFILE_COLLECTIONS') or "").split() for c in collections: compat_entry = data.getVar("LAYERSERIES_COMPAT_%s" % c) if compat_entry: compat_entries[c] = set(compat_entry.split()) data.delVar("LAYERSERIES_COMPAT_%s" % c) if not layerseries: layerseries = set((data.getVar("LAYERSERIES_CORENAMES") or "").split()) if layerseries: data.delVar("LAYERSERIES_CORENAMES") data.delVar('LAYERDIR_RE') data.delVar('LAYERDIR') for c in compat_entries: data.setVar("LAYERSERIES_COMPAT_%s" % c, " ".join(sorted(compat_entries[c]))) bbfiles_dynamic = (data.getVar('BBFILES_DYNAMIC') or "").split() collections = (data.getVar('BBFILE_COLLECTIONS') or "").split() invalid = [] for entry in bbfiles_dynamic: parts = entry.split(":", 1) if len(parts) != 2: invalid.append(entry) continue l, f = parts invert = l[0] == "!" if invert: l = l[1:] if (l in collections and not invert) or (l not in collections and invert): data.appendVar("BBFILES", " " + f) if invalid: bb.fatal("BBFILES_DYNAMIC entries must be of the form {!}<collection name>:<filename pattern>, not:\n %s" % "\n ".join(invalid)) collections_tmp = collections[:] for c in collections: collections_tmp.remove(c) if c in collections_tmp: bb.fatal("Found duplicated BBFILE_COLLECTIONS '%s', check bblayers.conf or layer.conf to fix it." % c) compat = set() if c in compat_entries: compat = compat_entries[c] if compat and not layerseries: bb.fatal("No core layer found to work with layer '%s'. Missing entry in bblayers.conf?" % c) if compat and not (compat & layerseries): bb.fatal("Layer %s is not compatible with the core layer which only supports these series: %s (layer is compatible with %s)" % (c, " ".join(layerseries), " ".join(compat))) elif not compat and not data.getVar("BB_WORKERCONTEXT"): 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)) data.setVar("LAYERSERIES_CORENAMES", " ".join(sorted(layerseries))) if not data.getVar("BBPATH"): msg = "The BBPATH variable is not set" if not layerconf: msg += (" and bitbake did not find a conf/bblayers.conf file in" " the expected location.\nMaybe you accidentally" " invoked bitbake from the wrong directory?") bb.fatal(msg) if not data.getVar("TOPDIR"): data.setVar("TOPDIR", os.path.abspath(os.getcwd())) if not data.getVar("BB_CACHEDIR"): data.setVar("BB_CACHEDIR", "${TOPDIR}/cache") bb.codeparser.parser_cache_init(data.getVar("BB_CACHEDIR")) data = parse_config_file(os.path.join("conf", "bitbake.conf"), data) # Parse files for loading *after* bitbake.conf and any includes for p in postfiles: data = parse_config_file(p, data) # Handle any INHERITs and inherit the base class bbclasses = ["base"] + (data.getVar('INHERIT') or "").split() for bbclass in bbclasses: data = _inherit(bbclass, data) # Normally we only register event handlers at the end of parsing .bb files # We register any handlers we've found so far here... for var in data.getVar('__BBHANDLERS', False) or []: handlerfn = data.getVarFlag(var, "filename", False) if not handlerfn: parselog.critical("Undefined event handler function '%s'" % var) raise bb.BBHandledException() handlerln = int(data.getVarFlag(var, "lineno", False)) bb.event.register(var, data.getVar(var, False), (data.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln, data) data.setVar('BBINCLUDED',bb.parse.get_file_depends(data)) return data @staticmethod def _parse_recipe(bb_data, bbfile, appends, mc, layername): bb_data.setVar("__BBMULTICONFIG", mc) bb_data.setVar("FILE_LAYERNAME", layername) bbfile_loc = os.path.abspath(os.path.dirname(bbfile)) bb.parse.cached_mtime_noerror(bbfile_loc) if appends: bb_data.setVar('__BBAPPEND', " ".join(appends)) return bb.parse.handle(bbfile, bb_data) def parseRecipeVariants(self, bbfile, appends, virtonly=False, mc=None, layername=None): """ Load and parse one .bb build file Return the data and whether parsing resulted in the file being skipped """ if virtonly: (bbfile, virtual, mc) = bb.cache.virtualfn2realfn(bbfile) bb_data = self.mcdata[mc].createCopy() bb_data.setVar("__ONLYFINALISE", virtual or "default") return self._parse_recipe(bb_data, bbfile, appends, mc, layername) if mc is not None: bb_data = self.mcdata[mc].createCopy() return self._parse_recipe(bb_data, bbfile, appends, mc, layername) bb_data = self.data.createCopy() datastores = self._parse_recipe(bb_data, bbfile, appends, '', layername) for mc in self.mcdata: if not mc: continue bb_data = self.mcdata[mc].createCopy() newstores = self._parse_recipe(bb_data, bbfile, appends, mc, layername) for ns in newstores: datastores["mc:%s:%s" % (mc, ns)] = newstores[ns] return datastores def parseRecipe(self, virtualfn, appends, layername): """ Return a complete set of data for fn. To do this, we need to parse the file. """ logger.debug("Parsing %s (full)" % virtualfn) (fn, virtual, mc) = bb.cache.virtualfn2realfn(virtualfn) datastores = self.parseRecipeVariants(virtualfn, appends, virtonly=True, layername=layername) return datastores[virtual]