summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2016-04-10 11:09:21 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-04-12 22:50:21 +0100
commite0e5426659011e85a5272e2f7f703c1c5e874755 (patch)
tree96c1d06863674173d61b4e048f301e88322ced1f /bitbake
parent380004b8551d1992eec244928c524252c47f7970 (diff)
downloadpoky-e0e5426659011e85a5272e2f7f703c1c5e874755.tar.gz
bitbake: runqueue: Improve 'mulitiple .bb files are due to be built' message
When multiple recipes which both provide something are being built, bitbake informs us that most likely one of them provides something the other doesn't, which is usually correct, but unfortunately it's rather painful to figure out exactly what that is. This patch dumps two sets of information, one is the provides information for each recipe, filtered so only common components are removed. The other is a list of dependees on the recipe, since sometimes this can easily identify why something is being built. Its not straightforward for bitbake to obtain the information but since the warning/error code path isn't the normal one, we can afford to go through some less than optimal processing to aid debugging. Also provide the same information even if we're showing a warning since its still useful. [YOCTO #8032] (Bitbake rev: 96fc889b8e62ba4463c71158c4b7286c48d68cd8) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/bb/runqueue.py72
1 files changed, 70 insertions, 2 deletions
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py
index 946aa980d3..e1b9b2e661 100644
--- a/bitbake/lib/bb/runqueue.py
+++ b/bitbake/lib/bb/runqueue.py
@@ -261,6 +261,13 @@ class RunQueueData:
261 taskname = self.runq_task[task] + task_name_suffix 261 taskname = self.runq_task[task] + task_name_suffix
262 return "%s, %s" % (fn, taskname) 262 return "%s, %s" % (fn, taskname)
263 263
264 def get_short_user_idstring(self, task, task_name_suffix = ""):
265 fn = self.taskData.fn_index[self.runq_fnid[task]]
266 pn = self.dataCache.pkg_fn[fn]
267 taskname = self.runq_task[task] + task_name_suffix
268 return "%s:%s" % (pn, taskname)
269
270
264 def get_task_id(self, fnid, taskname): 271 def get_task_id(self, fnid, taskname):
265 for listid in xrange(len(self.runq_fnid)): 272 for listid in xrange(len(self.runq_fnid)):
266 if self.runq_fnid[listid] == fnid and self.runq_task[listid] == taskname: 273 if self.runq_fnid[listid] == fnid and self.runq_task[listid] == taskname:
@@ -753,11 +760,72 @@ class RunQueueData:
753 seen_pn.append(pn) 760 seen_pn.append(pn)
754 else: 761 else:
755 bb.fatal("Multiple versions of %s are due to be built (%s). Only one version of a given PN should be built in any given build. You likely need to set PREFERRED_VERSION_%s to select the correct version or don't depend on multiple versions." % (pn, " ".join(prov_list[prov]), pn)) 762 bb.fatal("Multiple versions of %s are due to be built (%s). Only one version of a given PN should be built in any given build. You likely need to set PREFERRED_VERSION_%s to select the correct version or don't depend on multiple versions." % (pn, " ".join(prov_list[prov]), pn))
756 msg = "Multiple .bb files are due to be built which each provide %s (%s)." % (prov, " ".join(prov_list[prov])) 763 msg = "Multiple .bb files are due to be built which each provide %s:\n %s" % (prov, "\n ".join(prov_list[prov]))
764 #
765 # Construct a list of things which uniquely depend on each provider
766 # since this may help the user figure out which dependency is triggering this warning
767 #
768 msg += "\nA list of tasks depending on these providers is shown and may help explain where the dependency comes from."
769 deplist = {}
770 commondeps = None
771 for provfn in prov_list[prov]:
772 deps = set()
773 for task, fnid in enumerate(self.runq_fnid):
774 fn = taskData.fn_index[fnid]
775 if fn != provfn:
776 continue
777 for dep in self.runq_revdeps[task]:
778 fn = taskData.fn_index[self.runq_fnid[dep]]
779 if fn == provfn:
780 continue
781 deps.add(self.get_short_user_idstring(dep))
782 if not commondeps:
783 commondeps = set(deps)
784 else:
785 commondeps &= deps
786 deplist[provfn] = deps
787 for provfn in deplist:
788 msg += "\n%s has unique dependees:\n %s" % (provfn, "\n ".join(deplist[provfn] - commondeps))
789 #
790 # Construct a list of provides and runtime providers for each recipe
791 # (rprovides has to cover RPROVIDES, PACKAGES, PACKAGES_DYNAMIC)
792 #
793 msg += "\nIt could be that one recipe provides something the other doesn't and should. The following provider and runtime provider differences may be helpful."
794 provide_results = {}
795 rprovide_results = {}
796 commonprovs = None
797 commonrprovs = None
798 for provfn in prov_list[prov]:
799 provides = set(self.dataCache.fn_provides[provfn])
800 rprovides = set()
801 for rprovide in self.dataCache.rproviders:
802 if provfn in self.dataCache.rproviders[rprovide]:
803 rprovides.add(rprovide)
804 for package in self.dataCache.packages:
805 if provfn in self.dataCache.packages[package]:
806 rprovides.add(package)
807 for package in self.dataCache.packages_dynamic:
808 if provfn in self.dataCache.packages_dynamic[package]:
809 rprovides.add(package)
810 if not commonprovs:
811 commonprovs = set(provides)
812 else:
813 commonprovs &= provides
814 provide_results[provfn] = provides
815 if not commonrprovs:
816 commonrprovs = set(rprovides)
817 else:
818 commonrprovs &= rprovides
819 rprovide_results[provfn] = rprovides
820 #msg += "\nCommon provides:\n %s" % ("\n ".join(commonprovs))
821 #msg += "\nCommon rprovides:\n %s" % ("\n ".join(commonrprovs))
822 for provfn in prov_list[prov]:
823 msg += "\n%s has unique provides:\n %s" % (provfn, "\n ".join(provide_results[provfn] - commonprovs))
824 msg += "\n%s has unique rprovides:\n %s" % (provfn, "\n ".join(rprovide_results[provfn] - commonrprovs))
825
757 if self.warn_multi_bb: 826 if self.warn_multi_bb:
758 logger.warn(msg) 827 logger.warn(msg)
759 else: 828 else:
760 msg += "\n This usually means one provides something the other doesn't and should."
761 logger.error(msg) 829 logger.error(msg)
762 830
763 # Create a whitelist usable by the stamp checks 831 # Create a whitelist usable by the stamp checks