I have seen this bug happen in the dlang overlay with the dev-lang/ldc2 package. Since it is slotted, it IDEPENDs on app-eselect/eselect-dlang to provide symlinks. Since it is written in D, it requires a D compiler to both compile and provide a runtime so. This may lead to ldc2 RDEPENDing on ldc2 (possibly the same version) and IDEPEND on eselect-dlang. The bug arises when trying to depclean ldc2 along with eselect-dlang. The order should be: 1. dev-lang/ldc2 2. app-eselect/eselect-dlang yet emerge chooses the reverse: 1. app-eselect/eselect-dlang 2. dev-lang/ldc2 This leads to ldc2 not being able to call the eselect dlang module which leads to broken symlinks. An example of such a situation: ------------- $ emerge -c ldc2 eselect-dlang Calculating dependencies... done! >>> Calculating removal order... app-eselect/eselect-dlang selected: 20190608 protected: none omitted: none dev-lang/ldc2 selected: 1.35.0 protected: none omitted: none All selected packages: =app-eselect/eselect-dlang-20190608 =dev-lang/ldc2-1.35.0 >>> 'Selected' packages are slated for removal. >>> 'Protected' and 'omitted' packages will not be removed. >>> Waiting 5 seconds before starting... >>> (Control-C to abort)... >>> Unmerging in: 5 4 3 2 1 >>> Unmerging (1 of 2) app-eselect/eselect-dlang-20190608... >>> Unmerging (2 of 2) dev-lang/ldc2-1.35.0... !!! Error: Can't load module dlang Packages installed: 386 Packages in world: 30 Packages in system: 50 Required packages: 386 Number removed: 2 * GNU info directory index is up-to-date. ------------- The dependencies of the 2 packages in the above case: ------------- $ qdepends -v ldc2 eselect-dlang dev-lang/ldc2-1.35.0: DEPEND=" || ( sys-devel/llvm:16 sys-devel/llvm:15 sys-devel/llvm:14 ) <sys-devel/llvm-17:16/16= !!sys-devel/llvm:0 dev-lang/ldc2:1.35/0= " RDEPEND=" || ( sys-devel/llvm:16 sys-devel/llvm:15 sys-devel/llvm:14 ) <sys-devel/llvm-17:16/16= >=app-eselect/eselect-dlang-20140709 dev-lang/ldc2:1.35/0= " BDEPEND=" dev-util/ninja >=dev-util/ninja-1.8.2 >=dev-util/cmake-3.20.5 " IDEPEND=" >=app-eselect/eselect-dlang-20140709 " app-eselect/eselect-dlang-20190608: RDEPEND=" app-admin/eselect " ------------- As a small note, versions of ldc2 before 1.35.0 are affected in the same way, though they specify app-eselect/eselect-dlang as a RDEPEND due to EAPI=7. The above test can be simplified to (as a python portage unittest): ------------- def testIDEPENDDepclean(self): ebuilds = { "dev-util/A-1": {}, "dev-libs/B-1": { "EAPI": "8", "IDEPEND": "dev-util/A", "RDEPEND": "dev-libs/B:=", }, "dev-libs/C-1": {}, } installed = { "dev-util/A-1": {}, "dev-libs/B-1": { "EAPI": "8", "IDEPEND": "dev-util/A", "RDEPEND": "dev-libs/B:0/0=", }, "dev-libs/C-1": {}, } world = ('dev-libs/C',) test_cases = ( # Remove dev-libs/B first because it IDEPENDs on dev-util/A ResolverPlaygroundTestCase( [], options={"--depclean": True}, success=True, ordered=True, cleanlist=[ "dev-libs/B-1", "dev-util/A-1", ], ), ) playground = ResolverPlayground( ebuilds=ebuilds, installed=installed, world=world ) try: for test_case in test_cases: playground.run_TestCase(test_case) self.assertEqual(test_case.test_success, True, test_case.fail_msg) finally: playground.cleanup() ------------- Interestingly, removing the := operator leads to the test sometimes failing and sometimes passing, i.e. the remove order becomes inconsistent.
In https://github.com/gentoo/portage/pull/1212 I've handled direct circular dependencies, but it is possible that indirect circular dependencies may still trigger problems with the unmerge order (for example if there was a virtual/ldc2 which made this an indirect circular dependency).
The bug has been referenced in the following commit(s): https://gitweb.gentoo.org/proj/portage.git/commit/?id=bf3d091de8702f0c95e5530d03c6e925008ee80a commit bf3d091de8702f0c95e5530d03c6e925008ee80a Author: Zac Medico <zmedico@gentoo.org> AuthorDate: 2023-12-24 05:12:55 +0000 Commit: Zac Medico <zmedico@gentoo.org> CommitDate: 2023-12-24 19:29:25 +0000 depclean: drop direct circular deps in merge order calculation Drop direct circular deps in the depclean merge order calculation, since it does not handle them well as shown by the test case for bug 916135. Bug: https://bugs.gentoo.org/916135 Signed-off-by: Zac Medico <zmedico@gentoo.org> lib/_emerge/actions.py | 8 ++++++-- lib/portage/tests/resolver/test_depclean_order.py | 10 ++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) https://gitweb.gentoo.org/proj/portage.git/commit/?id=eeb4c29a64927efbaa7028153230367651bcf3b7 commit eeb4c29a64927efbaa7028153230367651bcf3b7 Author: Andrei Horodniceanu <a.horodniceanu@proton.me> AuthorDate: 2023-10-21 14:38:36 +0000 Commit: Zac Medico <zmedico@gentoo.org> CommitDate: 2023-12-24 19:29:16 +0000 tests/resolver: test depclean order with IDEPEND and circular deps Bug: https://bugs.gentoo.org/916135 Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me> Closes: https://github.com/gentoo/portage/pull/1147 Signed-off-by: Zac Medico <zmedico@gentoo.org> lib/portage/tests/resolver/test_depclean_order.py | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+)
(In reply to Zac Medico from comment #1) > In https://github.com/gentoo/portage/pull/1212 I've handled direct circular > dependencies, but it is possible that indirect circular dependencies may > still trigger problems with the unmerge order (for example if there was a > virtual/ldc2 which made this an indirect circular dependency). You can get indirect circular dependencies by having 2 ldc2 versions build each other, for example ldc2:1.35 was built with ldc2:1.34 and ldc2:1.34 was built with ldc2:1.35. As you guessed, the unmerge order is the wrong one because of the 1-layer indirection.
To handle indirect circular dependencies, we can increase the priority of IDEPEND relative to RDEPEND. Here's a test case that shows the incorrect order: def testCircularDepclean(self): """ Test for bug 916135, where an indirect circular dependency caused the unmerge order to fail to account for IDEPEND. """ ebuilds = { "dev-util/A-1": {}, "dev-libs/B-1": { "EAPI": "8", "SLOT": "1", "IDEPEND": "dev-util/A", "RDEPEND": "dev-libs/B:=", }, "dev-libs/B-2": { "EAPI": "8", "SLOT": "2", "IDEPEND": "dev-util/A", "RDEPEND": "dev-libs/B:=", }, "dev-libs/C-1": {}, } installed = { "dev-util/A-1": {}, "dev-libs/B-1": { "EAPI": "8", "SLOT": "1", "IDEPEND": "dev-util/A", "RDEPEND": "dev-libs/B:2/2=", }, "dev-libs/B-2": { "EAPI": "8", "SLOT": "2", "IDEPEND": "dev-util/A", "RDEPEND": "dev-libs/B:1/1=", }, "dev-libs/C-1": {}, } world = ("dev-libs/C",) test_cases = ( # Remove dev-libs/B first because it IDEPENDs on dev-util/A ResolverPlaygroundTestCase( [], options={"--depclean": True}, success=True, ordered=True, cleanlist=["dev-util/A-1", "dev-libs/B-1", "dev-libs/B-2"], ), ) playground = ResolverPlayground( ebuilds=ebuilds, installed=installed, world=world ) try: for test_case in test_cases: playground.run_TestCase(test_case) self.assertEqual(test_case.test_success, True, test_case.fail_msg) finally: playground.cleanup()
The bug has been referenced in the following commit(s): https://gitweb.gentoo.org/proj/portage.git/commit/?id=64b16b76611e14ff0b38b762486f073039f21a05 commit 64b16b76611e14ff0b38b762486f073039f21a05 Author: Zac Medico <zmedico@gentoo.org> AuthorDate: 2023-12-25 02:53:57 +0000 Commit: Zac Medico <zmedico@gentoo.org> CommitDate: 2023-12-26 21:04:25 +0000 depclean: Strengthen IDEPEND in unmerge order Increase priority of IDEPEND so that it is stronger than RDEPEND in unmerge order calculations. This causes IDEPEND to be unmerged afterwards when packages are involved in RDEPEND cycles. Bug: https://bugs.gentoo.org/916135 Signed-off-by: Zac Medico <zmedico@gentoo.org> lib/_emerge/AbstractDepPriority.py | 3 +- lib/_emerge/UnmergeDepPriority.py | 35 +++++++------ lib/_emerge/actions.py | 5 +- lib/_emerge/depgraph.py | 4 +- lib/portage/tests/resolver/test_depclean_order.py | 63 +++++++++++++++++++++++ 5 files changed, 92 insertions(+), 18 deletions(-)
The bug has been closed via the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=0a1f19cdd7a598070b7eb08b3954e677aa4868ad commit 0a1f19cdd7a598070b7eb08b3954e677aa4868ad Author: Sam James <sam@gentoo.org> AuthorDate: 2023-12-27 21:27:55 +0000 Commit: Sam James <sam@gentoo.org> CommitDate: 2023-12-27 21:28:01 +0000 sys-apps/portage: add 3.0.59 Closes: https://bugs.gentoo.org/587088 Closes: https://bugs.gentoo.org/822033 Closes: https://bugs.gentoo.org/915494 Closes: https://bugs.gentoo.org/916135 Closes: https://bugs.gentoo.org/917120 Closes: https://bugs.gentoo.org/919862 Closes: https://bugs.gentoo.org/920095 Closes: https://bugs.gentoo.org/920258 Closes: https://bugs.gentoo.org/920537 Closes: https://bugs.gentoo.org/920654 Signed-off-by: Sam James <sam@gentoo.org> sys-apps/portage/Manifest | 1 + sys-apps/portage/portage-3.0.59.ebuild | 246 +++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+)