bitbake: show more information for NoProvider errors

"Nothing PROVIDES" errors often come up when a recipe has been skipped
for some reason, and therefore it is useful to print out that reason
information when showing the error so that the user understands why the
error has occurred.

Given that we already feed the reason information into the skiplist for
various situations (COMMERCIAL_LICENSE, COMPATIBLE_MACHINE etc.) this
should now output a useful error message for skipped recipes.

Fixes [YOCTO #846], [YOCTO #1127]

(Bitbake rev: 6765218430e31c165888f26fbc75023c89a6eab2)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Paul Eggleton 2011-07-25 14:54:41 +01:00 committed by Richard Purdie
parent 60218d19f7
commit daed107ce1
5 changed files with 34 additions and 9 deletions

View File

@ -43,7 +43,7 @@ except ImportError:
logger.info("Importing cPickle failed. "
"Falling back to a very slow implementation.")
__cache_version__ = "141"
__cache_version__ = "142"
def getCacheFile(path, filename):
return os.path.join(path, filename)
@ -99,6 +99,7 @@ class CoreRecipeInfo(RecipeInfoCommon):
self.skipreason = self.getvar('__SKIPPED', metadata)
if self.skipreason:
self.pn = self.getvar('PN', metadata) or bb.parse.BBHandler.vars_from_file(filename,metadata)[0]
self.skipped = True
self.provides = self.depvar('PROVIDES', metadata)
self.rprovides = self.depvar('RPROVIDES', metadata)

View File

@ -59,11 +59,13 @@ class state:
class SkippedPackage:
def __init__(self, info = None, reason = None):
self.pn = None
self.skipreason = None
self.provides = None
self.rprovides = None
if info:
self.pn = info.pn
self.skipreason = info.skipreason
self.provides = info.provides
self.rprovides = info.rprovides
@ -328,7 +330,7 @@ class BBCooker:
bb.data.expandKeys(localdata)
# We set abort to False here to prevent unbuildable targets raising
# an exception when we're just generating data
taskdata = bb.taskdata.TaskData(False)
taskdata = bb.taskdata.TaskData(False, skiplist=self.skiplist)
runlist = []
for k in pkgs_to_build:
@ -1060,7 +1062,7 @@ class BBCooker:
bb.data.update_data(localdata)
bb.data.expandKeys(localdata)
taskdata = bb.taskdata.TaskData(self.configuration.abort)
taskdata = bb.taskdata.TaskData(self.configuration.abort, skiplist=self.skiplist)
runlist = []
for k in targets:

View File

@ -287,11 +287,12 @@ class BuildCompleted(BuildBase):
class NoProvider(Event):
"""No Provider for an Event"""
def __init__(self, item, runtime=False, dependees=None):
def __init__(self, item, runtime=False, dependees=None, reasons=[]):
Event.__init__(self)
self._item = item
self._runtime = runtime
self._dependees = dependees
self._reasons = reasons
def getItem(self):
return self._item

View File

@ -41,7 +41,7 @@ class TaskData:
"""
BitBake Task Data implementation
"""
def __init__(self, abort = True, tryaltconfigs = False):
def __init__(self, abort = True, tryaltconfigs = False, skiplist = None):
self.build_names_index = []
self.run_names_index = []
self.fn_index = []
@ -70,6 +70,8 @@ class TaskData:
self.abort = abort
self.tryaltconfigs = tryaltconfigs
self.skiplist = skiplist
def getbuild_id(self, name):
"""
Return an ID number for the build target name.
@ -348,6 +350,22 @@ class TaskData:
dependees.append(self.fn_index[fnid])
return dependees
def get_reasons(self, item, runtime=False):
"""
Get the reason(s) for an item not being provided, if any
"""
reasons = []
if self.skiplist:
for fn in self.skiplist:
skipitem = self.skiplist[fn]
if skipitem.pn == item:
reasons.append("%s was skipped: %s" % (skipitem.pn, skipitem.skipreason))
elif runtime and item in skipitem.rprovides:
reasons.append("%s RPROVIDES %s but was skipped: %s" % (skipitem.pn, item, skipitem.skipreason))
elif not runtime and item in skipitem.provides:
reasons.append("%s PROVIDES %s but was skipped: %s" % (skipitem.pn, item, skipitem.skipreason))
return reasons
def add_provider(self, cfgData, dataCache, item):
try:
self.add_provider_internal(cfgData, dataCache, item)
@ -369,7 +387,7 @@ class TaskData:
return
if not item in dataCache.providers:
bb.event.fire(bb.event.NoProvider(item, dependees=self.get_rdependees_str(item)), cfgData)
bb.event.fire(bb.event.NoProvider(item, dependees=self.get_rdependees_str(item), reasons=self.get_reasons(item)), cfgData)
raise bb.providers.NoProvider(item)
if self.have_build_target(item):
@ -381,7 +399,7 @@ class TaskData:
eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids]
if not eligible:
bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees_str(item)), cfgData)
bb.event.fire(bb.event.NoProvider(item, dependees=self.get_dependees_str(item), reasons=["No eligible PROVIDERs exist for '%s'" % item]), cfgData)
raise bb.providers.NoProvider(item)
if len(eligible) > 1 and foundUnique == False:
@ -418,14 +436,14 @@ class TaskData:
all_p = bb.providers.getRuntimeProviders(dataCache, item)
if not all_p:
bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees_str(item)), cfgData)
bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees_str(item), reasons=self.get_reasons(item, True)), cfgData)
raise bb.providers.NoRProvider(item)
eligible, numberPreferred = bb.providers.filterProvidersRunTime(all_p, item, cfgData, dataCache)
eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids]
if not eligible:
bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees_str(item)), cfgData)
bb.event.fire(bb.event.NoProvider(item, runtime=True, dependees=self.get_rdependees_str(item), reasons=["No eligible RPROVIDERs exist for '%s'" % item]), cfgData)
raise bb.providers.NoRProvider(item)
if len(eligible) > 1 and numberPreferred == 0:

View File

@ -208,6 +208,9 @@ def main(server, eventHandler):
logger.error("Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)", r, event._item, ", ".join(event._dependees), r)
else:
logger.error("Nothing %sPROVIDES '%s'", r, event._item)
if event._reasons:
for reason in event._reasons:
logger.error("%s", reason)
continue
if isinstance(event, bb.runqueue.runQueueTaskStarted):