diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-04-10 11:09:21 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-04-12 22:50:21 +0100 |
commit | e0e5426659011e85a5272e2f7f703c1c5e874755 (patch) | |
tree | 96c1d06863674173d61b4e048f301e88322ced1f /bitbake/lib/bb/runqueue.py | |
parent | 380004b8551d1992eec244928c524252c47f7970 (diff) | |
download | poky-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/lib/bb/runqueue.py')
-rw-r--r-- | bitbake/lib/bb/runqueue.py | 72 |
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 |